1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_CRYPTO_DRBG_HASH
18
19 #include <stdlib.h>
20 #include <securec.h>
21 #include "crypt_errno.h"
22 #include "crypt_local_types.h"
23 #include "crypt_utils.h"
24 #include "bsl_sal.h"
25 #include "crypt_types.h"
26 #include "bsl_err_internal.h"
27 #include "drbg_local.h"
28
29 #define DRBG_HASH_MAX_SEEDLEN (111)
30
31 typedef enum {
32 DRBG_SHA1MDSIZE = 20,
33 DRBG_SHA224MDSIZE = 28,
34 DRBG_SHA256MDSIZE = 32,
35 DRBG_SHA384MDSIZE = 48,
36 DRBG_SHA512MDSIZE = 64,
37 DRBG_SM3MDSIZE = 32,
38 } DRBG_MdSize;
39
40 typedef struct {
41 uint8_t v[DRBG_HASH_MAX_SEEDLEN];
42 uint8_t c[DRBG_HASH_MAX_SEEDLEN];
43 uint32_t seedLen;
44 const EAL_MdMethod *md;
45 void *mdCtx;
46 } DRBG_HashCtx;
47
48 // This function performs the ctx->V += xxx operation.
DRBG_HashAddV(uint8_t * v,uint32_t vLen,uint8_t * src,uint32_t srcLen)49 static void DRBG_HashAddV(uint8_t *v, uint32_t vLen, uint8_t *src, uint32_t srcLen)
50 {
51 uint8_t *d = v + vLen - 1;
52 uint8_t *s = src + srcLen - 1;
53 uint8_t c = 0;
54 uint32_t r;
55
56 while (s >= src) {
57 r = (uint32_t)(*d) + (*s) + c;
58 *d = (uint8_t)(r & 0xff);
59 c = (r > 0xff) ? 1 : 0;
60 d--;
61 s--;
62 }
63
64 while (d >= v && c > 0) {
65 r = (uint32_t)(*d) + c;
66 *d = (uint8_t)(r & 0xff);
67 c = (r > 0xff) ? 1 : 0;
68 d--;
69 }
70 return;
71 }
72
DRBG_UpdateDataInHashDf(DRBG_HashCtx * ctx,const CRYPT_Data * in1,const CRYPT_Data * in2,const CRYPT_Data * in3,const CRYPT_Data * in4)73 static int32_t DRBG_UpdateDataInHashDf(DRBG_HashCtx *ctx,
74 const CRYPT_Data *in1, const CRYPT_Data *in2,
75 const CRYPT_Data *in3, const CRYPT_Data *in4)
76 {
77 const EAL_MdMethod *meth = ctx->md;
78 void *mdCtx = ctx->mdCtx;
79 int32_t ret = CRYPT_SUCCESS;
80
81 if (!CRYPT_IsDataNull(in1)) {
82 ret = meth->update(mdCtx, in1->data, in1->len);
83 if (ret != CRYPT_SUCCESS) {
84 BSL_ERR_PUSH_ERROR(ret);
85 return ret;
86 }
87 }
88
89 if (!CRYPT_IsDataNull(in2)) {
90 ret = meth->update(mdCtx, in2->data, in2->len);
91 if (ret != CRYPT_SUCCESS) {
92 BSL_ERR_PUSH_ERROR(ret);
93 return ret;
94 }
95 }
96
97 if (!CRYPT_IsDataNull(in3)) {
98 ret = meth->update(mdCtx, in3->data, in3->len);
99 if (ret != CRYPT_SUCCESS) {
100 BSL_ERR_PUSH_ERROR(ret);
101 return ret;
102 }
103 }
104
105 if (!CRYPT_IsDataNull(in4)) {
106 ret = meth->update(mdCtx, in4->data, in4->len);
107 if (ret != CRYPT_SUCCESS) {
108 BSL_ERR_PUSH_ERROR(ret);
109 }
110 }
111
112 return ret;
113 }
114
DRBG_HashDfValuesAssig(uint8_t values[5],uint32_t len)115 static void DRBG_HashDfValuesAssig(uint8_t values[5], uint32_t len)
116 {
117 // The value of values is the same as that of counter || no_of_bits_to_return in Hash_df Process
118 // in section 10.3.1 in NIST 800-90a.
119 values[0] = 0x1;
120 // len is shifted leftward by 3, then byte-to-bit. Shift rightwards by 24 bits to get the highest 8 bits.
121 values[1] = (uint8_t)(((len << 3) >> 24) & 0xff);
122 // 2nd, len is shifted leftward by 3, then byte-to-bit. Shift rightwards by 16 bits to get the second 8 bits.
123 values[2] = (uint8_t)(((len << 3) >> 16) & 0xff);
124 // 3rd, len is shifted leftward by 3, then byte-to-bit. Shift rightwards by 8 bits to get the third 8 bits.
125 values[3] = (uint8_t)(((len << 3) >> 8) & 0xff);
126 values[4] = (uint8_t)((len << 3) & 0xff); // 4th, len is shifted leftward by 3, then byte-to-bit.
127 }
128
DRBG_HashDf(DRBG_HashCtx * ctx,uint8_t * out,uint32_t outLen,const CRYPT_Data * in1,const CRYPT_Data * in2,const CRYPT_Data * in3,const CRYPT_Data * in4)129 static int32_t DRBG_HashDf(DRBG_HashCtx *ctx, uint8_t *out, uint32_t outLen, const CRYPT_Data *in1,
130 const CRYPT_Data *in2, const CRYPT_Data *in3, const CRYPT_Data *in4)
131 {
132 const EAL_MdMethod *meth = ctx->md;
133 void *mdCtx = ctx->mdCtx;
134 uint32_t mdSize = meth->mdSize;
135 uint8_t *buf = out;
136 uint32_t len = outLen;
137 int32_t ret;
138 // The temp is the same as that of counter || no_of_bits_to_return in Hash_df Process
139 // in section 10.3.1 in NIST 800-90a.
140 uint8_t temp[5];
141 // len = floor(no_of_bits_to_return / outlen)
142 DRBG_HashDfValuesAssig(temp, len);
143
144 do {
145 // temp = temp || Hash (counter || no_of_bits_to_return || input_string).
146 if ((ret = meth->init(mdCtx, NULL)) != CRYPT_SUCCESS) {
147 BSL_ERR_PUSH_ERROR(ret);
148 return ret;
149 }
150
151 // 5 indicates the maximum length of temp. For details, see the temp statement.
152 if ((ret = meth->update(mdCtx, temp, 5)) != CRYPT_SUCCESS) {
153 BSL_ERR_PUSH_ERROR(ret);
154 goto EXIT;
155 }
156
157 if ((ret = DRBG_UpdateDataInHashDf(ctx, in1, in2, in3, in4)) != CRYPT_SUCCESS) {
158 BSL_ERR_PUSH_ERROR(ret);
159 goto EXIT;
160 }
161
162 uint8_t tmpOut[DRBG_HASH_MAX_MDSIZE];
163 uint32_t tmpOutLen = DRBG_HASH_MAX_MDSIZE;
164 if (len < mdSize) {
165 if ((ret = meth->final(mdCtx, tmpOut, &tmpOutLen)) != CRYPT_SUCCESS) {
166 BSL_ERR_PUSH_ERROR(ret);
167 goto EXIT;
168 }
169 // tmpOutLen is the maximum supported MD length,
170 // and len is the actual length, which must be smaller than tmpOutLen.
171 // Only the len length needs to be truncated as the output.
172 (void)memcpy_s(buf, len, tmpOut, len);
173 break;
174 }
175 if ((ret = meth->final(mdCtx, buf, &tmpOutLen)) != CRYPT_SUCCESS) {
176 BSL_ERR_PUSH_ERROR(ret);
177 goto EXIT;
178 }
179
180 buf += mdSize;
181 len -= mdSize;
182 temp[0]++;
183 } while (len > 0);
184
185 EXIT:
186 meth->deinit(mdCtx);
187 return ret;
188 }
189
DRBG_Hashgen(DRBG_HashCtx * ctx,uint8_t * out,uint32_t outLen)190 static int32_t DRBG_Hashgen(DRBG_HashCtx *ctx, uint8_t *out, uint32_t outLen)
191 {
192 uint8_t data[DRBG_HASH_MAX_SEEDLEN];
193 const EAL_MdMethod *md = ctx->md;
194 void *mdCtx = ctx->mdCtx;
195 int32_t ret = CRYPT_SUCCESS;
196 uint32_t mdSize = md->mdSize;
197 uint32_t tmpLen = mdSize;
198 uint32_t len = outLen;
199 uint8_t *buf = out;
200
201 // The length of the V array is the longest seedLen. Therefore, there is no failure.
202 (void)memcpy_s(data, sizeof(data), ctx->v, ctx->seedLen);
203
204 while (len > 0) {
205 uint8_t n = 1;
206 if ((ret = md->init(mdCtx, NULL)) != CRYPT_SUCCESS) {
207 BSL_ERR_PUSH_ERROR(ret);
208 return ret;
209 }
210
211 if ((ret = md->update(mdCtx, data, ctx->seedLen)) != CRYPT_SUCCESS) {
212 BSL_ERR_PUSH_ERROR(ret);
213 goto EXIT;
214 }
215
216 if (len >= mdSize) {
217 if ((ret = md->final(mdCtx, buf, &tmpLen)) != CRYPT_SUCCESS) {
218 BSL_ERR_PUSH_ERROR(ret);
219 goto EXIT;
220 }
221 } else {
222 uint8_t temp[DRBG_HASH_MAX_SEEDLEN];
223 uint32_t tempLen = DRBG_HASH_MAX_SEEDLEN;
224 if ((ret = md->final(mdCtx, temp, &tempLen)) != CRYPT_SUCCESS) {
225 BSL_ERR_PUSH_ERROR(ret);
226 goto EXIT;
227 }
228
229 (void)memcpy_s(buf, len, temp, len);
230 break;
231 }
232 buf += mdSize;
233 len -= mdSize;
234
235 DRBG_HashAddV(data, ctx->seedLen, &n, 1);
236 }
237
238 EXIT:
239 // Clear MD data.
240 md->deinit(mdCtx);
241 return ret;
242 }
243
DRBG_HashInstantiate(DRBG_Ctx * drbg,const CRYPT_Data * entropy,const CRYPT_Data * nonce,const CRYPT_Data * pers)244 int32_t DRBG_HashInstantiate(DRBG_Ctx *drbg, const CRYPT_Data *entropy,
245 const CRYPT_Data *nonce, const CRYPT_Data *pers)
246 {
247 DRBG_HashCtx *ctx = (DRBG_HashCtx*)drbg->ctx;
248 CRYPT_Data seed = {ctx->v, (uint32_t)(ctx->seedLen)};
249 int32_t ret;
250 uint8_t c = 0;
251 CRYPT_Data temp = {&c, 1};
252
253 /**
254 1. seed_material = entropy || nonce || pers
255 2. seed = Hash_df(seed_material)
256 3. V = seed
257 4. C = Hash_df(0x00 || V)
258 */
259 ret = DRBG_HashDf(ctx, ctx->v, ctx->seedLen, entropy, nonce, pers, NULL);
260 if (ret != CRYPT_SUCCESS) {
261 BSL_ERR_PUSH_ERROR(ret);
262 return ret;
263 }
264
265 ret = DRBG_HashDf(ctx, ctx->c, ctx->seedLen, &temp, &seed, NULL, NULL);
266 if (ret != CRYPT_SUCCESS) {
267 BSL_ERR_PUSH_ERROR(ret);
268 }
269 return ret;
270 }
271
DRBG_HashAdinInHashGenerate(DRBG_HashCtx * ctx,const CRYPT_Data * adin)272 static int32_t DRBG_HashAdinInHashGenerate(DRBG_HashCtx *ctx, const CRYPT_Data *adin)
273 {
274 void *mdCtx = ctx->mdCtx;
275 const EAL_MdMethod *md = ctx->md;
276 uint32_t mdSize = md->mdSize;
277 int32_t ret;
278 uint8_t temp = 0x2;
279 uint8_t w[DRBG_HASH_MAX_MDSIZE];
280 uint32_t wLen = DRBG_HASH_MAX_MDSIZE;
281
282 ret = md->init(mdCtx, NULL);
283 if (ret != CRYPT_SUCCESS) {
284 BSL_ERR_PUSH_ERROR(ret);
285 return ret;
286 }
287 ret = md->update(mdCtx, &temp, 1);
288 if (ret != CRYPT_SUCCESS) {
289 BSL_ERR_PUSH_ERROR(ret);
290 goto EXIT;
291 }
292 ret = md->update(mdCtx, ctx->v, ctx->seedLen);
293 if (ret != CRYPT_SUCCESS) {
294 BSL_ERR_PUSH_ERROR(ret);
295 goto EXIT;
296 }
297 ret = md->update(mdCtx, adin->data, adin->len);
298 if (ret != CRYPT_SUCCESS) {
299 BSL_ERR_PUSH_ERROR(ret);
300 goto EXIT;
301 }
302
303 ret = md->final(mdCtx, w, &wLen);
304 if (ret != CRYPT_SUCCESS) {
305 BSL_ERR_PUSH_ERROR(ret);
306 goto EXIT;
307 }
308
309 DRBG_HashAddV(ctx->v, ctx->seedLen, w, mdSize);
310
311 EXIT:
312 // Clear MD data.
313 md->deinit(mdCtx);
314 return ret;
315 }
316
DRBG_HashGenerate(DRBG_Ctx * drbg,uint8_t * out,uint32_t outLen,const CRYPT_Data * adin)317 int32_t DRBG_HashGenerate(DRBG_Ctx *drbg, uint8_t *out, uint32_t outLen, const CRYPT_Data *adin)
318 {
319 DRBG_HashCtx *ctx = (DRBG_HashCtx*)drbg->ctx;
320 const EAL_MdMethod *md = ctx->md;
321 void *mdCtx = ctx->mdCtx;
322 uint32_t mdSize = md->mdSize;
323 uint8_t h[DRBG_HASH_MAX_MDSIZE];
324 uint32_t len = outLen;
325 int32_t ret;
326 uint32_t reseedCtrBe;
327
328 /* if adin :
329 w = HASH(0x02 || V || adin)
330 V = (V + w) mod 2^seedLen
331 */
332 if (!CRYPT_IsDataNull(adin)) {
333 ret = DRBG_HashAdinInHashGenerate(ctx, adin);
334 if (ret != CRYPT_SUCCESS) {
335 BSL_ERR_PUSH_ERROR(ret);
336 return ret;
337 }
338 }
339
340 // Hashgen(V, out, len)
341 ret = DRBG_Hashgen(ctx, out, len);
342 if (ret != CRYPT_SUCCESS) {
343 BSL_ERR_PUSH_ERROR(ret);
344 return ret;
345 }
346
347 // H = HASH(0x03 || V)
348 uint8_t temp = 0x3;
349
350 ret = md->init(mdCtx, NULL);
351 if (ret != CRYPT_SUCCESS) {
352 BSL_ERR_PUSH_ERROR(ret);
353 return ret;
354 }
355
356 ret = md->update(mdCtx, &temp, 1);
357 if (ret != CRYPT_SUCCESS) {
358 BSL_ERR_PUSH_ERROR(ret);
359 goto EXIT;
360 }
361 ret = md->update(mdCtx, ctx->v, ctx->seedLen);
362 if (ret != CRYPT_SUCCESS) {
363 BSL_ERR_PUSH_ERROR(ret);
364 goto EXIT;
365 }
366
367 ret = md->final(mdCtx, h, &mdSize);
368 if (ret != CRYPT_SUCCESS) {
369 BSL_ERR_PUSH_ERROR(ret);
370 goto EXIT;
371 }
372
373 // V = (V + H + C + reseed_counter) mod 2^seedlen
374 DRBG_HashAddV(ctx->v, ctx->seedLen, h, mdSize);
375 DRBG_HashAddV(ctx->v, ctx->seedLen, ctx->c, ctx->seedLen);
376 reseedCtrBe = CRYPT_HTONL((uint32_t)(drbg->reseedCtr));
377 DRBG_HashAddV(ctx->v, ctx->seedLen, (uint8_t*)&reseedCtrBe, sizeof(reseedCtrBe));
378
379 EXIT:
380 // Clear MD data.
381 md->deinit(mdCtx);
382 return ret;
383 }
384
DRBG_HashReseed(DRBG_Ctx * drbg,const CRYPT_Data * entropy,const CRYPT_Data * adin)385 int32_t DRBG_HashReseed(DRBG_Ctx *drbg, const CRYPT_Data *entropy, const CRYPT_Data *adin)
386 {
387 int32_t ret;
388 DRBG_HashCtx *ctx = (DRBG_HashCtx*)drbg->ctx;
389 CRYPT_Data v = {ctx->v, ctx->seedLen};
390 uint8_t c = 0x1;
391 CRYPT_Data temp = {&c, 1};
392
393 /**
394 seed_material = 0x01 || V || entropy_input || additional_input.
395 seed = Hash_Df(seed_material) // The memory of C is reused.
396 V = seed
397 C = Hash_Df(0x00 || V)
398 */
399 if (drbg->isGm) {
400 ret = DRBG_HashDf(ctx, ctx->c, ctx->seedLen, &temp, entropy, &v, adin);
401 } else {
402 ret = DRBG_HashDf(ctx, ctx->c, ctx->seedLen, &temp, &v, entropy, adin);
403 }
404 if (ret != CRYPT_SUCCESS) {
405 BSL_ERR_PUSH_ERROR(ret);
406 return ret;
407 }
408
409 // The length of the C array is the longest seedLen. Therefore, there is no failure.
410 (void)memcpy_s(ctx->v, sizeof(ctx->v), ctx->c, ctx->seedLen);
411
412 c = 0x0;
413 ret = DRBG_HashDf(ctx, ctx->c, ctx->seedLen, &temp, &v, NULL, NULL);
414 if (ret != CRYPT_SUCCESS) {
415 BSL_ERR_PUSH_ERROR(ret);
416 }
417
418 return ret;
419 }
420
DRBG_HashUnInstantiate(DRBG_Ctx * drbg)421 void DRBG_HashUnInstantiate(DRBG_Ctx *drbg)
422 {
423 DRBG_HashCtx *ctx = (DRBG_HashCtx*)drbg->ctx;
424
425 ctx->md->deinit(ctx->mdCtx);
426 BSL_SAL_CleanseData((void *)(ctx->c), sizeof(ctx->c));
427 BSL_SAL_CleanseData((void *)(ctx->v), sizeof(ctx->v));
428 }
429
DRBG_HashDup(DRBG_Ctx * drbg)430 DRBG_Ctx *DRBG_HashDup(DRBG_Ctx *drbg)
431 {
432 DRBG_HashCtx *ctx = NULL;
433
434 if (drbg == NULL) {
435 return NULL;
436 }
437
438 ctx = (DRBG_HashCtx*)drbg->ctx;
439 return DRBG_NewHashCtx(ctx->md, drbg->isGm, &(drbg->seedMeth), drbg->seedCtx);
440 }
441
DRBG_HashFree(DRBG_Ctx * drbg)442 void DRBG_HashFree(DRBG_Ctx *drbg)
443 {
444 if (drbg == NULL) {
445 return;
446 }
447
448 DRBG_HashUnInstantiate(drbg);
449 DRBG_HashCtx *ctx = (DRBG_HashCtx*)drbg->ctx;
450 ctx->md->freeCtx(ctx->mdCtx);
451 BSL_SAL_FREE(drbg);
452 return;
453 }
454
DRBG_NewHashCtxBase(uint32_t mdSize,DRBG_Ctx * drbg,DRBG_HashCtx * ctx)455 static int32_t DRBG_NewHashCtxBase(uint32_t mdSize, DRBG_Ctx *drbg, DRBG_HashCtx *ctx)
456 {
457 switch (mdSize) {
458 case DRBG_SHA1MDSIZE:
459 drbg->strength = 128; // 128 is the standard content length of nist 800-90a.
460 ctx->seedLen = 55; // 55 is the standard content length of nist 800-90a.
461 return CRYPT_SUCCESS;
462 case DRBG_SHA224MDSIZE:
463 drbg->strength = 192; // 192 is the standard content length of nist 800-90a.
464 ctx->seedLen = 55; // 55 is the standard content length of nist 800-90a.
465 return CRYPT_SUCCESS;
466 case DRBG_SHA256MDSIZE:
467 drbg->strength = 256; // 256 is the standard content length of nist 800-90a.
468 ctx->seedLen = 55; // 55 is the standard content length of nist 800-90a.
469 return CRYPT_SUCCESS;
470 case DRBG_SHA384MDSIZE:
471 case DRBG_SHA512MDSIZE:
472 drbg->strength = 256; // 256 is the standard content length of nist 800-90a.
473 ctx->seedLen = 111; // 111 is the standard content length of nist 800-90a.
474 return CRYPT_SUCCESS;
475 default:
476 BSL_ERR_PUSH_ERROR(CRYPT_DRBG_ALG_NOT_SUPPORT);
477 return CRYPT_DRBG_ALG_NOT_SUPPORT;
478 }
479 }
480
DRBG_NewHashCtx(const EAL_MdMethod * md,bool isGm,const CRYPT_RandSeedMethod * seedMeth,void * seedCtx)481 DRBG_Ctx *DRBG_NewHashCtx(const EAL_MdMethod *md, bool isGm, const CRYPT_RandSeedMethod *seedMeth, void *seedCtx)
482 {
483 DRBG_Ctx *drbg = NULL;
484 DRBG_HashCtx *ctx = NULL;
485 static DRBG_Method meth = {
486 DRBG_HashInstantiate,
487 DRBG_HashGenerate,
488 DRBG_HashReseed,
489 DRBG_HashUnInstantiate,
490 DRBG_HashDup,
491 DRBG_HashFree
492 };
493
494 if (md == NULL || md->newCtx == NULL || md->freeCtx == NULL || seedMeth == NULL) {
495 return NULL;
496 }
497
498 drbg = (DRBG_Ctx*)BSL_SAL_Malloc(sizeof(DRBG_Ctx) + sizeof(DRBG_HashCtx));
499 if (drbg == NULL) {
500 return NULL;
501 }
502
503 ctx = (DRBG_HashCtx*)(drbg + 1);
504 ctx->md = md;
505 ctx->mdCtx = md->newCtx();
506 if (ctx->mdCtx == NULL) {
507 BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
508 BSL_SAL_FREE(drbg);
509 return NULL;
510 }
511 if (DRBG_NewHashCtxBase(md->mdSize, drbg, ctx) != CRYPT_SUCCESS) {
512 BSL_SAL_FREE(drbg);
513 md->freeCtx(ctx->mdCtx);
514 ctx->mdCtx = NULL;
515 return NULL;
516 }
517
518 drbg->state = DRBG_STATE_UNINITIALISED;
519 drbg->isGm = isGm;
520 drbg->reseedInterval = (drbg->isGm) ? HITLS_CRYPTO_RESEED_INTERVAL_GM : DRBG_MAX_RESEED_INTERVAL;
521 #if defined(HITLS_CRYPTO_DRBG_GM)
522 drbg->reseedIntervalTime = (drbg->isGm) ? HITLS_CRYPTO_DRBG_RESEED_TIME_GM : 0;
523 #endif
524
525 drbg->meth = &meth;
526 drbg->ctx = ctx;
527 drbg->seedMeth = *seedMeth;
528 drbg->seedCtx = seedCtx;
529
530 // Shift right by 3, from bit length to byte length
531 drbg->entropyRange.min = drbg->strength >> 3;
532 drbg->entropyRange.max = DRBG_MAX_LEN;
533
534 drbg->nonceRange.min = drbg->entropyRange.min / DRBG_NONCE_FROM_ENTROPY;
535 drbg->nonceRange.max = DRBG_MAX_LEN;
536
537 drbg->maxPersLen = DRBG_MAX_LEN;
538 drbg->maxAdinLen = DRBG_MAX_LEN;
539 drbg->maxRequest = (drbg->isGm) ? DRBG_MAX_REQUEST_SM3 : DRBG_MAX_REQUEST;
540
541 return drbg;
542 }
543 #endif
544