浏览代码

refactor PBES into separate modules

Steffen Jaeckel 7 年之前
父节点
当前提交
a2ec37b93c
共有 4 个文件被更改,包括 395 次插入0 次删除
  1. 35 0
      src/headers/tomcrypt_private.h
  2. 66 0
      src/misc/pbes/pbes.c
  3. 110 0
      src/misc/pbes/pbes1.c
  4. 184 0
      src/misc/pbes/pbes2.c

+ 35 - 0
src/headers/tomcrypt_private.h

@@ -36,6 +36,36 @@ typedef struct {
 } ltc_dh_set_type;
 
 
+typedef int (*fn_kdf_t)(const unsigned char *password, unsigned long password_len,
+                              const unsigned char *salt,     unsigned long salt_len,
+                              int iteration_count,  int hash_idx,
+                              unsigned char *out,   unsigned long *outlen);
+
+typedef struct {
+   /* KDF */
+   fn_kdf_t kdf;
+   /* Hash or HMAC */
+   const char* h;
+   /* cipher */
+   const char* c;
+   unsigned long keylen;
+   /* not used for pbkdf2 */
+   unsigned long blocklen;
+} pbes_properties;
+
+typedef struct
+{
+   pbes_properties type;
+   const void *pwd;
+   unsigned long pwdlen;
+   ltc_asn1_list *enc_data;
+   ltc_asn1_list *salt;
+   ltc_asn1_list *iv;
+   unsigned long iterations;
+   /* only used for RC2 */
+   unsigned long key_bits;
+} pbes_arg;
+
 /*
  * Internal functions
  */
@@ -167,6 +197,11 @@ void ocb3_int_xor_blocks(unsigned char *out, const unsigned char *block_a, const
 
 void copy_or_zeromem(const unsigned char* src, unsigned char* dest, unsigned long len, int coz);
 
+int pbes_decrypt(const pbes_arg  *arg, unsigned char *dec_data, unsigned long *dec_size);
+
+int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res);
+int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
+
 
 /* tomcrypt_pk.h */
 

+ 66 - 0
src/misc/pbes/pbes.c

@@ -10,6 +10,72 @@
 
 #ifdef LTC_PBES
 
+/**
+   Decrypt Data encrypted via either PBES1 or PBES2
+
+   @param arg        The according PBES parameters
+   @param dec_data   [out] The decrypted data
+   @param dec_size   [in/out] The length of the encrypted resp. decrypted data
+   @return CRYPT_OK on success
+*/
+int pbes_decrypt(const pbes_arg  *arg, unsigned char *dec_data, unsigned long *dec_size)
+{
+   int err, hid = -1, cid = -1;
+   unsigned char k[32], *iv;
+   unsigned long klen, keylen, dlen;
+   long diff;
+   symmetric_CBC cbc;
+
+   LTC_ARGCHK(arg           != NULL);
+   LTC_ARGCHK(arg->type.kdf != NULL);
+   LTC_ARGCHK(dec_data      != NULL);
+   LTC_ARGCHK(dec_size      != NULL);
+
+   hid = find_hash(arg->type.h);
+   if (hid == -1) return CRYPT_INVALID_HASH;
+   cid = find_cipher(arg->type.c);
+   if (cid == -1) return CRYPT_INVALID_CIPHER;
+
+   klen = arg->type.keylen;
+
+   /* RC2 special case */
+   if (arg->key_bits != 0) {
+      /* We can't handle odd lengths of Key Bits */
+      if ((arg->key_bits % 8) != 0) return CRYPT_INVALID_KEYSIZE;
+      /* Internally we use bytes, not bits */
+      klen = arg->key_bits / 8;
+   }
+   keylen = klen;
+
+   if (arg->iv != NULL) {
+      iv = arg->iv->data;
+   } else {
+      iv = k + klen;
+      klen += arg->type.blocklen;
+   }
+
+   if (klen > sizeof(k)) return CRYPT_INVALID_ARG;
+
+   if ((err = arg->type.kdf(arg->pwd, arg->pwdlen, arg->salt->data, arg->salt->size, arg->iterations, hid, k, &klen)) != CRYPT_OK) goto LBL_ERROR;
+   if ((err = cbc_start(cid, iv, k, keylen, 0, &cbc)) != CRYPT_OK) goto LBL_ERROR;
+   if ((err = cbc_decrypt(arg->enc_data->data, dec_data, arg->enc_data->size, &cbc)) != CRYPT_OK) goto LBL_ERROR;
+   if ((err = cbc_done(&cbc)) != CRYPT_OK) goto LBL_ERROR;
+   dlen = arg->enc_data->size;
+   if ((err = padding_depad(dec_data, &dlen, LTC_PAD_PKCS7)) != CRYPT_OK) goto LBL_ERROR;
+   diff = (long)arg->enc_data->size - (long)dlen;
+   if ((diff <= 0) || (diff > cipher_descriptor[cid].block_length)) {
+      err = CRYPT_PK_INVALID_PADDING;
+      goto LBL_ERROR;
+   }
+   *dec_size = dlen;
+   return CRYPT_OK;
+
+LBL_ERROR:
+   zeromem(k, sizeof(k));
+   zeromem(dec_data, *dec_size);
+   return err;
+}
+
 #endif
 
 /* ref:         $Format:%D$ */

