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