Any idea if this would be much faster on a GPU?(MD5 x3 + AES decrypt)
#1
Trying to recover a password I used 4 years ago. The data is encrypted with a passphrase and a JS library gibberish-aes. The decryption steps are as follows:

Decode base64 string to bytes
Extract salt and encrypted string from decoded data
pass+salt -> MD5
(prior hash + pass+salt)  -> MD5
repeat previous step
they 3 hashes as bytes concatenated contain the AES key and IV
AES decrypt(CBC 256-bit) the encrypted string with the key and iv

On my system JS source does the decryption in about 0.2 seconds, my Rust port does it in 1.7 microseconds, difference of about 5/s vs 582k/s. I can probably parallelize the Rust code to use additional cores of my CPU to scale that?

I'm curious if this could be faster on the GPU. Decrypting with random passphrases generated by hashcat would result in what the CPU versions reject as invalid padding, hashcat also wouldn't know when it's decrypted the data correctly. I know that if the decrypted text starts with 5 it's potentially a valid passphrase, no idea how many false positives I'd get.

If the algorithm would see significant speed up gains on the GPU I'd be happy to try port it, but perhaps the logic described doesn't suit GPU computer or hashcat that well?
#2
(05-28-2017, 03:30 PM)polarathene Wrote: Trying to recover a password I used 4 years ago. The data is encrypted with a passphrase and a JS library gibberish-aes. The decryption steps are as follows:

Decode base64 string to bytes
Extract salt and encrypted string from decoded data
pass+salt -> MD5
(prior hash + pass+salt)  -> MD5
repeat previous step
they 3 hashes as bytes concatenated contain the AES key and IV
AES decrypt(CBC 256-bit) the encrypted string with the key and iv

On my system JS source does the decryption in about 0.2 seconds, my Rust port does it in 1.7 microseconds, difference of about 5/s vs 582k/s. I can probably parallelize the Rust code to use additional cores of my CPU to scale that?

I'm curious if this could be faster on the GPU. Decrypting with random passphrases generated by hashcat would result in what the CPU versions reject as invalid padding, hashcat also wouldn't know when it's decrypted the data correctly. I know that if the decrypted text starts with 5 it's potentially a valid passphrase, no idea how many false positives I'd get.

If the algorithm would see significant speed up gains on the GPU I'd be happy to try port it, but perhaps the logic described doesn't suit GPU computer or hashcat that well?

GPU would definitely provide the horse power you are looking for. It is already highly optimised for MD5 and AES implementation is already ported. 

For the padding portion, it could be implemented easily without significant overhead (assuming standard PKCS 5/7). This would add an addtional validation to reduce false positives with your plaintext attack. 

Above speed you will benefit from all the cool features for password generation to perform more accurate guesses.
#3
yeah, OpenCL support might make sense.

But there are some questions still open:
- what about the lenght of the data, is 1 block enough ?
- you need way better means to determine if the decryption was successfull, not just a test for a single byte (0x35 == "5"), this will produce way too many false postitives, there must be some other important/hard-coded etc data within the decrypted data, or?
- is it really worth the effort? as far as I understood, you only have 1 single "hash" that you need to crack... maybe it is better to try to remember the password and maybe generate some very specific dictionaries (small ones, for instance with the help of hashcat-utils etc) that you use as input to your rust code?
- it's also very important that you carefully test that you got the algorithm correct (yeah, also your rust code etc) with some additional test vectors that you should generate with the tool that was used to generate the encrypted data (the JS library)
#4
(05-28-2017, 04:49 PM)philsmd Wrote: yeah, OpenCL support might make sense.

But there are some questions still open:
- what about the lenght of the data, is 1 block enough ?
- you need way better means to determine if the decryption was successfull, not just a test for a single byte (0x35 == "5"), this will produce way too many false postitives, there must be some other important/hard-coded etc data within the decrypted data, or?
- is it really worth the effort? as far as I understood, you only have 1 single "hash" that you need to crack... maybe it is better to try to remember the password and maybe generate some very specific dictionaries (small ones, for instance with the help of hashcat-utils etc) that you use as input to your rust code?
- it's also very important that you carefully test that you got the algorithm correct (yeah, also your rust code etc) with some additional test vectors that you should generate with the tool that was used to generate the encrypted data (the JS library)

Verified several tests
I've created several encryptions with the JS library and verified correct decryption on my Rust port. The library claims to be OpenSSL compatible(the MD5 hashing part is in their OpenSSLKey function), but this doesn't seem to be the case anymore, It is about 2 years old since last commit, perhaps recent openSSL versions broke that.

Worth the effort?
The effort is worth about $1k USD atm, it contains a small amount of BTC I stored in web service 4 years ago. That value is likely to increase over time, but so is computation power where I could attempt it then provided the service hasn't disappeared. I've attempted many passwords that I'd assume it should have been, I also located one on my old HDD mapped to the service in keepass db, but that may have been for the account itself which I have since reset. I could most definitely put together a wordlist of likely candidates and have a hashcat tool mutate variations for my Rust code to try.

Determining correctness of decrypted content
The service which uses the JS library has a decrypt button to enter your passphrase, it'll return "invalid password"  (due to a padding error during decryption iirc) or the decrypted data.

It mentions that valid decrypted data starts with a 5. I tried to look the source of that up on their site but it's concerningly down(cloudflare), the service has had many issues over the years and storing bitcoin there wasn't the best idea Smile

According to this reddit thread , private keys starting with 5 are uncompressed. Another comment also provides more details here:

Quote:The network byte is the first byte of input to base58 encoder.
For uncompressed keys the input is always 1 network byte (0x80) followed by 32-byte secret exponent, followed by a 4-byte checksum. For compressed keys there is an extra byte of 0x01 between the exponent and the checksum.
The prefixes '5', 'K' or 'L' are the result of the aforementioned constraints on the input data. If you plug in all 0x00 or all 0xff in the 32-byte exponent and convert it to base58, you will see that the private key must start with '5H...5K' for uncompressed and 'Kw...L5' for compressed.

Seems to be known as WIF(Wallet Import Format)? So the **starting two bytes is between 5H and 5K** of a base58 string.

Length of data, Is 1 block enouogh?
I'm not sure what you're referring to here. The base64 string decodes to 80 bytes. The first 8 don't matter, the next 8 is the salt, the rest is the encrypted data leaving 56 bytes.

---

So should I attempt this with hashcat? I guess I start with the source for hashing MD5 and add AES decryption from another?