As it turns out, there was a pretty significant bug in cowpatty 4.5 and earlier when built on systems with a more modern version of OpenSSL than what I was testing against:
typedef struct {
unsigned char k_ipad[65];
unsigned char k_opad[65];
unsigned char k_ipad_set;
unsigned char k_opad_set;
} SHA1_CACHE;
struct SHA1_CACHE cached;
SHA1_CTX context;
/* ... */
if (usecached) {
/* Cache the context value */
memcpy(&cached.k_ipad, &context, sizeof(context));
cached.k_ipad_set = 1;
}
When I looked at this I realized what the problem was right away: I was stupid when I wrote this code.
One of the ways we can accelerate WPA2-PSK cracking is to cache values that are computed each time during SHA1 rounds; namely the inner and outer pad hashes (ipad, opad). I implemented this in cowpatty and created a data structure SHA1_CACHE to store the hashed value with a field to indicate if it was currently cached or not.
At the time, OpenSSL’s SHA1_CACHE structure was 64 bytes; I created my structure members at 65 bytes (why not 64 bytes? Because I was stupid when I wrote this code). Perfect!
All worked well until I recently discovered that the SHA1_CTX structure is now 96 bytes, which did not fit so well in my 65 byte data structure.
The lesson here: don’t try to recreate the wheel. This is how I fixed the problem, and how I should have done it back in 2005:
typedef struct {
SHA1_CTX k_ipad;
SHA1_CTX k_opad;
unsigned char k_ipad_set;
unsigned char k_opad_set;
} SHA1_CACHE;
Instead of relying on a static byte length that once characterized the size of SHA1_CTX, I should have just used the real thing. I’ll remember this lesson in the future, and hopefully you won’t make the same mistake I did.
You can snag the latest version of cowpatty here. Special thanks to Kevin Kestinggolrer, Philipp Schroedel, Max Moser and Nathan Grennan, Jason Franks and Michal Knobel for hitting me with their various clue-sticks.
-Josh