Support importing of new-style OpenSSH private keys (encrypted by
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 12 Apr 2010 10:55:31 +0000 (10:55 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 12 Apr 2010 10:55:31 +0000 (10:55 +0000)
AES rather than 3DES).

git-svn-id: svn://svn.tartarus.org/sgt/putty@8916 cda61777-01e9-0310-a592-d414129be87e

import.c
ssh.h
sshaes.c

index a3c2405..17bf65b 100644 (file)
--- a/import.c
+++ b/import.c
@@ -308,9 +308,10 @@ static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret)
  */
 
 enum { OSSH_DSA, OSSH_RSA };
+enum { OSSH_ENC_3DES, OSSH_ENC_AES };
 struct openssh_key {
     int type;
-    int encrypted;
+    int encrypted, encryption;
     char iv[32];
     unsigned char *keyblob;
     int keyblob_len, keyblob_size;
@@ -387,21 +388,29 @@ static struct openssh_key *load_openssh_key(const Filename *filename,
                if (!strcmp(p, "ENCRYPTED"))
                    ret->encrypted = 1;
            } else if (!strcmp(line, "DEK-Info")) {
-               int i, j;
-
-               if (strncmp(p, "DES-EDE3-CBC,", 13)) {
-                   errmsg = "ciphers other than DES-EDE3-CBC not supported";
+               int i, j, ivlen;
+
+               if (!strncmp(p, "DES-EDE3-CBC,", 13)) {
+                   ret->encryption = OSSH_ENC_3DES;
+                   ivlen = 8;
+               } else if (!strncmp(p, "AES-128-CBC,", 12)) {
+                   ret->encryption = OSSH_ENC_AES;
+                   ivlen = 16;
+               } else {
+                   errmsg = "unsupported cipher";
                    goto error;
                }
-               p += 13;
-               for (i = 0; i < 8; i++) {
-                   if (1 != sscanf(p, "%2x", &j))
-                       break;
+               p = strchr(p, ',') + 1;/* always non-NULL, by above checks */
+               for (i = 0; i < ivlen; i++) {
+                   if (1 != sscanf(p, "%2x", &j)) {
+                       errmsg = "expected more iv data in DEK-Info";
+                       goto error;
+                   }
                    ret->iv[i] = j;
                    p += 2;
                }
-               if (i < 8) {
-                   errmsg = "expected 16-digit iv in DEK-Info";
+               if (*p) {
+                   errmsg = "more iv data than expected in DEK-Info";
                    goto error;
                }
            }
@@ -538,8 +547,18 @@ struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase,
        /*
         * Now decrypt the key blob.
         */
-       des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
-                                key->keyblob, key->keyblob_len);
+       if (key->encryption == OSSH_ENC_3DES)
+           des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
+                                    key->keyblob, key->keyblob_len);
+       else {
+           void *ctx;
+           assert(key->encryption == OSSH_ENC_AES);
+           ctx = aes_make_context();
+           aes128_key(ctx, keybuf);
+           aes_iv(ctx, (unsigned char *)key->iv);
+           aes_ssh2_decrypt_blk(ctx, key->keyblob, key->keyblob_len);
+           aes_free_context(ctx);
+       }
 
         memset(&md5c, 0, sizeof(md5c));
         memset(keybuf, 0, sizeof(keybuf));
diff --git a/ssh.h b/ssh.h
index 2e9194f..d17920c 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -290,6 +290,14 @@ extern const struct ssh_mac ssh_hmac_sha1_buggy;
 extern const struct ssh_mac ssh_hmac_sha1_96;
 extern const struct ssh_mac ssh_hmac_sha1_96_buggy;
 
+void *aes_make_context(void);
+void aes_free_context(void *handle);
+void aes128_key(void *handle, unsigned char *key);
+void aes192_key(void *handle, unsigned char *key);
+void aes256_key(void *handle, unsigned char *key);
+void aes_iv(void *handle, unsigned char *iv);
+void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len);
+void aes_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len);
 
 /*
  * PuTTY version number formatted as an SSH version string. 
index 44f8ac5..2800e02 100644 (file)
--- a/sshaes.c
+++ b/sshaes.c
@@ -1097,35 +1097,35 @@ static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx)
     memcpy(ctx->iv, iv, sizeof(iv));
 }
 
-static void *aes_make_context(void)
+void *aes_make_context(void)
 {
     return snew(AESContext);
 }
 
-static void aes_free_context(void *handle)
+void aes_free_context(void *handle)
 {
     sfree(handle);
 }
 
-static void aes128_key(void *handle, unsigned char *key)
+void aes128_key(void *handle, unsigned char *key)
 {
     AESContext *ctx = (AESContext *)handle;
     aes_setup(ctx, 16, key, 16);
 }
 
-static void aes192_key(void *handle, unsigned char *key)
+void aes192_key(void *handle, unsigned char *key)
 {
     AESContext *ctx = (AESContext *)handle;
     aes_setup(ctx, 16, key, 24);
 }
 
-static void aes256_key(void *handle, unsigned char *key)
+void aes256_key(void *handle, unsigned char *key)
 {
     AESContext *ctx = (AESContext *)handle;
     aes_setup(ctx, 16, key, 32);
 }
 
-static void aes_iv(void *handle, unsigned char *iv)
+void aes_iv(void *handle, unsigned char *iv)
 {
     AESContext *ctx = (AESContext *)handle;
     int i;
@@ -1133,13 +1133,13 @@ static void aes_iv(void *handle, unsigned char *iv)
        ctx->iv[i] = GET_32BIT_MSB_FIRST(iv + 4 * i);
 }
 
-static void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len)
+void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len)
 {
     AESContext *ctx = (AESContext *)handle;
     aes_encrypt_cbc(blk, len, ctx);
 }
 
-static void aes_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len)
+void aes_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len)
 {
     AESContext *ctx = (AESContext *)handle;
     aes_decrypt_cbc(blk, len, ctx);