diff --git a/ssh.h b/ssh.h index ed3f81c8..c4c1d3d9 100644 --- a/ssh.h +++ b/ssh.h @@ -1321,8 +1321,10 @@ void des3_decrypt_pubkey_ossh(const void *key, const void *iv, void *blk, int len); void des3_encrypt_pubkey_ossh(const void *key, const void *iv, void *blk, int len); -void aes256_encrypt_pubkey(const void *key, void *blk, int len); -void aes256_decrypt_pubkey(const void *key, void *blk, int len); +void aes256_encrypt_pubkey(const void *key, const void *iv, + void *blk, int len); +void aes256_decrypt_pubkey(const void *key, const void *iv, + void *blk, int len); void des_encrypt_xdmauth(const void *key, void *blk, int len); void des_decrypt_xdmauth(const void *key, void *blk, int len); diff --git a/sshauxcrypt.c b/sshauxcrypt.c index 1367d691..7f64b27a 100644 --- a/sshauxcrypt.c +++ b/sshauxcrypt.c @@ -11,30 +11,28 @@ #include "ssh.h" -static ssh_cipher *aes256_pubkey_cipher(const void *key) +static ssh_cipher *aes256_pubkey_cipher(const void *key, const void *iv) { /* * PuTTY's own .PPK format for SSH-2 private key files is * encrypted with 256-bit AES in CBC mode. */ - char iv[16]; - memset(iv, 0, 16); ssh_cipher *cipher = ssh_cipher_new(&ssh_aes256_cbc); ssh_cipher_setkey(cipher, key); ssh_cipher_setiv(cipher, iv); return cipher; } -void aes256_encrypt_pubkey(const void *key, void *blk, int len) +void aes256_encrypt_pubkey(const void *key, const void *iv, void *blk, int len) { - ssh_cipher *c = aes256_pubkey_cipher(key); + ssh_cipher *c = aes256_pubkey_cipher(key, iv); ssh_cipher_encrypt(c, blk, len); ssh_cipher_free(c); } -void aes256_decrypt_pubkey(const void *key, void *blk, int len) +void aes256_decrypt_pubkey(const void *key, const void *iv, void *blk, int len) { - ssh_cipher *c = aes256_pubkey_cipher(key); + ssh_cipher *c = aes256_pubkey_cipher(key, iv); ssh_cipher_decrypt(c, blk, len); ssh_cipher_free(c); } diff --git a/sshpubk.c b/sshpubk.c index 7a009537..75b901e7 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -608,6 +608,8 @@ static int userkey_parse_line_counter(const char *text) return -1; } +static const unsigned char zero_iv[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase, const char **errorstr) { @@ -729,7 +731,8 @@ ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase, goto error; ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key); - aes256_decrypt_pubkey(key, private_blob->u, private_blob->len); + aes256_decrypt_pubkey(key, zero_iv, + private_blob->u, private_blob->len); } /* @@ -1323,7 +1326,8 @@ strbuf *ppk_save_sb(ssh2_userkey *key, const char *passphrase) unsigned char key[40]; ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key); - aes256_encrypt_pubkey(key, priv_blob_encrypted, priv_encrypted_len); + aes256_encrypt_pubkey(key, zero_iv, + priv_blob_encrypted, priv_encrypted_len); smemclr(key, sizeof(key)); } diff --git a/test/cryptsuite.py b/test/cryptsuite.py index 78725a34..e2039c42 100755 --- a/test/cryptsuite.py +++ b/test/cryptsuite.py @@ -1410,11 +1410,20 @@ class crypt(MyTestBase): p = b'three AES blocks, or six DES, of arbitrary input' k = b'thirty-two-byte aes-256 test key' + iv = b'\0' * 16 c = unhex('7b112d00c0fc95bc13fcdacfd43281bf' 'de9389db1bbcfde79d59a303d41fd2eb' '0955c9477ae4ee3a4d6c1fbe474c0ef6') - self.assertEqualBin(aes256_encrypt_pubkey(k, p), c) - self.assertEqualBin(aes256_decrypt_pubkey(k, c), p) + self.assertEqualBin(aes256_encrypt_pubkey(k, iv, p), c) + self.assertEqualBin(aes256_decrypt_pubkey(k, iv, c), p) + + # same k as in the previous case + iv = unhex('0102030405060708090a0b0c0d0e0f10') + c = unhex('9e9c8a91b739677b834397bdd8e70c05' + 'c3e2cf6cce68d376d798a59848621c6d' + '42b9e7101260a438daadd7b742875a36') + self.assertEqualBin(aes256_encrypt_pubkey(k, iv, p), c) + self.assertEqualBin(aes256_decrypt_pubkey(k, iv, c), p) k = b'3des with keys distinct.' iv = b'randomIV' diff --git a/testcrypt.c b/testcrypt.c index 3fc1ad03..f6d9e61d 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -1029,28 +1029,32 @@ strbuf *des3_decrypt_pubkey_ossh_wrapper(ptrlen key, ptrlen iv, ptrlen data) } #define des3_decrypt_pubkey_ossh des3_decrypt_pubkey_ossh_wrapper -strbuf *aes256_encrypt_pubkey_wrapper(ptrlen key, ptrlen data) +strbuf *aes256_encrypt_pubkey_wrapper(ptrlen key, ptrlen iv, ptrlen data) { if (key.len != 32) fatal_error("aes256_encrypt_pubkey: key must be 32 bytes long"); + if (iv.len != 16) + fatal_error("aes256_encrypt_pubkey: iv must be 16 bytes long"); if (data.len % 16 != 0) fatal_error("aes256_encrypt_pubkey: data must be a multiple of 16 bytes"); strbuf *sb = strbuf_new(); put_datapl(sb, data); - aes256_encrypt_pubkey(key.ptr, sb->u, sb->len); + aes256_encrypt_pubkey(key.ptr, iv.ptr, sb->u, sb->len); return sb; } #define aes256_encrypt_pubkey aes256_encrypt_pubkey_wrapper -strbuf *aes256_decrypt_pubkey_wrapper(ptrlen key, ptrlen data) +strbuf *aes256_decrypt_pubkey_wrapper(ptrlen key, ptrlen iv, ptrlen data) { if (key.len != 32) fatal_error("aes256_decrypt_pubkey: key must be 32 bytes long"); + if (iv.len != 16) + fatal_error("aes256_encrypt_pubkey: iv must be 16 bytes long"); if (data.len % 16 != 0) fatal_error("aes256_decrypt_pubkey: data must be a multiple of 16 bytes"); strbuf *sb = strbuf_new(); put_datapl(sb, data); - aes256_decrypt_pubkey(key.ptr, sb->u, sb->len); + aes256_decrypt_pubkey(key.ptr, iv.ptr, sb->u, sb->len); return sb; } #define aes256_decrypt_pubkey aes256_decrypt_pubkey_wrapper diff --git a/testcrypt.h b/testcrypt.h index 70752f8f..a50c920c 100644 --- a/testcrypt.h +++ b/testcrypt.h @@ -299,8 +299,8 @@ FUNC2(val_string, des3_encrypt_pubkey, val_string_ptrlen, val_string_ptrlen) FUNC2(val_string, des3_decrypt_pubkey, val_string_ptrlen, val_string_ptrlen) FUNC3(val_string, des3_encrypt_pubkey_ossh, val_string_ptrlen, val_string_ptrlen, val_string_ptrlen) FUNC3(val_string, des3_decrypt_pubkey_ossh, val_string_ptrlen, val_string_ptrlen, val_string_ptrlen) -FUNC2(val_string, aes256_encrypt_pubkey, val_string_ptrlen, val_string_ptrlen) -FUNC2(val_string, aes256_decrypt_pubkey, val_string_ptrlen, val_string_ptrlen) +FUNC3(val_string, aes256_encrypt_pubkey, val_string_ptrlen, val_string_ptrlen, val_string_ptrlen) +FUNC3(val_string, aes256_decrypt_pubkey, val_string_ptrlen, val_string_ptrlen, val_string_ptrlen) FUNC1(uint, crc32_rfc1662, val_string_ptrlen) FUNC1(uint, crc32_ssh1, val_string_ptrlen) FUNC2(uint, crc32_update, uint, val_string_ptrlen)