I have been doing some reading on the mechanics of managing RSA key pairs, during which I learned that OpenSSL by default derives the encryption key by using MD5 on the passphrase (bad!) without any key stretching (worse!):

But how do you get from the passphrase to the AES encryption key? I couldn’t find it documented anywhere, so I had to dig through the OpenSSL source to find it:

  1. Append the first 8 bytes of the IV to the passphrase, without a separator (serves as a salt).
  2. Take the MD5 hash of the resulting string (once).

That's it.

The author of the quoted blog post goes on to explain how OpenSSL supports the PKCS#8 format (about which I know precisely nothing), offering protection against brute-forcing encrypted private keys that have fallen into the wrong hands through key stretching (PBKDF2).

However, my own valuable private keys are stored in Putty's own .PPK format which raises the question: how well are they protected against this sort of offline brute-force attack?


Gotta love open source! The following code is from the stable Putty-0.63 release.


 * Decrypt the private blob.
if (cipher) {
unsigned char key[40];
SHA_State s;

if (!passphrase)
    goto error;
if (private_blob_len % cipherblk)
    goto error;

SHA_Bytes(&s, "\0\0\0\0", 4);
SHA_Bytes(&s, passphrase, passlen);
SHA_Final(&s, key + 0);
SHA_Bytes(&s, "\0\0\0\1", 4);
SHA_Bytes(&s, passphrase, passlen);
SHA_Final(&s, key + 20);
aes256_decrypt_pubkey(key, private_blob, private_blob_len);

Your password is hashed twice using SHA1 with "\0\0\0\0" and "\0\0\0\1" as separate salts. The resulting hashes are concatenated to form the AES 256-bit key. I am not completely up on all the current password attacks, and while I don't believe this is the best password hashing scheme it's not the worst. Yes, SHA1 was recently deemed not secure, but I don't believe that this scheme would be trivial to break.

Something to remember about password guessing is that the attacker has to know when there is a success. In this case the private key bytes themselves are encrypted with a key generated from a password. So for each password attempt the attacker needs to do an AES 256-bit decrypt in addition to the hashing. There is an integrity check for the entire keyfile. For the PuTTY key-file we have the following HMAC:

    SHA_State s;
    unsigned char mackey[20];
    char header[] = "putty-private-key-file-mac-key";

    SHA_Bytes(&s, header, sizeof(header)-1);
    if (cipher && passphrase)
    SHA_Bytes(&s, passphrase, passlen);
    SHA_Final(&s, mackey);

    hmac_sha1_simple(mackey, 20, macdata, maclen, binary);

    smemclr(mackey, sizeof(mackey));
    smemclr(&s, sizeof(s));

Now after already performing 2 hashes and 1 AES decrypt the attacker now has to perform another SHA1 hash and a keyed SHA1 HMAC. Just to verify if one guess was correct. If it wasn't a PuTTY keyfile then the following else occurs:

else {
        SHA_Simple(macdata, maclen, binary);

Obviously not as secure as using a PuTTY keyfile, but that would still total 3 hashings, 1 AES decrypt... and a partridge in a pear tree.

| improve this answer | |
  • 1
    Thanks. A few comments: 2xSHA1 is not really better than 1xMD5, both hashes were designed with speed of computation as a goal which is the opposite of what we want for the key derivation function -- we are not trying to create collisions here. Also, you can easily tell when a decrypt for an RSA key was successful based on the mathematical properties of the result. So all in all, it seems the answer is "there's not much difference really". – Jon Oct 23 '14 at 15:35
  • @Jon It's easy in theory, but performing modular arithmetic is computationally intensive. And while only having to do a few iterations of hashes, they're hashes of different data. Piecing them all together for an efficient password attack I would not be so easy. – RoraΖ Oct 23 '14 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.