1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 #ifdef LTC_PBES
13 
_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)14 static int _pkcs_5_alg1_wrap(const unsigned char *password, unsigned long password_len,
15                               const unsigned char *salt,     unsigned long salt_len,
16                               int iteration_count,  int hash_idx,
17                               unsigned char *out,   unsigned long *outlen)
18 {
19    LTC_UNUSED_PARAM(salt_len);
20    return pkcs_5_alg1(password, password_len, salt, iteration_count, hash_idx, out, outlen);
21 }
22 
_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)23 static int _pkcs_12_wrap(const unsigned char *password, unsigned long password_len,
24                               const unsigned char *salt,     unsigned long salt_len,
25                               int iteration_count,  int hash_idx,
26                               unsigned char *out,   unsigned long *outlen)
27 {
28    int err;
29    /* convert password to unicode/utf16-be */
30    unsigned long pwlen = password_len * 2;
31    unsigned char* pw;
32    if (*outlen < 32) return CRYPT_INVALID_ARG;
33    pw = XMALLOC(pwlen + 2);
34    if (pw == NULL) return CRYPT_MEM;
35    if ((err = pkcs12_utf8_to_utf16(password, password_len, pw, &pwlen)) != CRYPT_OK) goto LBL_ERROR;
36    pw[pwlen++] = 0;
37    pw[pwlen++] = 0;
38    /* derive KEY */
39    if ((err = pkcs12_kdf(hash_idx, pw, pwlen, salt, salt_len, iteration_count, 1, out, 24)) != CRYPT_OK) goto LBL_ERROR;
40    /* derive IV */
41    if ((err = pkcs12_kdf(hash_idx, pw, pwlen, salt, salt_len, iteration_count, 2, out+24, 8)) != CRYPT_OK) goto LBL_ERROR;
42 
43    *outlen = 32;
44 LBL_ERROR:
45    zeromem(pw, pwlen);
46    XFREE(pw);
47    return err;
48 }
49 
50 static const pbes_properties _pbes1_types[] = {
51    { _pkcs_5_alg1_wrap, "md2",   "des",   8, 8 },
52    { _pkcs_5_alg1_wrap, "md2",   "rc2",   8, 8 },
53    { _pkcs_5_alg1_wrap, "md5",   "des",   8, 8 },
54    { _pkcs_5_alg1_wrap, "md5",   "rc2",   8, 8 },
55    { _pkcs_5_alg1_wrap, "sha1",  "des",   8, 8 },
56    { _pkcs_5_alg1_wrap, "sha1",  "rc2",   8, 8 },
57    { _pkcs_12_wrap,     "sha1",  "3des", 24, 8 },
58 };
59 
60 typedef struct {
61    const pbes_properties *data;
62    const char *oid;
63 } oid_to_pbes;
64 
65 static const oid_to_pbes _pbes1_list[] = {
66    { &_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 */
67    { &_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 */
68    { &_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 */
69    { &_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 */
70    { &_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 */
71    { &_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 */
72    { &_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 */
73    { 0 },
74 };
75 
_pbes1_from_oid(const ltc_asn1_list * oid,pbes_properties * res)76 static int _pbes1_from_oid(const ltc_asn1_list *oid, pbes_properties *res)
77 {
78    unsigned int i;
79    for (i = 0; _pbes1_list[i].data != NULL; ++i) {
80       if (pk_oid_cmp_with_asn1(_pbes1_list[i].oid, oid) == CRYPT_OK) {
81          if (res != NULL) *res = *_pbes1_list[i].data;
82          return CRYPT_OK;
83       }
84    }
85    return CRYPT_INVALID_ARG;
86 }
87 
88 /**
89    Extract PBES1 parameters
90 
91    @param s     The start of the sequence with potential PBES1 parameters
92    @param res   Pointer to where the extracted parameters should be stored
93    @return CRYPT_OK on success
94 */
pbes1_extract(const ltc_asn1_list * s,pbes_arg * res)95 int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res)
96 {
97    int err;
98 
99    LTC_ARGCHK(s   != NULL);
100    LTC_ARGCHK(res != NULL);
101 
102    if ((err = _pbes1_from_oid(s, &res->type)) != CRYPT_OK) return err;
103 
104    if (!LTC_ASN1_IS_TYPE(s->next, LTC_ASN1_SEQUENCE) ||
105        !LTC_ASN1_IS_TYPE(s->next->child, LTC_ASN1_OCTET_STRING) ||
106        !LTC_ASN1_IS_TYPE(s->next->child->next, LTC_ASN1_INTEGER)) {
107       return CRYPT_INVALID_PACKET;
108    }
109    /* PBES1: encrypted pkcs8 - pbeWithMD5AndDES-CBC:
110     *  0:d=0  hl=4 l= 329 cons: SEQUENCE
111     *  4:d=1  hl=2 l=  27 cons:   SEQUENCE
112     *  6:d=2  hl=2 l=   9 prim:     OBJECT             :pbeWithMD5AndDES-CBC (== 1.2.840.113549.1.5.3) (== *s)
113     * 17:d=2  hl=2 l=  14 cons:     SEQUENCE           (== *lalgparam)
114     * 19:d=3  hl=2 l=   8 prim:       OCTET STRING     [HEX DUMP]:8EDF749A06CCDE51 (== salt)
115     * 29:d=3  hl=2 l=   2 prim:       INTEGER          :0800  (== iterations)
116     * 33:d=1  hl=4 l= 296 prim:   OCTET STRING         :bytes (== encrypted data)
117     */
118    res->salt = s->next->child;
119    res->iterations = mp_get_int(s->next->child->next->data);
120 
121    return CRYPT_OK;
122 }
123 
124 #endif
125 
126 /* ref:         $Format:%D$ */
127 /* git commit:  $Format:%H$ */
128 /* commit time: $Format:%ai$ */
129