Browse Source

Add support for `aes256-ctr` encrypted SSH keys

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 2 years ago
parent
commit
6c24c5c06d
2 changed files with 42 additions and 15 deletions
  1. 34 15
      src/misc/pem/pem_ssh.c
  2. 8 0
      tests/ssh/ssh-testkey-ed25519-aesctr

+ 34 - 15
src/misc/pem/pem_ssh.c

@@ -29,7 +29,7 @@ const struct ssh_blockcipher ssh_ciphers[] =
 {
    { "none", "", 0, none },
    { "aes256-cbc", "aes", 256 / 8, cbc },
-   { 0 },
+   { "aes256-ctr", "aes", 256 / 8, ctr },
 };
 
 struct kdf_options {
@@ -232,9 +232,14 @@ static int s_decode_private_key(const unsigned char *in, unsigned long *inlen, l
 static int s_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struct kdf_options *opts)
 {
    int err, cipher;
-   unsigned char symkey[128];
    unsigned long symkey_len;
-   symmetric_CBC cbc_ctx;
+   struct {
+      unsigned char symkey[128];
+      union {
+         symmetric_CBC cbc;
+         symmetric_CTR ctr;
+      } ctx;
+   } s;
 
    LTC_ARGCHK(in    != NULL);
    LTC_ARGCHK(inlen != NULL);
@@ -246,27 +251,41 @@ static int s_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struc
    }
    symkey_len = opts->cipher->len + cipher_descriptor[cipher].block_length;
 
-   if (sizeof(symkey) < symkey_len) {
+   if (sizeof(s.symkey) < symkey_len) {
       return CRYPT_OVERFLOW;
    }
 
-   if ((err = bcrypt_pbkdf_openbsd(opts->pw.pw, opts->pw.l, opts->salt, opts->saltlen, opts->num_rounds, find_hash("sha512"), symkey, &symkey_len)) != CRYPT_OK) {
+   if ((err = bcrypt_pbkdf_openbsd(opts->pw.pw, opts->pw.l, opts->salt, opts->saltlen,
+                                   opts->num_rounds, find_hash("sha512"), s.symkey, &symkey_len)) != CRYPT_OK) {
       return err;
    }
 
-   if ((err = cbc_start(cipher, symkey + opts->cipher->len, symkey, opts->cipher->len, 0, &cbc_ctx)) != CRYPT_OK) {
-      goto cleanup;
-   }
-   if ((err = cbc_decrypt(in, in, *inlen, &cbc_ctx)) != CRYPT_OK) {
-      goto cleanup;
-   }
-   if ((err = cbc_done(&cbc_ctx)) != CRYPT_OK) {
-      goto cleanup;
+   if (opts->cipher->mode == cbc) {
+      if ((err = cbc_start(cipher, s.symkey + opts->cipher->len, s.symkey, opts->cipher->len,
+                           0, &s.ctx.cbc)) != CRYPT_OK) {
+         goto cleanup;
+      }
+      if ((err = cbc_decrypt(in, in, *inlen, &s.ctx.cbc)) != CRYPT_OK) {
+         goto cleanup;
+      }
+      if ((err = cbc_done(&s.ctx.cbc)) != CRYPT_OK) {
+         goto cleanup;
+      }
+   } else if (opts->cipher->mode == ctr) {
+      if ((err = ctr_start(cipher, s.symkey + opts->cipher->len, s.symkey, opts->cipher->len,
+                           0, CTR_COUNTER_BIG_ENDIAN, &s.ctx.ctr)) != CRYPT_OK) {
+         goto cleanup;
+      }
+      if ((err = ctr_decrypt(in, in, *inlen, &s.ctx.ctr)) != CRYPT_OK) {
+         goto cleanup;
+      }
+      if ((err = ctr_done(&s.ctx.ctr)) != CRYPT_OK) {
+         goto cleanup;
+      }
    }
 
 cleanup:
-   zeromem(symkey, sizeof(symkey));
-   zeromem(&cbc_ctx, sizeof(cbc_ctx));
+   zeromem(&s, sizeof(s));
 
    return err;
 }

+ 8 - 0
tests/ssh/ssh-testkey-ed25519-aesctr

@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBYWWGgpa
++aAsoGsV6JUqJ3AAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIEVemuQ8wNLBW205
+dbGF8l0DjxP7xLIWvmollyOm+9RoAAAAkK4XJkJqpHsZ0rYuwfnZu02gpmy3GnNmexMcyU
+SEtgIJNuTJbIlIn0oGBNt5xIWN6hweHq34gPvb6q9nbxgb6eS5WBFJI7+4Xng2hOrZ8rTm
+WR1YJLCnw4zk8dKKDehik+K6psMb5l7JqIUvu/F95NzO+LZXErhZ2/e6v2X2mqhSelg9fm
+gSe+OOWNesOUNtCQ==
+-----END OPENSSH PRIVATE KEY-----