Multibit Classic is a Bitcoin wallet that was popular during the 2010s, but that was abandoned in 2017. Nowadays, some people are trying to move their Bitcoins out of their wallet, but they can’t because their password is being rejected. Yet, they swear that it is correct and that their password must have been corrupted somehow.
I decided to investigate these claims and found out that Multibit Classic does, in some cases, corrupt the password meant to protect the wallet. In this article, I will explain my discovery further. Note that this text is technical by nature and is intended for readers with programming knowledge, especially in regard to character encoding. Bytes are written in hexadecimal format.
Who is affected by this issue?
This issue may affect users who are using password crackers – like hashcat, John the
Ripper or BTCRecover – to decrypt the .key
file associated to their wallet. It is
more likely to affect them if their password contains characters undefined in
the ASCII charset.
This issue should not affect users who are using password crackers on their .wallet
file.
Some of these tools have their own problems when it comes to character encoding, but they
are unrelated to the issue described in this article.
This issue should not affect users who are attempting to unlock their wallet directly through Multibit Classic.
How was this issue reproduced?
This issue was reproduced within the following environment:
- Multibit Classic version 0.5.14.
- Java Runtime Environment version 8 update 231.
- Windows 10 Home build 19044.2846.
The problem method: PKCS5PasswordToBytes
When you choose your password through Multibit’s user interface, the software passes
it as an argument to the PKCS5PasswordToBytes
method, which is part of the Spongy Castle
library. This method accepts the password as a char array and outputs it as a byte array.
It is later used to either encrypt or decrypt a .key
file. Below, here’s how the method
is implemented in the PBEParametersGenerator.java
file. Can you spot the bug?
1public static byte[] PKCS5PasswordToBytes(
2 char[] password)
3{
4 byte[] bytes = new byte[password.length];
5
6 for (int i = 0; i != bytes.length; i++)
7 {
8 bytes[i] = (byte)password[i];
9 }
10
11 return bytes;
12}
In Java, the char
type is made up of 2 bytes; however, the code above assumes that
a char
is made up of only one byte! Thus, for each char processed in the loop, the
low-order byte is kept while the high-order byte is discarded. Under the right
circumstances, this can become an issue.
When everything goes well
As an example, let’s say that our password is made up of a single letter:
t
Below, here’s a table listing the encoding of this password for some of the most popular charsets.
Charset | Encoding |
---|---|
ASCII | 74 |
ISO-8859-1 | 74 |
CP-1251 | 74 |
CP-1252 | 74 |
UTF-8 | 74 |
UTF-16 BE | 00 74 |
UTF-16 LE | 74 00 |
UTF-32 BE | 00 00 00 74 |
UTF-32 LE | 74 00 00 00 |
Since Java relies on the UTF-16 BE charset, Multibit encodes the password as 00 74
when it is
entered in the user interface. When it is converted through the PKCS5PasswordToBytes
method, the
high-order byte (00
) is dropped whereas the low-order byte (74
) is kept.
While Multibit’s conversion routine is incorrect, the end result is not in this case. Indeed, 74
is the proper encoding for our password in ASCII, ISO-8859-1, CP-1251, CP-1252 and UTF-8. Thus,
a password cracker should be able to decrypt the .key
file as long as one of the aforementioned
charsets is used.
When things don’t go so well
Now, let’s say that our password is made up of a single character, the euro symbol:
€
Below, here’s a table listing the encoding of this password for some of the most popular charsets.
Charset | Encoding |
---|---|
ASCII | N/A |
ISO-8859-1 | N/A |
CP-1251 | 88 |
CP-1252 | 80 |
UTF-8 | E2 82 AC |
UTF-16 BE | 20 AC |
UTF-16 LE | AC 20 |
UTF-32 BE | 00 00 20 AC |
UTF-32 LE | AC 20 00 00 |
Since Java relies on the UTF-16 BE charset, Multibit encodes the password as 20 AC
when it is
entered in the user interface. When it is converted through the PKCS5PasswordToBytes
method,
the high-order byte (20
) is dropped whereas the low-order byte (AC
) is kept.
Unlike with our previous example, AC
is not the proper encoding for our password in any of the
charsets above. As such, a password cracker may fail to decrypt the .key
file even with the
correct password.
What are your options?
If you haven’t done so already, you should try to unlock your wallet through Multibit Classic directly. You can download a working copy of the software by clicking here. Unfortunately, this approach quickly becomes impractical if you are unsure of your password and must type in every guess. In such a case, you will need a password cracker.
You can avoid the bug described in this article by using the password cracker on a .wallet
file instead of a .key
file. While this approach beats typing in every guess, it scales
terribly as the .wallet
file has much better protection against password crackers than the
.key
file. Moreover, some of these tools have their own set of character encoding issues
you should be aware of.
If you use the password cracker on a .key
file, they are multiple workarounds for character
encoding issues, but they should be evaluated on a case-by-case basis and it is outside the
scope of this article. I encourage you to keep doing your research or to contact me.
Conclusion: don’t lose hope!
Back in the 2010s, many people bought Bitcoins when its price was very low – at least, compared to today – and they trusted Multibit Classic to store their assets. Unfortunately, some of them are now unable to access their wealth because their password is being rejected. The bug described in this article may only explain a handful of cases, but I hope that the information presented here will be useful to you.