Bladeren bron

refactor & clean-up

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 6 jaren geleden
bovenliggende
commit
350fbc6546
1 gewijzigde bestanden met toevoegingen van 131 en 117 verwijderingen
  1. 131 117
      demos/openssh-privkey.c

+ 131 - 117
demos/openssh-privkey.c

@@ -10,6 +10,9 @@
 /**
   @file openssh-privkey.c
   OpenSSH Private Key decryption demo, Steffen Jaeckel
+
+  The basic format of the key is described here:
+  https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
 */
 
 #define _GNU_SOURCE
@@ -77,7 +80,7 @@ static void die_(int err, int line)
 #define DIE(s, ...) do { verbose = 1; print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
 
 
-static void check_padding(unsigned char *p, unsigned long len)
+static void check_padding(const unsigned char *p, unsigned long len)
 {
    unsigned char pad = 0x1u;
    while (len != 0) {
@@ -117,12 +120,9 @@ const struct ssh_blockcipher ssh_ciphers[] =
    { 0 },
 };
 
-struct ssh_kdf {
-   const char *name;
-};
-
 struct kdf_options {
-   struct ssh_blockcipher *cipher;
+   const char *name;
+   const struct ssh_blockcipher *cipher;
    unsigned char salt[64];
    ulong32 saltlen;
    ulong32 num_rounds;
@@ -130,13 +130,6 @@ struct kdf_options {
    unsigned long passlen;
 };
 
-const struct ssh_kdf ssh_kdfs[] =
-{
-   { "bcrypt" },
-   { "none" },
-   { 0 },
-};
-
 int ssh_find_init_ecc(const char *pka, pka_key *key)
 {
    int err;
@@ -152,10 +145,10 @@ int ssh_decode_ecdsa(const unsigned char *in, unsigned long *inlen, pka_key *key
 {
    int err;
    unsigned char groupname[64], group[512], privkey[512];
-   ulong32 groupnamelen = sizeof(groupname), grouplen = sizeof(group), privkeylen = sizeof(privkey);
+   unsigned long groupnamelen = sizeof(groupname), grouplen = sizeof(group), privkeylen = sizeof(privkey);
 
    if ((err = ssh_decode_sequence_multi(in, inlen,
-                                        LTC_SSHDATA_STRING, group, &groupnamelen,
+                                        LTC_SSHDATA_STRING, groupname, &groupnamelen,
                                         LTC_SSHDATA_STRING, group, &grouplen,
                                         LTC_SSHDATA_STRING, privkey, &privkeylen,
                                         LTC_SSHDATA_EOL)) != CRYPT_OK) {
@@ -179,7 +172,7 @@ int ssh_decode_ed25519(const unsigned char *in, unsigned long *inlen, pka_key *k
 {
    int err;
    unsigned char pubkey[2048], privkey[2048];
-   ulong32 pubkeylen = sizeof(pubkey), privkeylen = sizeof(privkey);
+   unsigned long pubkeylen = sizeof(pubkey), privkeylen = sizeof(privkey);
 
    if ((err = ssh_decode_sequence_multi(in, inlen,
                                         LTC_SSHDATA_STRING, pubkey, &pubkeylen,
@@ -250,9 +243,8 @@ int ssh_decode_private_key(const unsigned char *in, unsigned long *inlen, pka_ke
 {
    int err;
    ulong32 check1, check2;
-   unsigned char pka[64], pubkey[2048], privkey[2048], comment[256];
-   ulong32 pkalen = sizeof(pka), pubkeylen = sizeof(pubkey);
-   ulong32 privkeylen = sizeof(privkey), commentlen = sizeof(comment);
+   unsigned char pka[64], comment[256];
+   unsigned long pkalen = sizeof(pka), commentlen = sizeof(comment);
    unsigned long remaining, cur_len;
    const unsigned char *p;
    size_t n;
@@ -279,7 +271,7 @@ int ssh_decode_private_key(const unsigned char *in, unsigned long *inlen, pka_ke
 
    for (n = 0; n < sizeof(ssh_pkas)/sizeof(ssh_pkas[0]); ++n) {
       if (ssh_pkas[n].name != NULL) {
-         if (XSTRCMP(pka, ssh_pkas[n].name) != 0) continue;
+         if (XSTRCMP((char*)pka, ssh_pkas[n].name) != 0) continue;
       } else {
          if ((ssh_pkas[n].init == NULL) ||
                (ssh_pkas[n].init((char*)pka, key) != CRYPT_OK)) continue;
@@ -315,7 +307,8 @@ int ssh_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struct kdf
 {
    int err, cipher;
    unsigned char symkey[128];
-   unsigned long cur_len, symkey_len;
+   unsigned long symkey_len;
+   symmetric_CBC cbc_ctx;
 
    LTC_ARGCHK(in    != NULL);
    LTC_ARGCHK(inlen != NULL);
@@ -330,7 +323,6 @@ int ssh_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struct kdf
       die(err);
    }
 
-   symmetric_CBC cbc_ctx;
    if ((err = cbc_start(cipher, symkey + opts->cipher->len, symkey, opts->cipher->len, 0, &cbc_ctx)) != CRYPT_OK) {
       die(err);
    }
@@ -339,152 +331,174 @@ int ssh_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struct kdf
    }
    print_hex("decrypted", in, *inlen);
 
+   zeromem(symkey, sizeof(symkey));
+   zeromem(&cbc_ctx, sizeof(cbc_ctx));
+
    return err;
 }
 
-/* The basic format of the key is described here:
- * https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
- */
-
-int main(int argc, char **argv)
+int ssh_decode_header(unsigned char *in, unsigned long *inlen, struct kdf_options *opts)
 {
    int err;
-   if ((err = register_all_ciphers()) != CRYPT_OK) {
+   unsigned char ciphername[64], kdfname[64], kdfoptions[128], pubkey1[2048];
+   unsigned long ciphernamelen = sizeof(ciphername), kdfnamelen = sizeof(kdfname);
+   unsigned long kdfoptionslen = sizeof(kdfoptions), pubkey1len = sizeof(pubkey1);
+   ulong32 num_keys;
+   size_t i;
+
+   void *magic = strstr((const char*)in, "openssh-key-v1");
+   size_t slen = strlen("openssh-key-v1");
+   unsigned char *start = &in[slen + 1];
+   unsigned long len = *inlen - slen - 1;
+
+   if (magic == NULL) DIE("magic not found");
+   if (magic != in) DIE("magic not at the beginning");
+
+   if ((err = ssh_decode_sequence_multi(start, &len,
+                                        LTC_SSHDATA_STRING, ciphername, &ciphernamelen,
+                                        LTC_SSHDATA_STRING, kdfname, &kdfnamelen,
+                                        LTC_SSHDATA_STRING, kdfoptions, &kdfoptionslen,
+                                        LTC_SSHDATA_UINT32, &num_keys,
+                                        LTC_SSHDATA_STRING, pubkey1, &pubkey1len,
+                                        LTC_SSHDATA_EOL)) != CRYPT_OK) {
       die(err);
    }
-   if ((err = register_all_hashes()) != CRYPT_OK) {
-      die(err);
+   if (num_keys != 1) DIE("more than 1 pubkey not supported");
+
+   print_hex("public key", pubkey1, pubkey1len);
+
+   *inlen = len + slen + 1;
+
+   for (i = 0; i < sizeof(ssh_ciphers)/sizeof(ssh_ciphers[0]); ++i) {
+      if (XSTRCMP((char*)ciphername, ssh_ciphers[i].name) == 0) {
+         opts->cipher = &ssh_ciphers[i];
+         break;
+      }
    }
-   if ((err = crypt_mp_init("ltm")) != CRYPT_OK) {
-      die(err);
+   if (opts->cipher == NULL) DIE("can't find algo");
+
+   if (XSTRCMP((char*)kdfname, "none") == 0) {
+      /* NOP */
+      opts->name = "none";
+   } else if (XSTRCMP((char*)kdfname, "bcrypt") == 0) {
+      opts->name = "bcrypt";
+      opts->saltlen = sizeof(opts->salt);
+      len = kdfoptionslen;
+      if ((err = ssh_decode_sequence_multi(kdfoptions, &len,
+                                           LTC_SSHDATA_STRING, opts->salt, &opts->saltlen,
+                                           LTC_SSHDATA_UINT32, &opts->num_rounds,
+                                           LTC_SSHDATA_EOL)) != CRYPT_OK) {
+         die(err);
+      }
+      if (len != kdfoptionslen) DIE("unused data %lu", kdfoptionslen-len);
+   } else {
+      DIE("unsupported kdf %s", kdfname);
    }
 
-   char pem[100 * 72];
-   size_t w = 0;
+   return err;
+}
+
+
+void read_openssh_private_key(FILE *f, char *pem, size_t *w)
+{
    const char *openssh_privkey_start = "-----BEGIN OPENSSH PRIVATE KEY-----";
    const char *openssh_privkey_end = "-----END OPENSSH PRIVATE KEY-----";
-   char buf[72];
-   FILE *f = NULL;
-
-   if (argc > 1) f = fopen(argv[1], "r");
-   else f = stdin;
-   if (f == NULL) DIE("fopen sez no");
+   char buf[81];
+   char *end;
+   size_t n = 0;
 
    while (fgets(buf, sizeof(buf), f)) {
       const char *start = strstr(buf, openssh_privkey_start);
       if (start != NULL) {
+         size_t l;
          start += strlen(openssh_privkey_start);
-         size_t l = strlcpy(pem + w, start, sizeof(pem) - w);
-         w += l;
+         l = strlcpy(pem + n, start, *w - n);
+         n += l;
          break;
       }
    }
    while (fgets(buf, sizeof(buf), f)) {
-      size_t l = strlcpy(pem + w, buf, sizeof(pem) - w);
+      size_t l = strlcpy(pem + n, buf, *w - n);
       if (l == 0) {
          DIE("strlcpy sez no");
       }
-      w += l;
+      n += l;
    }
-   char *end = strstr(pem, openssh_privkey_end);
+   end = strstr(pem, openssh_privkey_end);
    if (end == NULL) DIE("could not find PEM end-tag");
    *end = '\0';
-   w = end - pem;
+   *w = end - pem;
+}
+
+int main(int argc, char **argv)
+{
+   int err;
+
+   char pem[100 * 72];
+   size_t plen = sizeof(pem);
+   FILE *f = NULL;
+   unsigned char b64_decoded[sizeof(pem)], privkey[sizeof(pem)];
+   unsigned long b64_decoded_len = sizeof(pem), privkey_len = sizeof(privkey);
+   struct kdf_options opts;
+   unsigned char *p;
+   unsigned long len;
+   pka_key k;
 
-   unsigned char b64_decoded[sizeof(pem)];
-   unsigned long b64_decoded_len = sizeof(pem);
-   if ((err = base64_sane_decode(pem, w, b64_decoded, &b64_decoded_len)) != CRYPT_OK) {
+   if ((err = register_all_ciphers()) != CRYPT_OK) {
+      die(err);
+   }
+   if ((err = register_all_hashes()) != CRYPT_OK) {
+      die(err);
+   }
+   if ((err = crypt_mp_init("ltm")) != CRYPT_OK) {
       die(err);
    }
-   print_hex("decoded", b64_decoded, b64_decoded_len);
 
-   void *magic = strstr((const char*)b64_decoded, "openssh-key-v1");
-   if (magic == NULL) DIE("magic not found");
-   if (magic != b64_decoded) DIE("magic not at the beginning");
-
-   size_t nlen = strlen("openssh-key-v1");
-   unsigned char *start = &b64_decoded[nlen + 1];
-   unsigned long tot_len = b64_decoded_len - nlen - 1;
-
-   unsigned char ciphername[64];
-   ulong32 ciphernamelen = sizeof(ciphername);
-   unsigned char kdfname[64];
-   ulong32 kdfnamelen = sizeof(kdfname);
-   unsigned char kdfoptions[128];
-   ulong32 kdfoptionslen = sizeof(kdfoptions);
-   ulong32 num_keys;
-   unsigned char pubkey1[2048];
-   ulong32 pubkey1len = sizeof(pubkey1);
+   if (argc > 1) f = fopen(argv[1], "r");
+   else f = stdin;
+   if (f == NULL) DIE("fopen sez no");
 
-   unsigned long cur_len = tot_len;
+   read_openssh_private_key(f, pem, &plen);
 
-   if ((err = ssh_decode_sequence_multi(start, &cur_len,
-                                        LTC_SSHDATA_STRING, ciphername, &ciphernamelen,
-                                        LTC_SSHDATA_STRING, kdfname, &kdfnamelen,
-                                        LTC_SSHDATA_STRING, kdfoptions, &kdfoptionslen,
-                                        LTC_SSHDATA_UINT32, &num_keys,
-                                        LTC_SSHDATA_STRING, pubkey1, &pubkey1len,
-                                        LTC_SSHDATA_EOL)) != CRYPT_OK) {
+   if ((err = base64_sane_decode(pem, plen, b64_decoded, &b64_decoded_len)) != CRYPT_OK) {
       die(err);
    }
-   if (num_keys != 1) DIE("more than 1 pubkey not supported");
 
-   print_hex("public key", pubkey1, pubkey1len);
+   p = b64_decoded;
+   plen = b64_decoded_len;
+   len = plen;
 
-   start += cur_len;
-   tot_len -= cur_len;
-   cur_len = tot_len;
+   print_hex("decoded", p, plen);
 
-   const struct ssh_blockcipher *c = NULL;
-   for (size_t i = 0; i < sizeof(ssh_ciphers)/sizeof(ssh_ciphers[0]); ++i) {
-      nlen = strlen(ssh_ciphers[i].name);
-      if ((nlen == ciphernamelen) && (XMEMCMP(ciphername, ssh_ciphers[i].name, nlen) == 0)) {
-         c = &ssh_ciphers[i];
-         break;
-      }
+   if ((err = ssh_decode_header(p, &len, &opts)) != CRYPT_OK) {
+      die(err);
    }
-   if (c == NULL) DIE("can't find algo");
+   p += len;
+   plen -= len;
+   len = plen;
 
-   struct kdf_options opts;
-   opts.saltlen = sizeof(opts.salt);
-   opts.cipher = c;
-   opts.pass = "abc123";
-   opts.passlen = 6;
-
-   unsigned char privkey[sizeof(pem)];
-   ulong32 privkey_len = sizeof(privkey);
+   print_hex("remaining", p, plen);
 
-   cur_len = tot_len;
-   if ((err = ssh_decode_sequence_multi(start, &cur_len,
+   if ((err = ssh_decode_sequence_multi(p, &len,
                                         LTC_SSHDATA_STRING, privkey, &privkey_len,
                                         LTC_SSHDATA_EOL)) != CRYPT_OK) {
       die(err);
    }
+   p += len;
+   plen -= len;
 
-   if (XSTRCMP(kdfname, "none") == 0) {
-      /* NOP */
-   } else if (XSTRCMP(kdfname, "bcrypt") == 0) {
-      cur_len = kdfoptionslen;
-      if ((err = ssh_decode_sequence_multi(kdfoptions, &cur_len,
-                                           LTC_SSHDATA_STRING, opts.salt, &opts.saltlen,
-                                           LTC_SSHDATA_UINT32, &opts.num_rounds,
-                                           LTC_SSHDATA_EOL)) != CRYPT_OK) {
-         die(err);
-      }
-      if (cur_len != kdfoptionslen) DIE("unused data %lu", kdfoptionslen-cur_len);
+   opts.pass = "abc123";
+   opts.passlen = 6;
 
-      cur_len = privkey_len;
-      if ((err = ssh_decrypt_private_keys(privkey, &cur_len, &opts)) != CRYPT_OK) {
+   if (XSTRCMP(opts.name, "none") != 0) {
+      len = privkey_len;
+      if ((err = ssh_decrypt_private_keys(privkey, &len, &opts)) != CRYPT_OK) {
          die(err);
       }
-   } else {
-      DIE("unsupported kdf %s", kdfname);
    }
 
-   pka_key k;
-
-   cur_len = privkey_len;
-   if ((err = ssh_decode_private_key(privkey, &cur_len, &k)) != CRYPT_OK) {
+   len = privkey_len;
+   if ((err = ssh_decode_private_key(privkey, &len, &k)) != CRYPT_OK) {
       die(err);
    }