]>
Commit | Line | Data |
---|---|---|
e98aa30d | 1 | /* |
da1c088f | 2 | * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved. |
e98aa30d | 3 | * |
365a2d99 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
2039c421 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
e98aa30d DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include "internal/cryptlib.h" | |
12 | #include <openssl/asn1t.h> | |
b536880c | 13 | #include <openssl/core_names.h> |
e98aa30d DSH |
14 | #include <openssl/err.h> |
15 | #include <openssl/evp.h> | |
16 | #include <openssl/x509.h> | |
17 | #include <openssl/rand.h> | |
b536880c | 18 | #include "crypto/evp.h" |
e98aa30d | 19 | |
b0809bc8 | 20 | #ifndef OPENSSL_NO_SCRYPT |
e98aa30d DSH |
21 | /* PKCS#5 scrypt password based encryption structures */ |
22 | ||
e98aa30d DSH |
23 | ASN1_SEQUENCE(SCRYPT_PARAMS) = { |
24 | ASN1_SIMPLE(SCRYPT_PARAMS, salt, ASN1_OCTET_STRING), | |
25 | ASN1_SIMPLE(SCRYPT_PARAMS, costParameter, ASN1_INTEGER), | |
26 | ASN1_SIMPLE(SCRYPT_PARAMS, blockSize, ASN1_INTEGER), | |
27 | ASN1_SIMPLE(SCRYPT_PARAMS, parallelizationParameter, ASN1_INTEGER), | |
28 | ASN1_OPT(SCRYPT_PARAMS, keyLength, ASN1_INTEGER), | |
e15c95ce | 29 | } ASN1_SEQUENCE_END(SCRYPT_PARAMS) |
e98aa30d | 30 | |
e15c95ce | 31 | IMPLEMENT_ASN1_FUNCTIONS(SCRYPT_PARAMS) |
e98aa30d DSH |
32 | |
33 | static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, size_t saltlen, | |
34 | size_t keylen, uint64_t N, uint64_t r, | |
35 | uint64_t p); | |
36 | ||
37 | /* | |
38 | * Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm using scrypt | |
39 | */ | |
40 | ||
41 | X509_ALGOR *PKCS5_pbe2_set_scrypt(const EVP_CIPHER *cipher, | |
42 | const unsigned char *salt, int saltlen, | |
43 | unsigned char *aiv, uint64_t N, uint64_t r, | |
44 | uint64_t p) | |
45 | { | |
2191dc84 | 46 | X509_ALGOR *scheme = NULL, *ret = NULL; |
e98aa30d DSH |
47 | int alg_nid; |
48 | size_t keylen = 0; | |
846ec07d | 49 | EVP_CIPHER_CTX *ctx = NULL; |
e98aa30d DSH |
50 | unsigned char iv[EVP_MAX_IV_LENGTH]; |
51 | PBE2PARAM *pbe2 = NULL; | |
e98aa30d DSH |
52 | |
53 | if (!cipher) { | |
9311d0c4 | 54 | ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER); |
e98aa30d DSH |
55 | goto err; |
56 | } | |
57 | ||
58 | if (EVP_PBE_scrypt(NULL, 0, NULL, 0, N, r, p, 0, NULL, 0) == 0) { | |
9311d0c4 | 59 | ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_SCRYPT_PARAMETERS); |
e98aa30d DSH |
60 | goto err; |
61 | } | |
62 | ||
ed576acd | 63 | alg_nid = EVP_CIPHER_get_type(cipher); |
e98aa30d | 64 | if (alg_nid == NID_undef) { |
9311d0c4 | 65 | ERR_raise(ERR_LIB_ASN1, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); |
e98aa30d DSH |
66 | goto err; |
67 | } | |
2191dc84 | 68 | |
e98aa30d | 69 | pbe2 = PBE2PARAM_new(); |
e077455e RL |
70 | if (pbe2 == NULL) { |
71 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
72 | goto err; | |
73 | } | |
e98aa30d DSH |
74 | |
75 | /* Setup the AlgorithmIdentifier for the encryption scheme */ | |
76 | scheme = pbe2->encryption; | |
77 | ||
2191dc84 | 78 | scheme->algorithm = OBJ_nid2obj(alg_nid); |
e98aa30d | 79 | scheme->parameter = ASN1_TYPE_new(); |
e077455e RL |
80 | if (scheme->parameter == NULL) { |
81 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
82 | goto err; | |
83 | } | |
e98aa30d DSH |
84 | |
85 | /* Create random IV */ | |
ed576acd | 86 | if (EVP_CIPHER_get_iv_length(cipher)) { |
e98aa30d | 87 | if (aiv) |
ed576acd TM |
88 | memcpy(iv, aiv, EVP_CIPHER_get_iv_length(cipher)); |
89 | else if (RAND_bytes(iv, EVP_CIPHER_get_iv_length(cipher)) <= 0) | |
e98aa30d DSH |
90 | goto err; |
91 | } | |
92 | ||
846ec07d | 93 | ctx = EVP_CIPHER_CTX_new(); |
e077455e RL |
94 | if (ctx == NULL) { |
95 | ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); | |
96 | goto err; | |
97 | } | |
e98aa30d DSH |
98 | |
99 | /* Dummy cipherinit to just setup the IV */ | |
846ec07d | 100 | if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, iv, 0) == 0) |
e98aa30d | 101 | goto err; |
49c9c1b3 | 102 | if (EVP_CIPHER_param_to_asn1(ctx, scheme->parameter) <= 0) { |
9311d0c4 | 103 | ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_SETTING_CIPHER_PARAMS); |
e98aa30d DSH |
104 | goto err; |
105 | } | |
846ec07d RL |
106 | EVP_CIPHER_CTX_free(ctx); |
107 | ctx = NULL; | |
e98aa30d DSH |
108 | |
109 | /* If its RC2 then we'd better setup the key length */ | |
110 | ||
111 | if (alg_nid == NID_rc2_cbc) | |
ed576acd | 112 | keylen = EVP_CIPHER_get_key_length(cipher); |
e98aa30d DSH |
113 | |
114 | /* Setup keyfunc */ | |
115 | ||
116 | X509_ALGOR_free(pbe2->keyfunc); | |
117 | ||
118 | pbe2->keyfunc = pkcs5_scrypt_set(salt, saltlen, keylen, N, r, p); | |
119 | ||
e077455e RL |
120 | if (pbe2->keyfunc == NULL) { |
121 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
122 | goto err; | |
123 | } | |
e98aa30d DSH |
124 | |
125 | /* Now set up top level AlgorithmIdentifier */ | |
126 | ||
127 | ret = X509_ALGOR_new(); | |
e077455e RL |
128 | if (ret == NULL) { |
129 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
130 | goto err; | |
131 | } | |
e98aa30d DSH |
132 | |
133 | ret->algorithm = OBJ_nid2obj(NID_pbes2); | |
134 | ||
135 | /* Encode PBE2PARAM into parameter */ | |
136 | ||
137 | if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBE2PARAM), pbe2, | |
e077455e RL |
138 | &ret->parameter) == NULL) { |
139 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
140 | goto err; | |
141 | } | |
e98aa30d DSH |
142 | |
143 | PBE2PARAM_free(pbe2); | |
144 | pbe2 = NULL; | |
145 | ||
146 | return ret; | |
147 | ||
e98aa30d DSH |
148 | err: |
149 | PBE2PARAM_free(pbe2); | |
e98aa30d | 150 | X509_ALGOR_free(ret); |
846ec07d | 151 | EVP_CIPHER_CTX_free(ctx); |
e98aa30d DSH |
152 | |
153 | return NULL; | |
e98aa30d DSH |
154 | } |
155 | ||
156 | static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, size_t saltlen, | |
157 | size_t keylen, uint64_t N, uint64_t r, | |
158 | uint64_t p) | |
159 | { | |
160 | X509_ALGOR *keyfunc = NULL; | |
2191dc84 | 161 | SCRYPT_PARAMS *sparam = SCRYPT_PARAMS_new(); |
e98aa30d | 162 | |
e077455e RL |
163 | if (sparam == NULL) { |
164 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
165 | goto err; | |
166 | } | |
e98aa30d DSH |
167 | |
168 | if (!saltlen) | |
3859a027 | 169 | saltlen = PKCS5_DEFAULT_PBE2_SALT_LEN; |
e98aa30d DSH |
170 | |
171 | /* This will either copy salt or grow the buffer */ | |
e077455e RL |
172 | if (ASN1_STRING_set(sparam->salt, salt, saltlen) == 0) { |
173 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
174 | goto err; | |
175 | } | |
e98aa30d DSH |
176 | |
177 | if (salt == NULL && RAND_bytes(sparam->salt->data, saltlen) <= 0) | |
178 | goto err; | |
179 | ||
e077455e RL |
180 | if (ASN1_INTEGER_set_uint64(sparam->costParameter, N) == 0) { |
181 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
182 | goto err; | |
183 | } | |
e98aa30d | 184 | |
e077455e RL |
185 | if (ASN1_INTEGER_set_uint64(sparam->blockSize, r) == 0) { |
186 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
187 | goto err; | |
188 | } | |
e98aa30d | 189 | |
e077455e RL |
190 | if (ASN1_INTEGER_set_uint64(sparam->parallelizationParameter, p) == 0) { |
191 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
192 | goto err; | |
193 | } | |
e98aa30d DSH |
194 | |
195 | /* If have a key len set it up */ | |
196 | ||
197 | if (keylen > 0) { | |
198 | sparam->keyLength = ASN1_INTEGER_new(); | |
e077455e RL |
199 | if (sparam->keyLength == NULL) { |
200 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
201 | goto err; | |
202 | } | |
203 | if (ASN1_INTEGER_set_int64(sparam->keyLength, keylen) == 0) { | |
204 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
205 | goto err; | |
206 | } | |
e98aa30d DSH |
207 | } |
208 | ||
209 | /* Finally setup the keyfunc structure */ | |
210 | ||
211 | keyfunc = X509_ALGOR_new(); | |
e077455e RL |
212 | if (keyfunc == NULL) { |
213 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
214 | goto err; | |
215 | } | |
e98aa30d DSH |
216 | |
217 | keyfunc->algorithm = OBJ_nid2obj(NID_id_scrypt); | |
218 | ||
219 | /* Encode SCRYPT_PARAMS into parameter of pbe2 */ | |
220 | ||
221 | if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(SCRYPT_PARAMS), sparam, | |
e077455e RL |
222 | &keyfunc->parameter) == NULL) { |
223 | ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); | |
224 | goto err; | |
225 | } | |
e98aa30d DSH |
226 | |
227 | SCRYPT_PARAMS_free(sparam); | |
228 | return keyfunc; | |
229 | ||
e98aa30d DSH |
230 | err: |
231 | SCRYPT_PARAMS_free(sparam); | |
232 | X509_ALGOR_free(keyfunc); | |
233 | return NULL; | |
234 | } | |
235 | ||
b536880c JS |
236 | int PKCS5_v2_scrypt_keyivgen_ex(EVP_CIPHER_CTX *ctx, const char *pass, |
237 | int passlen, ASN1_TYPE *param, | |
238 | const EVP_CIPHER *c, const EVP_MD *md, int en_de, | |
239 | OSSL_LIB_CTX *libctx, const char *propq) | |
e98aa30d DSH |
240 | { |
241 | unsigned char *salt, key[EVP_MAX_KEY_LENGTH]; | |
242 | uint64_t p, r, N; | |
243 | size_t saltlen; | |
244 | size_t keylen = 0; | |
0484af22 | 245 | int t, rv = 0; |
e98aa30d DSH |
246 | SCRYPT_PARAMS *sparam = NULL; |
247 | ||
f6c95e46 | 248 | if (EVP_CIPHER_CTX_get0_cipher(ctx) == NULL) { |
9311d0c4 | 249 | ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); |
e98aa30d DSH |
250 | goto err; |
251 | } | |
252 | ||
253 | /* Decode parameter */ | |
254 | ||
255 | sparam = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(SCRYPT_PARAMS), param); | |
256 | ||
257 | if (sparam == NULL) { | |
9311d0c4 | 258 | ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR); |
e98aa30d DSH |
259 | goto err; |
260 | } | |
261 | ||
ed576acd | 262 | t = EVP_CIPHER_CTX_get_key_length(ctx); |
0484af22 | 263 | if (t < 0) { |
9311d0c4 | 264 | ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH); |
0484af22 P |
265 | goto err; |
266 | } | |
267 | keylen = t; | |
e98aa30d DSH |
268 | |
269 | /* Now check the parameters of sparam */ | |
270 | ||
271 | if (sparam->keyLength) { | |
272 | uint64_t spkeylen; | |
273 | if ((ASN1_INTEGER_get_uint64(&spkeylen, sparam->keyLength) == 0) | |
274 | || (spkeylen != keylen)) { | |
9311d0c4 | 275 | ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEYLENGTH); |
e98aa30d DSH |
276 | goto err; |
277 | } | |
278 | } | |
279 | /* Check all parameters fit in uint64_t and are acceptable to scrypt */ | |
280 | if (ASN1_INTEGER_get_uint64(&N, sparam->costParameter) == 0 | |
281 | || ASN1_INTEGER_get_uint64(&r, sparam->blockSize) == 0 | |
282 | || ASN1_INTEGER_get_uint64(&p, sparam->parallelizationParameter) == 0 | |
b536880c JS |
283 | || EVP_PBE_scrypt_ex(NULL, 0, NULL, 0, N, r, p, 0, NULL, 0, |
284 | libctx, propq) == 0) { | |
9311d0c4 | 285 | ERR_raise(ERR_LIB_EVP, EVP_R_ILLEGAL_SCRYPT_PARAMETERS); |
e98aa30d DSH |
286 | goto err; |
287 | } | |
288 | ||
289 | /* it seems that its all OK */ | |
290 | ||
291 | salt = sparam->salt->data; | |
292 | saltlen = sparam->salt->length; | |
b536880c JS |
293 | if (EVP_PBE_scrypt_ex(pass, passlen, salt, saltlen, N, r, p, 0, key, |
294 | keylen, libctx, propq) == 0) | |
e98aa30d DSH |
295 | goto err; |
296 | rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de); | |
297 | err: | |
298 | if (keylen) | |
299 | OPENSSL_cleanse(key, keylen); | |
300 | SCRYPT_PARAMS_free(sparam); | |
301 | return rv; | |
302 | } | |
b536880c JS |
303 | |
304 | int PKCS5_v2_scrypt_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, | |
305 | int passlen, ASN1_TYPE *param, | |
306 | const EVP_CIPHER *c, const EVP_MD *md, int en_de) | |
307 | { | |
308 | return PKCS5_v2_scrypt_keyivgen_ex(ctx, pass, passlen, param, c, md, en_de, NULL, NULL); | |
309 | } | |
310 | ||
b0809bc8 | 311 | #endif /* OPENSSL_NO_SCRYPT */ |