Yesterday, 08:10 PM
I'm writing a custom hashcat plugin (mode 99000) to crack a LastPass vault — PBKDF2-HMAC-SHA256 → AES-256-CBC verification. I've got the module compiling and the PBKDF2 producing the correct derived key (verified against Python), but I'm running into something weird with the AES key schedule and figured you'd spot the issue in about 30 seconds where I've been stuck for the better part of a day.
The symptom: after calling aes256_set_decrypt_key (or aes256_ExpandKey + aes256_InvertKey, same result), the key schedule looks like this (all keys are test vector):
ks[0..3]: 3a86015c 0d2e18ba 2229483c 6fbc5a65 (looks computed)
ks[4..7]: 52525252 52525252 52525252 52525252
ks[8..11]: 52525252 52525252 52525252 52525252
ks[28..31]: 52525252 52525252 52525252 52525252
ks[52..55]: 52525252 52525252 52525252 52525252
ks[56..59]: 4586015c 1da819e6 598151da 723d0bbf (original key)
The first 4 and last 4 entries look right, but the middle 52 entries are all 0x52525252 — which I'm pretty sure is what InvMixColumns gives you when the input is uninitialized zeros (Sinv[0] = 0x52). So ExpandKey doesn't seem to be populating ks[8..55] before InvertKey runs over it.
To rule out an environment issue, I tried decrypting the NIST AES-256 test vector inside the same kernel:
Key: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
CT: 8ea2b7ca516745bfeafc49904b496089
Expected PT: 00112233445566778899aabbccddeeff
Got: the input key bytes back instead of the plaintext
So it's not specific to my PBKDF2 output — AES is broken with any key.
What I'm doing:
- Built on hashcat v7.1.2-382-g2d71af371, MSYS2 MINGW64 on Windows, RTX 4090, CUDA 13.2
- Module is a standard slow-hash (init / loop / comp), based on the m15600 pattern
- Tables loaded into LOCAL_VK with the standard `for (i = lid; i < 256; i += lsz)` pattern, SYNC_THREADS after — confirmed s_td0[0] = 0x51f4a750 and s_te0[0] = 0xc66363a5 in-kernel
- ks declared as `u32 ks[60]` in private memory inside the _comp kernel
- Calling: `aes256_set_decrypt_key(ks, key, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3)`
- Also tried the capital wrapper, also tried aes256_ExpandKey + aes256_InvertKey manually — all three produce the same 0x52525252 middle
I figure I'm either missing a setup step I don't know about, or there's a constraint on where/when these functions can be called that I'm not aware of. I'd really appreciate a pointer
The symptom: after calling aes256_set_decrypt_key (or aes256_ExpandKey + aes256_InvertKey, same result), the key schedule looks like this (all keys are test vector):
ks[0..3]: 3a86015c 0d2e18ba 2229483c 6fbc5a65 (looks computed)
ks[4..7]: 52525252 52525252 52525252 52525252
ks[8..11]: 52525252 52525252 52525252 52525252
ks[28..31]: 52525252 52525252 52525252 52525252
ks[52..55]: 52525252 52525252 52525252 52525252
ks[56..59]: 4586015c 1da819e6 598151da 723d0bbf (original key)
The first 4 and last 4 entries look right, but the middle 52 entries are all 0x52525252 — which I'm pretty sure is what InvMixColumns gives you when the input is uninitialized zeros (Sinv[0] = 0x52). So ExpandKey doesn't seem to be populating ks[8..55] before InvertKey runs over it.
To rule out an environment issue, I tried decrypting the NIST AES-256 test vector inside the same kernel:
Key: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
CT: 8ea2b7ca516745bfeafc49904b496089
Expected PT: 00112233445566778899aabbccddeeff
Got: the input key bytes back instead of the plaintext
So it's not specific to my PBKDF2 output — AES is broken with any key.
What I'm doing:
- Built on hashcat v7.1.2-382-g2d71af371, MSYS2 MINGW64 on Windows, RTX 4090, CUDA 13.2
- Module is a standard slow-hash (init / loop / comp), based on the m15600 pattern
- Tables loaded into LOCAL_VK with the standard `for (i = lid; i < 256; i += lsz)` pattern, SYNC_THREADS after — confirmed s_td0[0] = 0x51f4a750 and s_te0[0] = 0xc66363a5 in-kernel
- ks declared as `u32 ks[60]` in private memory inside the _comp kernel
- Calling: `aes256_set_decrypt_key(ks, key, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3)`
- Also tried the capital wrapper, also tried aes256_ExpandKey + aes256_InvertKey manually — all three produce the same 0x52525252 middle
I figure I'm either missing a setup step I don't know about, or there's a constraint on where/when these functions can be called that I'm not aware of. I'd really appreciate a pointer
