| // SPDX-License-Identifier: BSD-2-Clause |
| /* LibTomCrypt, modular cryptographic library -- Tom St Denis |
| * |
| * LibTomCrypt is a library that provides various cryptographic |
| * algorithms in a highly modular and flexible manner. |
| * |
| * The library is free for all purposes without any express |
| * guarantee it works. |
| */ |
| #include "tomcrypt_private.h" |
| |
| #ifdef LTC_PBES |
| |
| static const char * const _oid_pbes2 = "1.2.840.113549.1.5.13"; |
| static const char * const _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, *liter, *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, *liter) |
| * 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; |
| } |
| |
| liter = lkdf->next->child->next; |
| loptseq = liter->next; |
| res->salt = lkdf->next->child; |
| res->iterations = mp_get_int(liter->data); |
| |
| /* There's an optional INTEGER keyLength after the iterations, skip that if it's there. |
| * c.f. RFC 2898 A.2 PBKDF2 */ |
| if(LTC_ASN1_IS_TYPE(loptseq, LTC_ASN1_INTEGER)) { |
| loptseq = loptseq->next; |
| } |
| |
| /* 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$ */ |
| /* git commit: $Format:%H$ */ |
| /* commit time: $Format:%ai$ */ |