+ 110 - 0
src/misc/pbes/pbes1.c

@@ -10,6 +10,116 @@
 
 #ifdef LTC_PBES
 
+static int _pkcs_5_alg1_wrap(const unsigned char *password, unsigned long password_len,
+                              const unsigned char *salt,     unsigned long salt_len,
+                              int iteration_count,  int hash_idx,
+                              unsigned char *out,   unsigned long *outlen)
+{
+   LTC_UNUSED_PARAM(salt_len);
+   return pkcs_5_alg1(password, password_len, salt, iteration_count, hash_idx, out, outlen);
+}
+
+static int _pkcs_12_wrap(const unsigned char *password, unsigned long password_len,
+                              const unsigned char *salt,     unsigned long salt_len,
+                              int iteration_count,  int hash_idx,
+                              unsigned char *out,   unsigned long *outlen)
+{
+   int err;
+   /* convert password to unicode/utf16-be */
+   unsigned long pwlen = password_len * 2;
+   unsigned char* pw;
+   if (*outlen < 32) return CRYPT_INVALID_ARG;
+   pw = XMALLOC(pwlen + 2);
+   if (pw == NULL) return CRYPT_MEM;
+   if ((err = pkcs12_utf8_to_utf16(password, password_len, pw, &pwlen) != CRYPT_OK)) goto LBL_ERROR;
+   pw[pwlen++] = 0;
+   pw[pwlen++] = 0;
+   /* derive KEY */
+   if ((err = pkcs12_kdf(hash_idx, pw, pwlen, salt, salt_len, iteration_count, 1, out, 24)) != CRYPT_OK) goto LBL_ERROR;
+   /* derive IV */
+   if ((err = pkcs12_kdf(hash_idx, pw, pwlen, salt, salt_len, iteration_count, 2, out+24, 8)) != CRYPT_OK) goto LBL_ERROR;
+
+   *outlen = 32;
+LBL_ERROR:
+   zeromem(pw, pwlen);
+   XFREE(pw);
+   return err;
+}
+
+static const pbes_properties _pbes1_types[] = {
+   { _pkcs_5_alg1_wrap, "md2",   "des",   8, 8 },
+   { _pkcs_5_alg1_wrap, "md2",   "rc2",   8, 8 },
+   { _pkcs_5_alg1_wrap, "md5",   "des",   8, 8 },
+   { _pkcs_5_alg1_wrap, "md5",   "rc2",   8, 8 },
+   { _pkcs_5_alg1_wrap, "sha1",  "des",   8, 8 },
+   { _pkcs_5_alg1_wrap, "sha1",  "rc2",   8, 8 },
+   { _pkcs_12_wrap,     "sha1",  "3des", 24, 8 },
+};
+
+typedef struct {
+   const pbes_properties *data;
+   const char *oid;
+} oid_to_pbes;
+
+static const oid_to_pbes _pbes1_list[] = {
+   { &_pbes1_types[0], "1.2.840.113549.1.5.1"    },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.1    pbeWithMD2AndDES-CBC */
+   { &_pbes1_types[1], "1.2.840.113549.1.5.4"    },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.4    pbeWithMD2AndRC2-CBC */
+   { &_pbes1_types[2], "1.2.840.113549.1.5.3"    },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.3    pbeWithMD5AndDES-CBC */
+   { &_pbes1_types[3], "1.2.840.113549.1.5.6"    },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.6    pbeWithMD5AndRC2-CBC */
+   { &_pbes1_types[4], "1.2.840.113549.1.5.10"   },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.10   pbeWithSHA1AndDES-CBC */
+   { &_pbes1_types[5], "1.2.840.113549.1.5.11"   },  /* http://www.oid-info.com/get/1.2.840.113549.1.5.11   pbeWithSHA1AndRC2-CBC */
+   { &_pbes1_types[6], "1.2.840.113549.1.12.1.3" },  /* http://www.oid-info.com/get/1.2.840.113549.1.12.1.3 pbeWithSHAAnd3-KeyTripleDES-CBC */
+   { 0 },
+};
+
+static int _pbes1_from_oid(const ltc_asn1_list *oid, pbes_properties *res)
+{
+   unsigned int i;
+   for (i = 0; _pbes1_list[i].data != NULL; ++i) {
+      if (pk_oid_cmp_with_asn1(_pbes1_list[i].oid, oid) == CRYPT_OK) {
+         if (res != NULL) *res = *_pbes1_list[i].data;
+         return CRYPT_OK;
+      }
+   }
+   return CRYPT_INVALID_ARG;
+}
+
+/**
+   Extract PBES1 parameters
+
+   @param s     The start of the sequence with potential PBES1 parameters
+   @param res   Pointer to where the extracted parameters should be stored
+   @return CRYPT_OK on success
+*/
+int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res)
+{
+   int err;
+
+   LTC_ARGCHK(s   != NULL);
+   LTC_ARGCHK(res != NULL);
+
+   if ((err = _pbes1_from_oid(s, &res->type)) != CRYPT_OK) return err;
+
+   if (!LTC_ASN1_IS_TYPE(s->next, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(s->next->child, LTC_ASN1_OCTET_STRING) ||
+       !LTC_ASN1_IS_TYPE(s->next->child->next, LTC_ASN1_INTEGER)) {
+      return CRYPT_INVALID_PACKET;
+   }
+   /* PBES1: encrypted pkcs8 - pbeWithMD5AndDES-CBC:
+    *  0:d=0  hl=4 l= 329 cons: SEQUENCE
+    *  4:d=1  hl=2 l=  27 cons:   SEQUENCE
+    *  6:d=2  hl=2 l=   9 prim:     OBJECT             :pbeWithMD5AndDES-CBC (== 1.2.840.113549.1.5.3) (== *s)
+    * 17:d=2  hl=2 l=  14 cons:     SEQUENCE           (== *lalgparam)
+    * 19:d=3  hl=2 l=   8 prim:       OCTET STRING     [HEX DUMP]:8EDF749A06CCDE51 (== salt)
+    * 29:d=3  hl=2 l=   2 prim:       INTEGER          :0800  (== iterations)
+    * 33:d=1  hl=4 l= 296 prim:   OCTET STRING         :bytes (== encrypted data)
+    */
+   res->salt = s->next->child;
+   res->iterations = mp_get_int(s->next->child->next->data);
+
+   return CRYPT_OK;
+}
+
 #endif
 
 /* ref:         $Format:%D$ */

+ 184 - 0
src/misc/pbes/pbes2.c

@@ -10,6 +10,190 @@
 
 #ifdef LTC_PBES
 
+static const char *_oid_pbes2 =  "1.2.840.113549.1.5.13";
+static const char *_oid_pbkdf2 = "1.2.840.113549.1.5.12";
+
+typedef struct {
+   const char *oid;
+   const char *id;
+} oid_id_st;
+
+static const oid_id_st _hmac_oid_names[] = {
+   { "1.2.840.113549.2.7",  "sha1" },
+   { "1.2.840.113549.2.8",  "sha224" },
+   { "1.2.840.113549.2.9",  "sha256" },
+   { "1.2.840.113549.2.10", "sha384" },
+   { "1.2.840.113549.2.11", "sha512" },
+   { "1.2.840.113549.2.12", "sha512-224" },
+   { "1.2.840.113549.2.13", "sha512-256" },
+};
+
+static const pbes_properties _pbes2_default_types[] = {
+   { pkcs_5_alg2, "sha1",   "des",   8, 0 },
+   { pkcs_5_alg2, "sha1",   "rc2",   4, 0 },
+   { pkcs_5_alg2, "sha1",   "3des", 24, 0 },
+   { pkcs_5_alg2, "sha1",   "aes",  16, 0 },
+   { pkcs_5_alg2, "sha1",   "aes",  24, 0 },
+   { pkcs_5_alg2, "sha1",   "aes",  32, 0 },
+};
+
+typedef struct {
+   const pbes_properties *data;
+   const char* oid;
+} oid_to_pbes;
+
+static const oid_to_pbes _pbes2_list[] = {
+   { &_pbes2_default_types[0], "1.3.14.3.2.7"            },  /* http://www.oid-info.com/get/1.3.14.3.2.7            desCBC */
+   { &_pbes2_default_types[1], "1.2.840.113549.3.2"      },  /* http://www.oid-info.com/get/1.2.840.113549.3.2      rc2CBC */
+   { &_pbes2_default_types[2], "1.2.840.113549.3.7"      },  /* http://www.oid-info.com/get/1.2.840.113549.3.7      des-EDE3-CBC */
+   { &_pbes2_default_types[3], "2.16.840.1.101.3.4.1.2"  },  /* http://www.oid-info.com/get/2.16.840.1.101.3.4.1.2  aes128-CBC */
+   { &_pbes2_default_types[4], "2.16.840.1.101.3.4.1.22" },  /* http://www.oid-info.com/get/2.16.840.1.101.3.4.1.22 aes192-CBC */
+   { &_pbes2_default_types[5], "2.16.840.1.101.3.4.1.42" },  /* http://www.oid-info.com/get/2.16.840.1.101.3.4.1.42 aes256-CBC */
+};
+
+static int _pbes2_from_oid(const ltc_asn1_list *cipher_oid, const ltc_asn1_list *hmac_oid, pbes_properties *res)
+{
+   unsigned int i;
+   for (i = 0; i < sizeof(_pbes2_list)/sizeof(_pbes2_list[0]); ++i) {
+      if (pk_oid_cmp_with_asn1(_pbes2_list[i].oid, cipher_oid) == CRYPT_OK) {
+         *res = *_pbes2_list[i].data;
+         break;
+      }
+   }
+   if (res->c == NULL) return CRYPT_INVALID_CIPHER;
+   if (hmac_oid != NULL) {
+      for (i = 0; i < sizeof(_hmac_oid_names)/sizeof(_hmac_oid_names[0]); ++i) {
+         if (pk_oid_cmp_with_asn1(_hmac_oid_names[i].oid, hmac_oid) == CRYPT_OK) {
+            res->h = _hmac_oid_names[i].id;
+            return CRYPT_OK;
+         }
+      }
+      return CRYPT_INVALID_HASH;
+   }
+   return CRYPT_OK;
+}
+
+
+/**
+   Extract PBES2 parameters
+
+   @param s     The start of the sequence with potential PBES2 parameters
+   @param res   Pointer to where the extracted parameters should be stored
+   @return CRYPT_OK on success
+*/
+int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res)
+{
+   unsigned long klen;
+   ltc_asn1_list *lkdf, *lenc, *loptseq, *lhmac;
+   int err;
+
+   LTC_ARGCHK(s   != NULL);
+   LTC_ARGCHK(res != NULL);
+
+   if ((err = pk_oid_cmp_with_asn1(_oid_pbes2, s)) != CRYPT_OK) return err;
+
+   if (!LTC_ASN1_IS_TYPE(s->next, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(s->next->child, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(s->next->child->child, LTC_ASN1_OBJECT_IDENTIFIER) ||
+       !LTC_ASN1_IS_TYPE(s->next->child->child->next, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(s->next->child->next, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(s->next->child->next->child, LTC_ASN1_OBJECT_IDENTIFIER)) {
+      return CRYPT_INVALID_PACKET;
+   }
+   /* PBES2: encrypted pkcs8 - PBES2+PBKDF2+des-ede3-cbc:
+    *  0:d=0  hl=4 l= 380 cons: SEQUENCE
+    *  4:d=1  hl=2 l=  78 cons:   SEQUENCE
+    *  6:d=2  hl=2 l=   9 prim:     OBJECT             :PBES2 (== 1.2.840.113549.1.5.13) (== *s)
+    * 17:d=2  hl=2 l=  65 cons:     SEQUENCE
+    * 19:d=3  hl=2 l=  41 cons:       SEQUENCE
+    * 21:d=4  hl=2 l=   9 prim:         OBJECT         :PBKDF2 (== *lkdf)
+    * 32:d=4  hl=2 l=  28 cons:         SEQUENCE
+    * 34:d=5  hl=2 l=   8 prim:           OCTET STRING [HEX DUMP]:28BA4ABF6AA76A3D (== res->salt)
+    * 44:d=5  hl=2 l=   2 prim:           INTEGER      :0800 (== res->iterations)
+    * 48:d=5  hl=2 l=  12 cons:           SEQUENCE     (== *loptseq   - this sequence is optional, may be missing)
+    * 50:d=6  hl=2 l=   8 prim:             OBJECT     :hmacWithSHA256 (== *lhmac)
+    * 60:d=6  hl=2 l=   0 prim:             NULL
+    * 62:d=3  hl=2 l=  20 cons:       SEQUENCE
+    * 64:d=4  hl=2 l=   8 prim:         OBJECT         :des-ede3-cbc (== *lenc)
+    * 74:d=4  hl=2 l=   8 prim:         OCTET STRING   [HEX DUMP]:B1404C4688DC9A5A
+    * 84:d=1  hl=4 l= 296 prim:   OCTET STRING         :bytes (== encrypted data)
+    */
+   lkdf = s->next->child->child;
+   lenc = s->next->child->next->child;
+
+   if ((err = pk_oid_cmp_with_asn1(_oid_pbkdf2, lkdf)) != CRYPT_OK) return err;
+
+   if (!LTC_ASN1_IS_TYPE(lkdf->next, LTC_ASN1_SEQUENCE) ||
+       !LTC_ASN1_IS_TYPE(lkdf->next->child, LTC_ASN1_OCTET_STRING) ||
+       !LTC_ASN1_IS_TYPE(lkdf->next->child->next, LTC_ASN1_INTEGER)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   loptseq = lkdf->next->child->next->next;
+   res->salt = lkdf->next->child;
+   res->iterations = mp_get_int(lkdf->next->child->next->data);
+
+   /* this sequence is optional */
+   lhmac = NULL;
+   if (LTC_ASN1_IS_TYPE(loptseq, LTC_ASN1_SEQUENCE) &&
+       LTC_ASN1_IS_TYPE(loptseq->child, LTC_ASN1_OBJECT_IDENTIFIER)) {
+      lhmac = loptseq->child;
+   }
+   if ((err = _pbes2_from_oid(lenc, lhmac, &res->type)) != CRYPT_OK) return err;
+
+   if (LTC_ASN1_IS_TYPE(lenc->next, LTC_ASN1_OCTET_STRING)) {
+      /* 'NON-RC2'-CBC */
+      res->iv = lenc->next;
+   } else if (LTC_ASN1_IS_TYPE(lenc->next, LTC_ASN1_SEQUENCE)) {
+      /* RC2-CBC is a bit special ...
+       *
+       * RC2-CBC-Parameter ::= SEQUENCE {
+       *     rc2ParameterVersion INTEGER OPTIONAL,
+       *     iv OCTET STRING (SIZE(8)) }
+       */
+      if (LTC_ASN1_IS_TYPE(lenc->next->child, LTC_ASN1_INTEGER) &&
+          LTC_ASN1_IS_TYPE(lenc->next->child->next, LTC_ASN1_OCTET_STRING)) {
+         klen = mp_get_int(lenc->next->child->data);
+         res->iv   = lenc->next->child->next;
+         /*
+          * Effective Key Bits         Encoding
+          *         40                    160
+          *         64                    120
+          *        128                     58
+          *       b >= 256                  b
+          */
+         switch (klen) {
+            case 160:
+               res->key_bits = 40;
+               break;
+            case 120:
+               res->key_bits = 64;
+               break;
+            case 58:
+               res->key_bits = 128;
+               break;
+            default:
+               /* We don't handle undefined Key Bits */
+               if (klen < 256) return CRYPT_INVALID_KEYSIZE;
+
+               res->key_bits = klen;
+               break;
+         }
+      } else if (LTC_ASN1_IS_TYPE(lenc->next->child, LTC_ASN1_OCTET_STRING)) {
+         res->iv   = lenc->next->child;
+         /*
+          * If the rc2ParameterVersion field is omitted, the "effective key bits"
+          * defaults to 32.
+          */
+         res->key_bits = 32;
+      } else {
+         return CRYPT_INVALID_PACKET;
+      }
+   }
+
+   return CRYPT_OK;
+}
+
 #endif
 
 /* ref:         $Format:%D$ */