|
@@ -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$ */
|