1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file pkcs_5_1.c
7    PKCS #5, Algorithm #1, Tom St Denis
8 */
9 #ifdef LTC_PKCS_5
10 /**
11    Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.
12 
13    PKCS#5 v1 specifies that the output key length can be no larger than
14    the hash output length.  OpenSSL unilaterally extended that by repeating
15    the hash process on a block-by-block basis for as long as needed to make
16    bigger keys.  If you want to be compatible with KDF for e.g. "openssl enc",
17    you'll want that.
18 
19    If you want strict PKCS behavior, turn openssl_compat off.  Or (more
20    likely), use one of the convenience functions below.
21 
22    @param password         The password (or key)
23    @param password_len     The length of the password (octet)
24    @param salt             The salt (or nonce) which is 8 octets long
25    @param iteration_count  The PKCS #5 v1 iteration count
26    @param hash_idx         The index of the hash desired
27    @param out              [out] The destination for this algorithm
28    @param outlen           [in/out] The max size and resulting size of the algorithm output
29    @param openssl_compat   [in] Whether or not to grow the key to the buffer size ala OpenSSL
30    @return CRYPT_OK if successful
31 */
s_pkcs_5_alg1_common(const unsigned char * password,unsigned long password_len,const unsigned char * salt,int iteration_count,int hash_idx,unsigned char * out,unsigned long * outlen,int openssl_compat)32 static int s_pkcs_5_alg1_common(const unsigned char *password,
33                        unsigned long password_len,
34                        const unsigned char *salt,
35                        int iteration_count,  int hash_idx,
36                        unsigned char *out,   unsigned long *outlen,
37                        int openssl_compat)
38 {
39    int err;
40    unsigned long x;
41    hash_state    *md;
42    unsigned char *buf;
43    /* Storage vars in case we need to support > hashsize (OpenSSL compat) */
44    unsigned long block = 0, iter;
45    /* How many bytes to put in the outbut buffer (convenience calc) */
46    unsigned long outidx = 0, nb = 0;
47 
48    LTC_ARGCHK(password != NULL);
49    LTC_ARGCHK(salt     != NULL);
50    LTC_ARGCHK(out      != NULL);
51    LTC_ARGCHK(outlen   != NULL);
52 
53    if (iteration_count <= 0) {
54       return CRYPT_INVALID_ARG;
55    }
56 
57    /* test hash IDX */
58    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
59       return err;
60    }
61 
62    /* allocate memory */
63    md  = XMALLOC(sizeof(hash_state));
64    buf = XMALLOC(MAXBLOCKSIZE);
65    if (md == NULL || buf == NULL) {
66       if (md != NULL) {
67          XFREE(md);
68       }
69       if (buf != NULL) {
70          XFREE(buf);
71       }
72       return CRYPT_MEM;
73    }
74 
75    while(block * hash_descriptor[hash_idx]->hashsize < *outlen) {
76 
77       /* hash initial (maybe previous hash) + password + salt */
78       if ((err = hash_descriptor[hash_idx]->init(md)) != CRYPT_OK) {
79           goto LBL_ERR;
80       }
81       /* in OpenSSL mode, we first hash the previous result for blocks 2-n */
82       if (openssl_compat && block) {
83           if ((err = hash_descriptor[hash_idx]->process(md, buf, hash_descriptor[hash_idx]->hashsize)) != CRYPT_OK) {
84               goto LBL_ERR;
85           }
86       }
87       if ((err = hash_descriptor[hash_idx]->process(md, password, password_len)) != CRYPT_OK) {
88           goto LBL_ERR;
89       }
90       if ((err = hash_descriptor[hash_idx]->process(md, salt, 8)) != CRYPT_OK) {
91           goto LBL_ERR;
92       }
93       if ((err = hash_descriptor[hash_idx]->done(md, buf)) != CRYPT_OK) {
94           goto LBL_ERR;
95       }
96 
97       iter = iteration_count;
98       while (--iter) {
99          /* code goes here. */
100          x = MAXBLOCKSIZE;
101          if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx]->hashsize, buf, &x)) != CRYPT_OK) {
102             goto LBL_ERR;
103          }
104       }
105 
106       /* limit the size of the copy to however many bytes we have left in
107          the output buffer (and how many bytes we have to copy) */
108       outidx = block*hash_descriptor[hash_idx]->hashsize;
109       nb = hash_descriptor[hash_idx]->hashsize;
110       if(outidx+nb > *outlen) {
111           nb = *outlen - outidx;
112       }
113       if(nb > 0) {
114           XMEMCPY(out+outidx, buf, nb);
115       }
116 
117       block++;
118       if (!openssl_compat) {
119           break;
120       }
121    }
122    /* In strict mode, we always return the hashsize, in compat we filled it
123       as much as was requested, so we leave it alone. */
124    if(!openssl_compat) {
125       *outlen = hash_descriptor[hash_idx]->hashsize;
126    }
127 
128    err = CRYPT_OK;
129 LBL_ERR:
130 #ifdef LTC_CLEAN_STACK
131    zeromem(buf, MAXBLOCKSIZE);
132    zeromem(md, sizeof(hash_state));
133 #endif
134 
135    XFREE(buf);
136    XFREE(md);
137 
138    return err;
139 }
140 
141 /**
142    Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)
143    @param password         The password (or key)
144    @param password_len     The length of the password (octet)
145    @param salt             The salt (or nonce) which is 8 octets long
146    @param iteration_count  The PKCS #5 v1 iteration count
147    @param hash_idx         The index of the hash desired
148    @param out              [out] The destination for this algorithm
149    @param outlen           [in/out] The max size and resulting size of the algorithm output
150    @return CRYPT_OK if successful
151 */
pkcs_5_alg1(const unsigned char * password,unsigned long password_len,const unsigned char * salt,int iteration_count,int hash_idx,unsigned char * out,unsigned long * outlen)152 int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
153                 const unsigned char *salt,
154                 int iteration_count,  int hash_idx,
155                 unsigned char *out,   unsigned long *outlen)
156 {
157    return s_pkcs_5_alg1_common(password, password_len, salt, iteration_count,
158                              hash_idx, out, outlen, 0);
159 }
160 
161 /**
162    Execute PKCS #5 v1 - OpenSSL-extension-compatible mode
163 
164    Use this one if you need to derive keys as "openssl enc" does by default.
165    OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.
166    @param password         The password (or key)
167    @param password_len     The length of the password (octet)
168    @param salt             The salt (or nonce) which is 8 octets long
169    @param iteration_count  The PKCS #5 v1 iteration count
170    @param hash_idx         The index of the hash desired
171    @param out              [out] The destination for this algorithm
172    @param outlen           [in/out] The max size and resulting size of the algorithm output
173    @return CRYPT_OK if successful
174 */
pkcs_5_alg1_openssl(const unsigned char * password,unsigned long password_len,const unsigned char * salt,int iteration_count,int hash_idx,unsigned char * out,unsigned long * outlen)175 int pkcs_5_alg1_openssl(const unsigned char *password,
176                         unsigned long password_len,
177                         const unsigned char *salt,
178                         int iteration_count,  int hash_idx,
179                         unsigned char *out,   unsigned long *outlen)
180 {
181    return s_pkcs_5_alg1_common(password, password_len, salt, iteration_count,
182                              hash_idx, out, outlen, 1);
183 }
184 
185 #endif
186