xref: /freebsd-src/crypto/openssl/providers/implementations/rands/drbg_ctr.c (revision 44096ebd22ddd0081a357011714eff8963614b65)
1b077aed3SPierre Pronchery /*
2*44096ebdSEnji Cooper  * Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8b077aed3SPierre Pronchery  */
9b077aed3SPierre Pronchery 
10b077aed3SPierre Pronchery #include <stdlib.h>
11b077aed3SPierre Pronchery #include <string.h>
12b077aed3SPierre Pronchery #include <openssl/crypto.h>
13b077aed3SPierre Pronchery #include <openssl/err.h>
14b077aed3SPierre Pronchery #include <openssl/rand.h>
15b077aed3SPierre Pronchery #include <openssl/aes.h>
16b077aed3SPierre Pronchery #include <openssl/proverr.h>
17b077aed3SPierre Pronchery #include "crypto/modes.h"
18b077aed3SPierre Pronchery #include "internal/thread_once.h"
19b077aed3SPierre Pronchery #include "prov/implementations.h"
20b077aed3SPierre Pronchery #include "prov/providercommon.h"
21b077aed3SPierre Pronchery #include "prov/provider_ctx.h"
22b077aed3SPierre Pronchery #include "drbg_local.h"
23b077aed3SPierre Pronchery 
24b077aed3SPierre Pronchery static OSSL_FUNC_rand_newctx_fn drbg_ctr_new_wrapper;
25b077aed3SPierre Pronchery static OSSL_FUNC_rand_freectx_fn drbg_ctr_free;
26b077aed3SPierre Pronchery static OSSL_FUNC_rand_instantiate_fn drbg_ctr_instantiate_wrapper;
27b077aed3SPierre Pronchery static OSSL_FUNC_rand_uninstantiate_fn drbg_ctr_uninstantiate_wrapper;
28b077aed3SPierre Pronchery static OSSL_FUNC_rand_generate_fn drbg_ctr_generate_wrapper;
29b077aed3SPierre Pronchery static OSSL_FUNC_rand_reseed_fn drbg_ctr_reseed_wrapper;
30b077aed3SPierre Pronchery static OSSL_FUNC_rand_settable_ctx_params_fn drbg_ctr_settable_ctx_params;
31b077aed3SPierre Pronchery static OSSL_FUNC_rand_set_ctx_params_fn drbg_ctr_set_ctx_params;
32b077aed3SPierre Pronchery static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_ctr_gettable_ctx_params;
33b077aed3SPierre Pronchery static OSSL_FUNC_rand_get_ctx_params_fn drbg_ctr_get_ctx_params;
34b077aed3SPierre Pronchery static OSSL_FUNC_rand_verify_zeroization_fn drbg_ctr_verify_zeroization;
35b077aed3SPierre Pronchery 
36b077aed3SPierre Pronchery /*
37b077aed3SPierre Pronchery  * The state of a DRBG AES-CTR.
38b077aed3SPierre Pronchery  */
39b077aed3SPierre Pronchery typedef struct rand_drbg_ctr_st {
40b077aed3SPierre Pronchery     EVP_CIPHER_CTX *ctx_ecb;
41b077aed3SPierre Pronchery     EVP_CIPHER_CTX *ctx_ctr;
42b077aed3SPierre Pronchery     EVP_CIPHER_CTX *ctx_df;
43b077aed3SPierre Pronchery     EVP_CIPHER *cipher_ecb;
44b077aed3SPierre Pronchery     EVP_CIPHER *cipher_ctr;
45b077aed3SPierre Pronchery     size_t keylen;
46b077aed3SPierre Pronchery     int use_df;
47b077aed3SPierre Pronchery     unsigned char K[32];
48b077aed3SPierre Pronchery     unsigned char V[16];
49b077aed3SPierre Pronchery     /* Temporary block storage used by ctr_df */
50b077aed3SPierre Pronchery     unsigned char bltmp[16];
51b077aed3SPierre Pronchery     size_t bltmp_pos;
52b077aed3SPierre Pronchery     unsigned char KX[48];
53b077aed3SPierre Pronchery } PROV_DRBG_CTR;
54b077aed3SPierre Pronchery 
55b077aed3SPierre Pronchery /*
56b077aed3SPierre Pronchery  * Implementation of NIST SP 800-90A CTR DRBG.
57b077aed3SPierre Pronchery  */
inc_128(PROV_DRBG_CTR * ctr)58b077aed3SPierre Pronchery static void inc_128(PROV_DRBG_CTR *ctr)
59b077aed3SPierre Pronchery {
60b077aed3SPierre Pronchery     unsigned char *p = &ctr->V[0];
61b077aed3SPierre Pronchery     u32 n = 16, c = 1;
62b077aed3SPierre Pronchery 
63b077aed3SPierre Pronchery     do {
64b077aed3SPierre Pronchery         --n;
65b077aed3SPierre Pronchery         c += p[n];
66b077aed3SPierre Pronchery         p[n] = (u8)c;
67b077aed3SPierre Pronchery         c >>= 8;
68b077aed3SPierre Pronchery     } while (n);
69b077aed3SPierre Pronchery }
70b077aed3SPierre Pronchery 
ctr_XOR(PROV_DRBG_CTR * ctr,const unsigned char * in,size_t inlen)71b077aed3SPierre Pronchery static void ctr_XOR(PROV_DRBG_CTR *ctr, const unsigned char *in, size_t inlen)
72b077aed3SPierre Pronchery {
73b077aed3SPierre Pronchery     size_t i, n;
74b077aed3SPierre Pronchery 
75b077aed3SPierre Pronchery     if (in == NULL || inlen == 0)
76b077aed3SPierre Pronchery         return;
77b077aed3SPierre Pronchery 
78b077aed3SPierre Pronchery     /*
79b077aed3SPierre Pronchery      * Any zero padding will have no effect on the result as we
80b077aed3SPierre Pronchery      * are XORing. So just process however much input we have.
81b077aed3SPierre Pronchery      */
82b077aed3SPierre Pronchery     n = inlen < ctr->keylen ? inlen : ctr->keylen;
83b077aed3SPierre Pronchery     for (i = 0; i < n; i++)
84b077aed3SPierre Pronchery         ctr->K[i] ^= in[i];
85b077aed3SPierre Pronchery     if (inlen <= ctr->keylen)
86b077aed3SPierre Pronchery         return;
87b077aed3SPierre Pronchery 
88b077aed3SPierre Pronchery     n = inlen - ctr->keylen;
89b077aed3SPierre Pronchery     if (n > 16) {
90b077aed3SPierre Pronchery         /* Should never happen */
91b077aed3SPierre Pronchery         n = 16;
92b077aed3SPierre Pronchery     }
93b077aed3SPierre Pronchery     for (i = 0; i < n; i++)
94b077aed3SPierre Pronchery         ctr->V[i] ^= in[i + ctr->keylen];
95b077aed3SPierre Pronchery }
96b077aed3SPierre Pronchery 
97b077aed3SPierre Pronchery /*
98b077aed3SPierre Pronchery  * Process a complete block using BCC algorithm of SP 800-90A 10.3.3
99b077aed3SPierre Pronchery  */
ctr_BCC_block(PROV_DRBG_CTR * ctr,unsigned char * out,const unsigned char * in,int len)100b077aed3SPierre Pronchery __owur static int ctr_BCC_block(PROV_DRBG_CTR *ctr, unsigned char *out,
101b077aed3SPierre Pronchery                                 const unsigned char *in, int len)
102b077aed3SPierre Pronchery {
103b077aed3SPierre Pronchery     int i, outlen = AES_BLOCK_SIZE;
104b077aed3SPierre Pronchery 
105b077aed3SPierre Pronchery     for (i = 0; i < len; i++)
106b077aed3SPierre Pronchery         out[i] ^= in[i];
107b077aed3SPierre Pronchery 
108b077aed3SPierre Pronchery     if (!EVP_CipherUpdate(ctr->ctx_df, out, &outlen, out, len)
109b077aed3SPierre Pronchery         || outlen != len)
110b077aed3SPierre Pronchery         return 0;
111b077aed3SPierre Pronchery     return 1;
112b077aed3SPierre Pronchery }
113b077aed3SPierre Pronchery 
114b077aed3SPierre Pronchery 
115b077aed3SPierre Pronchery /*
116b077aed3SPierre Pronchery  * Handle several BCC operations for as much data as we need for K and X
117b077aed3SPierre Pronchery  */
ctr_BCC_blocks(PROV_DRBG_CTR * ctr,const unsigned char * in)118b077aed3SPierre Pronchery __owur static int ctr_BCC_blocks(PROV_DRBG_CTR *ctr, const unsigned char *in)
119b077aed3SPierre Pronchery {
120b077aed3SPierre Pronchery     unsigned char in_tmp[48];
121b077aed3SPierre Pronchery     unsigned char num_of_blk = 2;
122b077aed3SPierre Pronchery 
123b077aed3SPierre Pronchery     memcpy(in_tmp, in, 16);
124b077aed3SPierre Pronchery     memcpy(in_tmp + 16, in, 16);
125b077aed3SPierre Pronchery     if (ctr->keylen != 16) {
126b077aed3SPierre Pronchery         memcpy(in_tmp + 32, in, 16);
127b077aed3SPierre Pronchery         num_of_blk = 3;
128b077aed3SPierre Pronchery     }
129b077aed3SPierre Pronchery     return ctr_BCC_block(ctr, ctr->KX, in_tmp, AES_BLOCK_SIZE * num_of_blk);
130b077aed3SPierre Pronchery }
131b077aed3SPierre Pronchery 
132b077aed3SPierre Pronchery /*
133b077aed3SPierre Pronchery  * Initialise BCC blocks: these have the value 0,1,2 in leftmost positions:
134b077aed3SPierre Pronchery  * see 10.3.1 stage 7.
135b077aed3SPierre Pronchery  */
ctr_BCC_init(PROV_DRBG_CTR * ctr)136b077aed3SPierre Pronchery __owur static int ctr_BCC_init(PROV_DRBG_CTR *ctr)
137b077aed3SPierre Pronchery {
138b077aed3SPierre Pronchery     unsigned char bltmp[48] = {0};
139b077aed3SPierre Pronchery     unsigned char num_of_blk;
140b077aed3SPierre Pronchery 
141b077aed3SPierre Pronchery     memset(ctr->KX, 0, 48);
142b077aed3SPierre Pronchery     num_of_blk = ctr->keylen == 16 ? 2 : 3;
143b077aed3SPierre Pronchery     bltmp[(AES_BLOCK_SIZE * 1) + 3] = 1;
144b077aed3SPierre Pronchery     bltmp[(AES_BLOCK_SIZE * 2) + 3] = 2;
145b077aed3SPierre Pronchery     return ctr_BCC_block(ctr, ctr->KX, bltmp, num_of_blk * AES_BLOCK_SIZE);
146b077aed3SPierre Pronchery }
147b077aed3SPierre Pronchery 
148b077aed3SPierre Pronchery /*
149b077aed3SPierre Pronchery  * Process several blocks into BCC algorithm, some possibly partial
150b077aed3SPierre Pronchery  */
ctr_BCC_update(PROV_DRBG_CTR * ctr,const unsigned char * in,size_t inlen)151b077aed3SPierre Pronchery __owur static int ctr_BCC_update(PROV_DRBG_CTR *ctr,
152b077aed3SPierre Pronchery                                  const unsigned char *in, size_t inlen)
153b077aed3SPierre Pronchery {
154b077aed3SPierre Pronchery     if (in == NULL || inlen == 0)
155b077aed3SPierre Pronchery         return 1;
156b077aed3SPierre Pronchery 
157b077aed3SPierre Pronchery     /* If we have partial block handle it first */
158b077aed3SPierre Pronchery     if (ctr->bltmp_pos) {
159b077aed3SPierre Pronchery         size_t left = 16 - ctr->bltmp_pos;
160b077aed3SPierre Pronchery 
161b077aed3SPierre Pronchery         /* If we now have a complete block process it */
162b077aed3SPierre Pronchery         if (inlen >= left) {
163b077aed3SPierre Pronchery             memcpy(ctr->bltmp + ctr->bltmp_pos, in, left);
164b077aed3SPierre Pronchery             if (!ctr_BCC_blocks(ctr, ctr->bltmp))
165b077aed3SPierre Pronchery                 return 0;
166b077aed3SPierre Pronchery             ctr->bltmp_pos = 0;
167b077aed3SPierre Pronchery             inlen -= left;
168b077aed3SPierre Pronchery             in += left;
169b077aed3SPierre Pronchery         }
170b077aed3SPierre Pronchery     }
171b077aed3SPierre Pronchery 
172b077aed3SPierre Pronchery     /* Process zero or more complete blocks */
173b077aed3SPierre Pronchery     for (; inlen >= 16; in += 16, inlen -= 16) {
174b077aed3SPierre Pronchery         if (!ctr_BCC_blocks(ctr, in))
175b077aed3SPierre Pronchery             return 0;
176b077aed3SPierre Pronchery     }
177b077aed3SPierre Pronchery 
178b077aed3SPierre Pronchery     /* Copy any remaining partial block to the temporary buffer */
179b077aed3SPierre Pronchery     if (inlen > 0) {
180b077aed3SPierre Pronchery         memcpy(ctr->bltmp + ctr->bltmp_pos, in, inlen);
181b077aed3SPierre Pronchery         ctr->bltmp_pos += inlen;
182b077aed3SPierre Pronchery     }
183b077aed3SPierre Pronchery     return 1;
184b077aed3SPierre Pronchery }
185b077aed3SPierre Pronchery 
ctr_BCC_final(PROV_DRBG_CTR * ctr)186b077aed3SPierre Pronchery __owur static int ctr_BCC_final(PROV_DRBG_CTR *ctr)
187b077aed3SPierre Pronchery {
188b077aed3SPierre Pronchery     if (ctr->bltmp_pos) {
189b077aed3SPierre Pronchery         memset(ctr->bltmp + ctr->bltmp_pos, 0, 16 - ctr->bltmp_pos);
190b077aed3SPierre Pronchery         if (!ctr_BCC_blocks(ctr, ctr->bltmp))
191b077aed3SPierre Pronchery             return 0;
192b077aed3SPierre Pronchery     }
193b077aed3SPierre Pronchery     return 1;
194b077aed3SPierre Pronchery }
195b077aed3SPierre Pronchery 
ctr_df(PROV_DRBG_CTR * ctr,const unsigned char * in1,size_t in1len,const unsigned char * in2,size_t in2len,const unsigned char * in3,size_t in3len)196b077aed3SPierre Pronchery __owur static int ctr_df(PROV_DRBG_CTR *ctr,
197b077aed3SPierre Pronchery                          const unsigned char *in1, size_t in1len,
198b077aed3SPierre Pronchery                          const unsigned char *in2, size_t in2len,
199b077aed3SPierre Pronchery                          const unsigned char *in3, size_t in3len)
200b077aed3SPierre Pronchery {
201b077aed3SPierre Pronchery     static unsigned char c80 = 0x80;
202b077aed3SPierre Pronchery     size_t inlen;
203b077aed3SPierre Pronchery     unsigned char *p = ctr->bltmp;
204b077aed3SPierre Pronchery     int outlen = AES_BLOCK_SIZE;
205b077aed3SPierre Pronchery 
206b077aed3SPierre Pronchery     if (!ctr_BCC_init(ctr))
207b077aed3SPierre Pronchery         return 0;
208b077aed3SPierre Pronchery     if (in1 == NULL)
209b077aed3SPierre Pronchery         in1len = 0;
210b077aed3SPierre Pronchery     if (in2 == NULL)
211b077aed3SPierre Pronchery         in2len = 0;
212b077aed3SPierre Pronchery     if (in3 == NULL)
213b077aed3SPierre Pronchery         in3len = 0;
214b077aed3SPierre Pronchery     inlen = in1len + in2len + in3len;
215b077aed3SPierre Pronchery     /* Initialise L||N in temporary block */
216b077aed3SPierre Pronchery     *p++ = (inlen >> 24) & 0xff;
217b077aed3SPierre Pronchery     *p++ = (inlen >> 16) & 0xff;
218b077aed3SPierre Pronchery     *p++ = (inlen >> 8) & 0xff;
219b077aed3SPierre Pronchery     *p++ = inlen & 0xff;
220b077aed3SPierre Pronchery 
221b077aed3SPierre Pronchery     /* NB keylen is at most 32 bytes */
222b077aed3SPierre Pronchery     *p++ = 0;
223b077aed3SPierre Pronchery     *p++ = 0;
224b077aed3SPierre Pronchery     *p++ = 0;
225b077aed3SPierre Pronchery     *p = (unsigned char)((ctr->keylen + 16) & 0xff);
226b077aed3SPierre Pronchery     ctr->bltmp_pos = 8;
227b077aed3SPierre Pronchery     if (!ctr_BCC_update(ctr, in1, in1len)
228b077aed3SPierre Pronchery         || !ctr_BCC_update(ctr, in2, in2len)
229b077aed3SPierre Pronchery         || !ctr_BCC_update(ctr, in3, in3len)
230b077aed3SPierre Pronchery         || !ctr_BCC_update(ctr, &c80, 1)
231b077aed3SPierre Pronchery         || !ctr_BCC_final(ctr))
232b077aed3SPierre Pronchery         return 0;
233b077aed3SPierre Pronchery     /* Set up key K */
234b077aed3SPierre Pronchery     if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->KX, NULL, -1))
235b077aed3SPierre Pronchery         return 0;
236b077aed3SPierre Pronchery     /* X follows key K */
237b077aed3SPierre Pronchery     if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX, &outlen, ctr->KX + ctr->keylen,
238b077aed3SPierre Pronchery                           AES_BLOCK_SIZE)
239b077aed3SPierre Pronchery         || outlen != AES_BLOCK_SIZE)
240b077aed3SPierre Pronchery         return 0;
241b077aed3SPierre Pronchery     if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX + 16, &outlen, ctr->KX,
242b077aed3SPierre Pronchery                           AES_BLOCK_SIZE)
243b077aed3SPierre Pronchery         || outlen != AES_BLOCK_SIZE)
244b077aed3SPierre Pronchery         return 0;
245b077aed3SPierre Pronchery     if (ctr->keylen != 16)
246b077aed3SPierre Pronchery         if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX + 32, &outlen,
247b077aed3SPierre Pronchery                               ctr->KX + 16, AES_BLOCK_SIZE)
248b077aed3SPierre Pronchery             || outlen != AES_BLOCK_SIZE)
249b077aed3SPierre Pronchery             return 0;
250b077aed3SPierre Pronchery     return 1;
251b077aed3SPierre Pronchery }
252b077aed3SPierre Pronchery 
253b077aed3SPierre Pronchery /*
254b077aed3SPierre Pronchery  * NB the no-df Update in SP800-90A specifies a constant input length
255b077aed3SPierre Pronchery  * of seedlen, however other uses of this algorithm pad the input with
256b077aed3SPierre Pronchery  * zeroes if necessary and have up to two parameters XORed together,
257b077aed3SPierre Pronchery  * so we handle both cases in this function instead.
258b077aed3SPierre Pronchery  */
ctr_update(PROV_DRBG * drbg,const unsigned char * in1,size_t in1len,const unsigned char * in2,size_t in2len,const unsigned char * nonce,size_t noncelen)259b077aed3SPierre Pronchery __owur static int ctr_update(PROV_DRBG *drbg,
260b077aed3SPierre Pronchery                              const unsigned char *in1, size_t in1len,
261b077aed3SPierre Pronchery                              const unsigned char *in2, size_t in2len,
262b077aed3SPierre Pronchery                              const unsigned char *nonce, size_t noncelen)
263b077aed3SPierre Pronchery {
264b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
265b077aed3SPierre Pronchery     int outlen = AES_BLOCK_SIZE;
266b077aed3SPierre Pronchery     unsigned char V_tmp[48], out[48];
267b077aed3SPierre Pronchery     unsigned char len;
268b077aed3SPierre Pronchery 
269b077aed3SPierre Pronchery     /* correct key is already set up. */
270b077aed3SPierre Pronchery     memcpy(V_tmp, ctr->V, 16);
271b077aed3SPierre Pronchery     inc_128(ctr);
272b077aed3SPierre Pronchery     memcpy(V_tmp + 16, ctr->V, 16);
273b077aed3SPierre Pronchery     if (ctr->keylen == 16) {
274b077aed3SPierre Pronchery         len = 32;
275b077aed3SPierre Pronchery     } else {
276b077aed3SPierre Pronchery         inc_128(ctr);
277b077aed3SPierre Pronchery         memcpy(V_tmp + 32, ctr->V, 16);
278b077aed3SPierre Pronchery         len = 48;
279b077aed3SPierre Pronchery     }
280b077aed3SPierre Pronchery     if (!EVP_CipherUpdate(ctr->ctx_ecb, out, &outlen, V_tmp, len)
281b077aed3SPierre Pronchery             || outlen != len)
282b077aed3SPierre Pronchery         return 0;
283b077aed3SPierre Pronchery     memcpy(ctr->K, out, ctr->keylen);
284b077aed3SPierre Pronchery     memcpy(ctr->V, out + ctr->keylen, 16);
285b077aed3SPierre Pronchery 
286b077aed3SPierre Pronchery     if (ctr->use_df) {
287b077aed3SPierre Pronchery         /* If no input reuse existing derived value */
288b077aed3SPierre Pronchery         if (in1 != NULL || nonce != NULL || in2 != NULL)
289b077aed3SPierre Pronchery             if (!ctr_df(ctr, in1, in1len, nonce, noncelen, in2, in2len))
290b077aed3SPierre Pronchery                 return 0;
291b077aed3SPierre Pronchery         /* If this a reuse input in1len != 0 */
292b077aed3SPierre Pronchery         if (in1len)
293b077aed3SPierre Pronchery             ctr_XOR(ctr, ctr->KX, drbg->seedlen);
294b077aed3SPierre Pronchery     } else {
295b077aed3SPierre Pronchery         ctr_XOR(ctr, in1, in1len);
296b077aed3SPierre Pronchery         ctr_XOR(ctr, in2, in2len);
297b077aed3SPierre Pronchery     }
298b077aed3SPierre Pronchery 
299b077aed3SPierre Pronchery     if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->K, NULL, -1)
300b077aed3SPierre Pronchery         || !EVP_CipherInit_ex(ctr->ctx_ctr, NULL, NULL, ctr->K, NULL, -1))
301b077aed3SPierre Pronchery         return 0;
302b077aed3SPierre Pronchery     return 1;
303b077aed3SPierre Pronchery }
304b077aed3SPierre Pronchery 
drbg_ctr_instantiate(PROV_DRBG * drbg,const unsigned char * entropy,size_t entropylen,const unsigned char * nonce,size_t noncelen,const unsigned char * pers,size_t perslen)305b077aed3SPierre Pronchery static int drbg_ctr_instantiate(PROV_DRBG *drbg,
306b077aed3SPierre Pronchery                                 const unsigned char *entropy, size_t entropylen,
307b077aed3SPierre Pronchery                                 const unsigned char *nonce, size_t noncelen,
308b077aed3SPierre Pronchery                                 const unsigned char *pers, size_t perslen)
309b077aed3SPierre Pronchery {
310b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
311b077aed3SPierre Pronchery 
312b077aed3SPierre Pronchery     if (entropy == NULL)
313b077aed3SPierre Pronchery         return 0;
314b077aed3SPierre Pronchery 
315b077aed3SPierre Pronchery     memset(ctr->K, 0, sizeof(ctr->K));
316b077aed3SPierre Pronchery     memset(ctr->V, 0, sizeof(ctr->V));
317b077aed3SPierre Pronchery     if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->K, NULL, -1))
318b077aed3SPierre Pronchery         return 0;
319b077aed3SPierre Pronchery 
320b077aed3SPierre Pronchery     inc_128(ctr);
321b077aed3SPierre Pronchery     if (!ctr_update(drbg, entropy, entropylen, pers, perslen, nonce, noncelen))
322b077aed3SPierre Pronchery         return 0;
323b077aed3SPierre Pronchery     return 1;
324b077aed3SPierre Pronchery }
325b077aed3SPierre Pronchery 
drbg_ctr_instantiate_wrapper(void * vdrbg,unsigned int strength,int prediction_resistance,const unsigned char * pstr,size_t pstr_len,const OSSL_PARAM params[])326b077aed3SPierre Pronchery static int drbg_ctr_instantiate_wrapper(void *vdrbg, unsigned int strength,
327b077aed3SPierre Pronchery                                         int prediction_resistance,
328b077aed3SPierre Pronchery                                         const unsigned char *pstr,
329b077aed3SPierre Pronchery                                         size_t pstr_len,
330b077aed3SPierre Pronchery                                         const OSSL_PARAM params[])
331b077aed3SPierre Pronchery {
332b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
333b077aed3SPierre Pronchery 
334b077aed3SPierre Pronchery     if (!ossl_prov_is_running() || !drbg_ctr_set_ctx_params(drbg, params))
335b077aed3SPierre Pronchery         return 0;
336b077aed3SPierre Pronchery     return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
337b077aed3SPierre Pronchery                                       pstr, pstr_len);
338b077aed3SPierre Pronchery }
339b077aed3SPierre Pronchery 
drbg_ctr_reseed(PROV_DRBG * drbg,const unsigned char * entropy,size_t entropylen,const unsigned char * adin,size_t adinlen)340b077aed3SPierre Pronchery static int drbg_ctr_reseed(PROV_DRBG *drbg,
341b077aed3SPierre Pronchery                            const unsigned char *entropy, size_t entropylen,
342b077aed3SPierre Pronchery                            const unsigned char *adin, size_t adinlen)
343b077aed3SPierre Pronchery {
344b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
345b077aed3SPierre Pronchery 
346b077aed3SPierre Pronchery     if (entropy == NULL)
347b077aed3SPierre Pronchery         return 0;
348b077aed3SPierre Pronchery 
349b077aed3SPierre Pronchery     inc_128(ctr);
350b077aed3SPierre Pronchery     if (!ctr_update(drbg, entropy, entropylen, adin, adinlen, NULL, 0))
351b077aed3SPierre Pronchery         return 0;
352b077aed3SPierre Pronchery     return 1;
353b077aed3SPierre Pronchery }
354b077aed3SPierre Pronchery 
drbg_ctr_reseed_wrapper(void * vdrbg,int prediction_resistance,const unsigned char * ent,size_t ent_len,const unsigned char * adin,size_t adin_len)355b077aed3SPierre Pronchery static int drbg_ctr_reseed_wrapper(void *vdrbg, int prediction_resistance,
356b077aed3SPierre Pronchery                                    const unsigned char *ent, size_t ent_len,
357b077aed3SPierre Pronchery                                    const unsigned char *adin, size_t adin_len)
358b077aed3SPierre Pronchery {
359b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
360b077aed3SPierre Pronchery 
361b077aed3SPierre Pronchery     return ossl_prov_drbg_reseed(drbg, prediction_resistance, ent, ent_len,
362b077aed3SPierre Pronchery                                  adin, adin_len);
363b077aed3SPierre Pronchery }
364b077aed3SPierre Pronchery 
ctr96_inc(unsigned char * counter)365b077aed3SPierre Pronchery static void ctr96_inc(unsigned char *counter)
366b077aed3SPierre Pronchery {
367b077aed3SPierre Pronchery     u32 n = 12, c = 1;
368b077aed3SPierre Pronchery 
369b077aed3SPierre Pronchery     do {
370b077aed3SPierre Pronchery         --n;
371b077aed3SPierre Pronchery         c += counter[n];
372b077aed3SPierre Pronchery         counter[n] = (u8)c;
373b077aed3SPierre Pronchery         c >>= 8;
374b077aed3SPierre Pronchery     } while (n);
375b077aed3SPierre Pronchery }
376b077aed3SPierre Pronchery 
drbg_ctr_generate(PROV_DRBG * drbg,unsigned char * out,size_t outlen,const unsigned char * adin,size_t adinlen)377b077aed3SPierre Pronchery static int drbg_ctr_generate(PROV_DRBG *drbg,
378b077aed3SPierre Pronchery                              unsigned char *out, size_t outlen,
379b077aed3SPierre Pronchery                              const unsigned char *adin, size_t adinlen)
380b077aed3SPierre Pronchery {
381b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
382b077aed3SPierre Pronchery     unsigned int ctr32, blocks;
383b077aed3SPierre Pronchery     int outl, buflen;
384b077aed3SPierre Pronchery 
385b077aed3SPierre Pronchery     if (adin != NULL && adinlen != 0) {
386b077aed3SPierre Pronchery         inc_128(ctr);
387b077aed3SPierre Pronchery 
388b077aed3SPierre Pronchery         if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0))
389b077aed3SPierre Pronchery             return 0;
390b077aed3SPierre Pronchery         /* This means we reuse derived value */
391b077aed3SPierre Pronchery         if (ctr->use_df) {
392b077aed3SPierre Pronchery             adin = NULL;
393b077aed3SPierre Pronchery             adinlen = 1;
394b077aed3SPierre Pronchery         }
395b077aed3SPierre Pronchery     } else {
396b077aed3SPierre Pronchery         adinlen = 0;
397b077aed3SPierre Pronchery     }
398b077aed3SPierre Pronchery 
399b077aed3SPierre Pronchery     inc_128(ctr);
400b077aed3SPierre Pronchery 
401b077aed3SPierre Pronchery     if (outlen == 0) {
402b077aed3SPierre Pronchery         inc_128(ctr);
403b077aed3SPierre Pronchery 
404b077aed3SPierre Pronchery         if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0))
405b077aed3SPierre Pronchery             return 0;
406b077aed3SPierre Pronchery         return 1;
407b077aed3SPierre Pronchery     }
408b077aed3SPierre Pronchery 
409b077aed3SPierre Pronchery     memset(out, 0, outlen);
410b077aed3SPierre Pronchery 
411b077aed3SPierre Pronchery     do {
412b077aed3SPierre Pronchery         if (!EVP_CipherInit_ex(ctr->ctx_ctr,
413b077aed3SPierre Pronchery                                NULL, NULL, NULL, ctr->V, -1))
414b077aed3SPierre Pronchery             return 0;
415b077aed3SPierre Pronchery 
416b077aed3SPierre Pronchery         /*-
417b077aed3SPierre Pronchery          * outlen has type size_t while EVP_CipherUpdate takes an
418b077aed3SPierre Pronchery          * int argument and thus cannot be guaranteed to process more
419b077aed3SPierre Pronchery          * than 2^31-1 bytes at a time. We process such huge generate
420b077aed3SPierre Pronchery          * requests in 2^30 byte chunks, which is the greatest multiple
421b077aed3SPierre Pronchery          * of AES block size lower than or equal to 2^31-1.
422b077aed3SPierre Pronchery          */
423b077aed3SPierre Pronchery         buflen = outlen > (1U << 30) ? (1U << 30) : outlen;
424b077aed3SPierre Pronchery         blocks = (buflen + 15) / 16;
425b077aed3SPierre Pronchery 
426b077aed3SPierre Pronchery         ctr32 = GETU32(ctr->V + 12) + blocks;
427b077aed3SPierre Pronchery         if (ctr32 < blocks) {
428b077aed3SPierre Pronchery             /* 32-bit counter overflow into V. */
429b077aed3SPierre Pronchery             if (ctr32 != 0) {
430b077aed3SPierre Pronchery                 blocks -= ctr32;
431b077aed3SPierre Pronchery                 buflen = blocks * 16;
432b077aed3SPierre Pronchery                 ctr32 = 0;
433b077aed3SPierre Pronchery             }
434b077aed3SPierre Pronchery             ctr96_inc(ctr->V);
435b077aed3SPierre Pronchery         }
436b077aed3SPierre Pronchery         PUTU32(ctr->V + 12, ctr32);
437b077aed3SPierre Pronchery 
438b077aed3SPierre Pronchery         if (!EVP_CipherUpdate(ctr->ctx_ctr, out, &outl, out, buflen)
439b077aed3SPierre Pronchery             || outl != buflen)
440b077aed3SPierre Pronchery             return 0;
441b077aed3SPierre Pronchery 
442b077aed3SPierre Pronchery         out += buflen;
443b077aed3SPierre Pronchery         outlen -= buflen;
444b077aed3SPierre Pronchery     } while (outlen);
445b077aed3SPierre Pronchery 
446b077aed3SPierre Pronchery     if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0))
447b077aed3SPierre Pronchery         return 0;
448b077aed3SPierre Pronchery     return 1;
449b077aed3SPierre Pronchery }
450b077aed3SPierre Pronchery 
drbg_ctr_generate_wrapper(void * vdrbg,unsigned char * out,size_t outlen,unsigned int strength,int prediction_resistance,const unsigned char * adin,size_t adin_len)451b077aed3SPierre Pronchery static int drbg_ctr_generate_wrapper
452b077aed3SPierre Pronchery     (void *vdrbg, unsigned char *out, size_t outlen,
453b077aed3SPierre Pronchery      unsigned int strength, int prediction_resistance,
454b077aed3SPierre Pronchery      const unsigned char *adin, size_t adin_len)
455b077aed3SPierre Pronchery {
456b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
457b077aed3SPierre Pronchery 
458b077aed3SPierre Pronchery     return ossl_prov_drbg_generate(drbg, out, outlen, strength,
459b077aed3SPierre Pronchery                                    prediction_resistance, adin, adin_len);
460b077aed3SPierre Pronchery }
461b077aed3SPierre Pronchery 
drbg_ctr_uninstantiate(PROV_DRBG * drbg)462b077aed3SPierre Pronchery static int drbg_ctr_uninstantiate(PROV_DRBG *drbg)
463b077aed3SPierre Pronchery {
464b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
465b077aed3SPierre Pronchery 
466b077aed3SPierre Pronchery     OPENSSL_cleanse(ctr->K, sizeof(ctr->K));
467b077aed3SPierre Pronchery     OPENSSL_cleanse(ctr->V, sizeof(ctr->V));
468b077aed3SPierre Pronchery     OPENSSL_cleanse(ctr->bltmp, sizeof(ctr->bltmp));
469b077aed3SPierre Pronchery     OPENSSL_cleanse(ctr->KX, sizeof(ctr->KX));
470b077aed3SPierre Pronchery     ctr->bltmp_pos = 0;
471b077aed3SPierre Pronchery     return ossl_prov_drbg_uninstantiate(drbg);
472b077aed3SPierre Pronchery }
473b077aed3SPierre Pronchery 
drbg_ctr_uninstantiate_wrapper(void * vdrbg)474b077aed3SPierre Pronchery static int drbg_ctr_uninstantiate_wrapper(void *vdrbg)
475b077aed3SPierre Pronchery {
476b077aed3SPierre Pronchery     return drbg_ctr_uninstantiate((PROV_DRBG *)vdrbg);
477b077aed3SPierre Pronchery }
478b077aed3SPierre Pronchery 
drbg_ctr_verify_zeroization(void * vdrbg)479b077aed3SPierre Pronchery static int drbg_ctr_verify_zeroization(void *vdrbg)
480b077aed3SPierre Pronchery {
481b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
482b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
483b077aed3SPierre Pronchery 
484b077aed3SPierre Pronchery     PROV_DRBG_VERYIFY_ZEROIZATION(ctr->K);
485b077aed3SPierre Pronchery     PROV_DRBG_VERYIFY_ZEROIZATION(ctr->V);
486b077aed3SPierre Pronchery     PROV_DRBG_VERYIFY_ZEROIZATION(ctr->bltmp);
487b077aed3SPierre Pronchery     PROV_DRBG_VERYIFY_ZEROIZATION(ctr->KX);
488b077aed3SPierre Pronchery     if (ctr->bltmp_pos != 0)
489b077aed3SPierre Pronchery         return 0;
490b077aed3SPierre Pronchery     return 1;
491b077aed3SPierre Pronchery }
492b077aed3SPierre Pronchery 
drbg_ctr_init_lengths(PROV_DRBG * drbg)493b077aed3SPierre Pronchery static int drbg_ctr_init_lengths(PROV_DRBG *drbg)
494b077aed3SPierre Pronchery {
495b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
496b077aed3SPierre Pronchery     int res = 1;
497b077aed3SPierre Pronchery 
498b077aed3SPierre Pronchery     /* Maximum number of bits per request = 2^19  = 2^16 bytes */
499b077aed3SPierre Pronchery     drbg->max_request = 1 << 16;
500b077aed3SPierre Pronchery     if (ctr->use_df) {
501b077aed3SPierre Pronchery         drbg->min_entropylen = 0;
502b077aed3SPierre Pronchery         drbg->max_entropylen = DRBG_MAX_LENGTH;
503b077aed3SPierre Pronchery         drbg->min_noncelen = 0;
504b077aed3SPierre Pronchery         drbg->max_noncelen = DRBG_MAX_LENGTH;
505b077aed3SPierre Pronchery         drbg->max_perslen = DRBG_MAX_LENGTH;
506b077aed3SPierre Pronchery         drbg->max_adinlen = DRBG_MAX_LENGTH;
507b077aed3SPierre Pronchery 
508b077aed3SPierre Pronchery         if (ctr->keylen > 0) {
509b077aed3SPierre Pronchery             drbg->min_entropylen = ctr->keylen;
510b077aed3SPierre Pronchery             drbg->min_noncelen = drbg->min_entropylen / 2;
511b077aed3SPierre Pronchery         }
512b077aed3SPierre Pronchery     } else {
513b077aed3SPierre Pronchery         const size_t len = ctr->keylen > 0 ? drbg->seedlen : DRBG_MAX_LENGTH;
514b077aed3SPierre Pronchery 
515b077aed3SPierre Pronchery         drbg->min_entropylen = len;
516b077aed3SPierre Pronchery         drbg->max_entropylen = len;
517b077aed3SPierre Pronchery         /* Nonce not used */
518b077aed3SPierre Pronchery         drbg->min_noncelen = 0;
519b077aed3SPierre Pronchery         drbg->max_noncelen = 0;
520b077aed3SPierre Pronchery         drbg->max_perslen = len;
521b077aed3SPierre Pronchery         drbg->max_adinlen = len;
522b077aed3SPierre Pronchery     }
523b077aed3SPierre Pronchery     return res;
524b077aed3SPierre Pronchery }
525b077aed3SPierre Pronchery 
drbg_ctr_init(PROV_DRBG * drbg)526b077aed3SPierre Pronchery static int drbg_ctr_init(PROV_DRBG *drbg)
527b077aed3SPierre Pronchery {
528b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
529b077aed3SPierre Pronchery     size_t keylen;
530b077aed3SPierre Pronchery 
531b077aed3SPierre Pronchery     if (ctr->cipher_ctr == NULL) {
532b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
533b077aed3SPierre Pronchery         return 0;
534b077aed3SPierre Pronchery     }
535b077aed3SPierre Pronchery     ctr->keylen = keylen = EVP_CIPHER_get_key_length(ctr->cipher_ctr);
536b077aed3SPierre Pronchery     if (ctr->ctx_ecb == NULL)
537b077aed3SPierre Pronchery         ctr->ctx_ecb = EVP_CIPHER_CTX_new();
538b077aed3SPierre Pronchery     if (ctr->ctx_ctr == NULL)
539b077aed3SPierre Pronchery         ctr->ctx_ctr = EVP_CIPHER_CTX_new();
540b077aed3SPierre Pronchery     if (ctr->ctx_ecb == NULL || ctr->ctx_ctr == NULL) {
541b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
542b077aed3SPierre Pronchery         goto err;
543b077aed3SPierre Pronchery     }
544b077aed3SPierre Pronchery 
545b077aed3SPierre Pronchery     if (!EVP_CipherInit_ex(ctr->ctx_ecb,
546b077aed3SPierre Pronchery                            ctr->cipher_ecb, NULL, NULL, NULL, 1)
547b077aed3SPierre Pronchery         || !EVP_CipherInit_ex(ctr->ctx_ctr,
548b077aed3SPierre Pronchery                               ctr->cipher_ctr, NULL, NULL, NULL, 1)) {
549b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS);
550b077aed3SPierre Pronchery         goto err;
551b077aed3SPierre Pronchery     }
552b077aed3SPierre Pronchery 
553b077aed3SPierre Pronchery     drbg->strength = keylen * 8;
554b077aed3SPierre Pronchery     drbg->seedlen = keylen + 16;
555b077aed3SPierre Pronchery 
556b077aed3SPierre Pronchery     if (ctr->use_df) {
557b077aed3SPierre Pronchery         /* df initialisation */
558b077aed3SPierre Pronchery         static const unsigned char df_key[32] = {
559b077aed3SPierre Pronchery             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
560b077aed3SPierre Pronchery             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
561b077aed3SPierre Pronchery             0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
562b077aed3SPierre Pronchery             0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
563b077aed3SPierre Pronchery         };
564b077aed3SPierre Pronchery 
565b077aed3SPierre Pronchery         if (ctr->ctx_df == NULL)
566b077aed3SPierre Pronchery             ctr->ctx_df = EVP_CIPHER_CTX_new();
567b077aed3SPierre Pronchery         if (ctr->ctx_df == NULL) {
568b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
569b077aed3SPierre Pronchery             goto err;
570b077aed3SPierre Pronchery         }
571b077aed3SPierre Pronchery         /* Set key schedule for df_key */
572b077aed3SPierre Pronchery         if (!EVP_CipherInit_ex(ctr->ctx_df,
573b077aed3SPierre Pronchery                                ctr->cipher_ecb, NULL, df_key, NULL, 1)) {
574b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED);
575b077aed3SPierre Pronchery             goto err;
576b077aed3SPierre Pronchery         }
577b077aed3SPierre Pronchery     }
578b077aed3SPierre Pronchery     return drbg_ctr_init_lengths(drbg);
579b077aed3SPierre Pronchery 
580b077aed3SPierre Pronchery err:
581b077aed3SPierre Pronchery     EVP_CIPHER_CTX_free(ctr->ctx_ecb);
582b077aed3SPierre Pronchery     EVP_CIPHER_CTX_free(ctr->ctx_ctr);
583b077aed3SPierre Pronchery     ctr->ctx_ecb = ctr->ctx_ctr = NULL;
584b077aed3SPierre Pronchery     return 0;
585b077aed3SPierre Pronchery }
586b077aed3SPierre Pronchery 
drbg_ctr_new(PROV_DRBG * drbg)587b077aed3SPierre Pronchery static int drbg_ctr_new(PROV_DRBG *drbg)
588b077aed3SPierre Pronchery {
589b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr;
590b077aed3SPierre Pronchery 
591b077aed3SPierre Pronchery     ctr = OPENSSL_secure_zalloc(sizeof(*ctr));
592b077aed3SPierre Pronchery     if (ctr == NULL) {
593b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
594b077aed3SPierre Pronchery         return 0;
595b077aed3SPierre Pronchery     }
596b077aed3SPierre Pronchery 
597b077aed3SPierre Pronchery     ctr->use_df = 1;
598b077aed3SPierre Pronchery     drbg->data = ctr;
599b077aed3SPierre Pronchery     return drbg_ctr_init_lengths(drbg);
600b077aed3SPierre Pronchery }
601b077aed3SPierre Pronchery 
drbg_ctr_new_wrapper(void * provctx,void * parent,const OSSL_DISPATCH * parent_dispatch)602b077aed3SPierre Pronchery static void *drbg_ctr_new_wrapper(void *provctx, void *parent,
603b077aed3SPierre Pronchery                                    const OSSL_DISPATCH *parent_dispatch)
604b077aed3SPierre Pronchery {
605*44096ebdSEnji Cooper     return ossl_rand_drbg_new(provctx, parent, parent_dispatch,
606*44096ebdSEnji Cooper                               &drbg_ctr_new, &drbg_ctr_free,
607b077aed3SPierre Pronchery                               &drbg_ctr_instantiate, &drbg_ctr_uninstantiate,
608b077aed3SPierre Pronchery                               &drbg_ctr_reseed, &drbg_ctr_generate);
609b077aed3SPierre Pronchery }
610b077aed3SPierre Pronchery 
drbg_ctr_free(void * vdrbg)611b077aed3SPierre Pronchery static void drbg_ctr_free(void *vdrbg)
612b077aed3SPierre Pronchery {
613b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
614b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr;
615b077aed3SPierre Pronchery 
616b077aed3SPierre Pronchery     if (drbg != NULL && (ctr = (PROV_DRBG_CTR *)drbg->data) != NULL) {
617b077aed3SPierre Pronchery         EVP_CIPHER_CTX_free(ctr->ctx_ecb);
618b077aed3SPierre Pronchery         EVP_CIPHER_CTX_free(ctr->ctx_ctr);
619b077aed3SPierre Pronchery         EVP_CIPHER_CTX_free(ctr->ctx_df);
620b077aed3SPierre Pronchery         EVP_CIPHER_free(ctr->cipher_ecb);
621b077aed3SPierre Pronchery         EVP_CIPHER_free(ctr->cipher_ctr);
622b077aed3SPierre Pronchery 
623b077aed3SPierre Pronchery         OPENSSL_secure_clear_free(ctr, sizeof(*ctr));
624b077aed3SPierre Pronchery     }
625b077aed3SPierre Pronchery     ossl_rand_drbg_free(drbg);
626b077aed3SPierre Pronchery }
627b077aed3SPierre Pronchery 
drbg_ctr_get_ctx_params(void * vdrbg,OSSL_PARAM params[])628b077aed3SPierre Pronchery static int drbg_ctr_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
629b077aed3SPierre Pronchery {
630b077aed3SPierre Pronchery     PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
631b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
632b077aed3SPierre Pronchery     OSSL_PARAM *p;
633b077aed3SPierre Pronchery 
634b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_USE_DF);
635b077aed3SPierre Pronchery     if (p != NULL && !OSSL_PARAM_set_int(p, ctr->use_df))
636b077aed3SPierre Pronchery         return 0;
637b077aed3SPierre Pronchery 
638b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_CIPHER);
639b077aed3SPierre Pronchery     if (p != NULL) {
640b077aed3SPierre Pronchery         if (ctr->cipher_ctr == NULL
641b077aed3SPierre Pronchery             || !OSSL_PARAM_set_utf8_string(p,
642b077aed3SPierre Pronchery                                            EVP_CIPHER_get0_name(ctr->cipher_ctr)))
643b077aed3SPierre Pronchery             return 0;
644b077aed3SPierre Pronchery     }
645b077aed3SPierre Pronchery 
646b077aed3SPierre Pronchery     return ossl_drbg_get_ctx_params(drbg, params);
647b077aed3SPierre Pronchery }
648b077aed3SPierre Pronchery 
drbg_ctr_gettable_ctx_params(ossl_unused void * vctx,ossl_unused void * provctx)649b077aed3SPierre Pronchery static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(ossl_unused void *vctx,
650b077aed3SPierre Pronchery                                                       ossl_unused void *provctx)
651b077aed3SPierre Pronchery {
652b077aed3SPierre Pronchery     static const OSSL_PARAM known_gettable_ctx_params[] = {
653b077aed3SPierre Pronchery         OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0),
654b077aed3SPierre Pronchery         OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL),
655b077aed3SPierre Pronchery         OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON,
656b077aed3SPierre Pronchery         OSSL_PARAM_END
657b077aed3SPierre Pronchery     };
658b077aed3SPierre Pronchery     return known_gettable_ctx_params;
659b077aed3SPierre Pronchery }
660b077aed3SPierre Pronchery 
drbg_ctr_set_ctx_params(void * vctx,const OSSL_PARAM params[])661b077aed3SPierre Pronchery static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[])
662b077aed3SPierre Pronchery {
663b077aed3SPierre Pronchery     PROV_DRBG *ctx = (PROV_DRBG *)vctx;
664b077aed3SPierre Pronchery     PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data;
665b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
666b077aed3SPierre Pronchery     const OSSL_PARAM *p;
667b077aed3SPierre Pronchery     char *ecb;
668b077aed3SPierre Pronchery     const char *propquery = NULL;
669b077aed3SPierre Pronchery     int i, cipher_init = 0;
670b077aed3SPierre Pronchery 
671b077aed3SPierre Pronchery     if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_USE_DF)) != NULL
672b077aed3SPierre Pronchery             && OSSL_PARAM_get_int(p, &i)) {
673b077aed3SPierre Pronchery         /* FIPS errors out in the drbg_ctr_init() call later */
674b077aed3SPierre Pronchery         ctr->use_df = i != 0;
675b077aed3SPierre Pronchery         cipher_init = 1;
676b077aed3SPierre Pronchery     }
677b077aed3SPierre Pronchery 
678b077aed3SPierre Pronchery     if ((p = OSSL_PARAM_locate_const(params,
679b077aed3SPierre Pronchery                                      OSSL_DRBG_PARAM_PROPERTIES)) != NULL) {
680b077aed3SPierre Pronchery         if (p->data_type != OSSL_PARAM_UTF8_STRING)
681b077aed3SPierre Pronchery             return 0;
682b077aed3SPierre Pronchery         propquery = (const char *)p->data;
683b077aed3SPierre Pronchery     }
684b077aed3SPierre Pronchery 
685b077aed3SPierre Pronchery     if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) {
686b077aed3SPierre Pronchery         const char *base = (const char *)p->data;
687b077aed3SPierre Pronchery         size_t ctr_str_len = sizeof("CTR") - 1;
688b077aed3SPierre Pronchery         size_t ecb_str_len = sizeof("ECB") - 1;
689b077aed3SPierre Pronchery 
690b077aed3SPierre Pronchery         if (p->data_type != OSSL_PARAM_UTF8_STRING
691b077aed3SPierre Pronchery                 || p->data_size < ctr_str_len)
692b077aed3SPierre Pronchery             return 0;
693b077aed3SPierre Pronchery         if (OPENSSL_strcasecmp("CTR", base + p->data_size - ctr_str_len) != 0) {
694b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER);
695b077aed3SPierre Pronchery             return 0;
696b077aed3SPierre Pronchery         }
697b077aed3SPierre Pronchery         if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) {
698b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
699b077aed3SPierre Pronchery             return 0;
700b077aed3SPierre Pronchery         }
701b077aed3SPierre Pronchery         strcpy(ecb + p->data_size - ecb_str_len, "ECB");
702b077aed3SPierre Pronchery         EVP_CIPHER_free(ctr->cipher_ecb);
703b077aed3SPierre Pronchery         EVP_CIPHER_free(ctr->cipher_ctr);
704b077aed3SPierre Pronchery         ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery);
705b077aed3SPierre Pronchery         ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery);
706b077aed3SPierre Pronchery         OPENSSL_free(ecb);
707b077aed3SPierre Pronchery         if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) {
708b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS);
709b077aed3SPierre Pronchery             return 0;
710b077aed3SPierre Pronchery         }
711b077aed3SPierre Pronchery         cipher_init = 1;
712b077aed3SPierre Pronchery     }
713b077aed3SPierre Pronchery 
714b077aed3SPierre Pronchery     if (cipher_init && !drbg_ctr_init(ctx))
715b077aed3SPierre Pronchery         return 0;
716b077aed3SPierre Pronchery 
717b077aed3SPierre Pronchery     return ossl_drbg_set_ctx_params(ctx, params);
718b077aed3SPierre Pronchery }
719b077aed3SPierre Pronchery 
drbg_ctr_settable_ctx_params(ossl_unused void * vctx,ossl_unused void * provctx)720b077aed3SPierre Pronchery static const OSSL_PARAM *drbg_ctr_settable_ctx_params(ossl_unused void *vctx,
721b077aed3SPierre Pronchery                                                       ossl_unused void *provctx)
722b077aed3SPierre Pronchery {
723b077aed3SPierre Pronchery     static const OSSL_PARAM known_settable_ctx_params[] = {
724b077aed3SPierre Pronchery         OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0),
725b077aed3SPierre Pronchery         OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0),
726b077aed3SPierre Pronchery         OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL),
727b077aed3SPierre Pronchery         OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON,
728b077aed3SPierre Pronchery         OSSL_PARAM_END
729b077aed3SPierre Pronchery     };
730b077aed3SPierre Pronchery     return known_settable_ctx_params;
731b077aed3SPierre Pronchery }
732b077aed3SPierre Pronchery 
733b077aed3SPierre Pronchery const OSSL_DISPATCH ossl_drbg_ctr_functions[] = {
734b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_ctr_new_wrapper },
735b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_ctr_free },
736b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_INSTANTIATE,
737b077aed3SPierre Pronchery       (void(*)(void))drbg_ctr_instantiate_wrapper },
738b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_UNINSTANTIATE,
739b077aed3SPierre Pronchery       (void(*)(void))drbg_ctr_uninstantiate_wrapper },
740b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_ctr_generate_wrapper },
741b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_ctr_reseed_wrapper },
742b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking },
743b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock },
744b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock },
745b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS,
746b077aed3SPierre Pronchery       (void(*)(void))drbg_ctr_settable_ctx_params },
747b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params },
748b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
749b077aed3SPierre Pronchery       (void(*)(void))drbg_ctr_gettable_ctx_params },
750b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params },
751b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
752b077aed3SPierre Pronchery       (void(*)(void))drbg_ctr_verify_zeroization },
753b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed },
754b077aed3SPierre Pronchery     { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed },
755b077aed3SPierre Pronchery     { 0, NULL }
756b077aed3SPierre Pronchery };
757