Initial, provisional, subject to wholesale change, untested, probably
authorDr. Stephen Henson <steve@openssl.org>
Fri, 4 Mar 2011 18:00:21 +0000 (18:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 4 Mar 2011 18:00:21 +0000 (18:00 +0000)
not working, incomplete and unused SP800-90 DRBGs for CTR and Hash modes.

Did I say this was untested?

CHANGES
fips/rand/Makefile
fips/rand/fips_drbg_ctr.c [new file with mode: 0644]
fips/rand/fips_drbg_hash.c [new file with mode: 0644]
fips/rand/fips_drbg_lib.c [new file with mode: 0644]
fips/rand/fips_rand.h
fips/rand/fips_rand_lcl.h [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 6b80397..d3c0c27 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Initial implementation of SP800-90 DRBGs for Hash and CTR. Not used by
+     anything, incomplete, subject to change and largely untested at present.
+     [Steve Henson]
+
   *) Modify fipscanisteronly build option to only build the necessary object
      files by filtering FIPS_EX_OBJ through a perl script in crypto/Makefile.
      [Steve Henson]
index ce08396..580d6df 100644 (file)
@@ -22,13 +22,15 @@ TEST= fips_randtest.c fips_rngvs.c
 APPS=
 
 LIB=$(TOP)/libcrypto.a
-LIBSRC=fips_rand.c fips_rand_selftest.c
-LIBOBJ=fips_rand.o fips_rand_selftest.o
+LIBSRC=        fips_rand.c fips_rand_selftest.c \
+       fips_drbg_lib.c fips_drbg_hash.c fips_drbg_ctr.c
+LIBOBJ=        fips_rand.o fips_rand_selftest.o \
+       fips_drbg_lib.o fips_drbg_hash.o fips_drbg_ctr.o
 
 SRC= $(LIBSRC)
 
 EXHEADER= fips_rand.h
-HEADER=        $(EXHEADER)
+HEADER=        $(EXHEADER) fips_rand_lcl.h
 
 ALL=    $(GENERAL) $(SRC) $(HEADER)
 
diff --git a/fips/rand/fips_drbg_ctr.c b/fips/rand/fips_drbg_ctr.c
new file mode 100644 (file)
index 0000000..212bcf8
--- /dev/null
@@ -0,0 +1,419 @@
+/* fips/rand/fips_drbg_ctr.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/fips.h>
+#include <openssl/fips_rand.h>
+#include "fips_rand_lcl.h"
+
+static void inc_128(DRBG_CTR_CTX *cctx)
+       {
+       int i;
+       unsigned char c;
+       unsigned char *p = cctx->V + 15;
+       for (i = 0; i < 16; i++)
+               {
+               c = *p;
+               c++;
+               *p = c;
+               if (c)
+                       return;
+               p--;
+               }
+       }
+
+static void ctr_XOR(DRBG_CTR_CTX *cctx, const unsigned char *in, size_t inlen)
+       {
+       size_t i, n;
+       /* Any zero padding will have no effect on the result as we
+        * are XORing. So just process however much input we have.
+        */
+
+       if (!in || !inlen)
+               return;
+
+       if (inlen < cctx->keylen)
+               n = inlen;
+       else
+               n = cctx->keylen;
+
+       for (i = 0; i < n; i++)
+               cctx->K[i] ^= in[i];
+       if (inlen <= cctx->keylen)
+               return;
+
+       n = inlen - cctx->keylen;
+       /* Should never happen */
+       if (n > 16)
+               n = 16;
+       for (i = 0; i < 16; i++)
+               cctx->V[i] ^= in[i + cctx->keylen];
+       }
+
+/* Process a complete block using BCC algorithm of SPP 800-90 10.4.3 */
+
+static void ctr_BCC_block(DRBG_CTR_CTX *cctx, unsigned char *out,
+                               const unsigned char *in)
+       {
+       int i;
+       for (i = 0; i < 16; i++)
+               out[i] ^= in[i];
+       AES_encrypt(out, out, &cctx->df_ks);
+#if 0
+fprintf(stderr, "BCC in+out\n");
+BIO_dump_fp(stderr, in, 16);
+BIO_dump_fp(stderr, out, 16);
+#endif
+       }
+
+/* Handle several BCC operations for as much data as we need for K and X */
+static void ctr_BCC_blocks(DRBG_CTR_CTX *cctx, const unsigned char *in)
+       {
+       ctr_BCC_block(cctx, cctx->KX, in);
+       ctr_BCC_block(cctx, cctx->KX + 16, in);
+       if (cctx->keylen != 16)
+               ctr_BCC_block(cctx, cctx->KX + 32, in);
+       }
+/* Initialise BCC blocks: these have the value 0,1,2 in leftmost positions:
+ * see 10.4.2 stage 7.
+ */
+static void ctr_BCC_init(DRBG_CTR_CTX *cctx)
+       {
+       memset(cctx->KX, 0, 48);
+       memset(cctx->bltmp, 0, 16);
+       ctr_BCC_block(cctx, cctx->KX, cctx->bltmp);
+       cctx->bltmp[3] = 1;
+       ctr_BCC_block(cctx, cctx->KX + 16, cctx->bltmp);
+       if (cctx->keylen != 16)
+               {
+               cctx->bltmp[3] = 2;
+               ctr_BCC_block(cctx, cctx->KX + 32, cctx->bltmp);
+               }
+       }
+
+/* Process several blocks into BCC algorithm, some possibly partial */
+static void ctr_BCC_update(DRBG_CTR_CTX *cctx,
+                               const unsigned char *in, size_t inlen)
+       {
+       if (!in || !inlen)
+               return;
+       /* If we have partial block handle it first */
+       if (cctx->bltmp_pos)
+               {
+               size_t left = 16 - cctx->bltmp_pos;
+               /* If we now have a complete block process it */
+               if (inlen >= left)
+                       {
+                       memcpy(cctx->bltmp + cctx->bltmp_pos, in, left);
+                       ctr_BCC_blocks(cctx, cctx->bltmp);
+                       cctx->bltmp_pos = 0;
+                       inlen -= left;
+                       in += left;
+                       }
+               }
+       /* Process zero or more complete blocks */
+       while (inlen >= 16)
+               {
+               ctr_BCC_blocks(cctx, in);
+               in += 16;
+               inlen -= 16;
+               }
+       /* Copy any remaining partial block to the temporary buffer */
+       if (inlen > 0)
+               {
+               memcpy(cctx->bltmp + cctx->bltmp_pos, in, inlen);
+               cctx->bltmp_pos += inlen;
+               }
+       }
+
+static void ctr_BCC_final(DRBG_CTR_CTX *cctx)
+       {
+       if (cctx->bltmp_pos)
+               {
+               memset(cctx->bltmp + cctx->bltmp_pos, 0, 16 - cctx->bltmp_pos);
+               ctr_BCC_blocks(cctx, cctx->bltmp);
+               }
+       }
+
+static void ctr_df(DRBG_CTR_CTX *cctx,
+                       const unsigned char *in1, size_t in1len,
+                       const unsigned char *in2, size_t in2len,
+                       const unsigned char *in3, size_t in3len)
+       {
+       size_t inlen;
+       unsigned char *p = cctx->bltmp;
+       static unsigned char c80 = 0x80;
+
+       ctr_BCC_init(cctx);
+       if (!in1)
+               in1len = 0;
+       if (!in2)
+               in2len = 0;
+       if (!in3)
+               in3len = 0;
+       inlen = in1len + in2len + in3len;
+       /* Initialise L||N in temporary block */
+       *p++ = (inlen >> 24) & 0xff;
+       *p++ = (inlen >> 16) & 0xff;
+       *p++ = (inlen >> 8) & 0xff;
+       *p++ = inlen & 0xff;
+       /* NB keylen is at most 32 bytes */
+       *p++ = 0;
+       *p++ = 0;
+       *p++ = 0;
+       *p = (unsigned char)((cctx->keylen + 16) & 0xff);
+       cctx->bltmp_pos = 8;
+       ctr_BCC_update(cctx, in1, in1len);
+       ctr_BCC_update(cctx, in2, in2len);
+       ctr_BCC_update(cctx, in3, in3len);
+       ctr_BCC_update(cctx, &c80, 1);
+       ctr_BCC_final(cctx);
+       /* Set up key K */
+       AES_set_encrypt_key(cctx->KX, cctx->keylen * 8, &cctx->df_kxks);
+       /* X follows key K */
+       AES_encrypt(cctx->KX + cctx->keylen, cctx->KX, &cctx->df_kxks);
+       AES_encrypt(cctx->KX, cctx->KX + 16, &cctx->df_kxks);
+       if (cctx->keylen != 16)
+               AES_encrypt(cctx->KX + 16, cctx->KX + 32, &cctx->df_kxks);
+#if 0
+fprintf(stderr, "Output of ctr_df:\n");
+BIO_dump_fp(stderr, cctx->KX, cctx->keylen + 16);
+#endif
+       }
+
+/* NB the no-df  Update in SP800-90 specifies a constant input length
+ * of seedlen, however other uses of this algorithm pad the input with
+ * zeroes if necessary and have up to two parameters XORed together,
+ * handle both cases in this function instead.
+ */
+
+static void ctr_Update(DRBG_CTX *dctx,
+               const unsigned char *in1, size_t in1len,
+               const unsigned char *in2, size_t in2len,
+               const unsigned char *nonce, size_t noncelen)
+       {
+       DRBG_CTR_CTX *cctx = &dctx->d.ctr;
+       /* ks is already setup for correct key */
+       inc_128(cctx);
+       AES_encrypt(cctx->V, cctx->K, &cctx->ks);
+       /* If keylen longer than 128 bits need extra encrypt */
+       if (cctx->keylen != 16)
+               {
+               inc_128(cctx);
+               AES_encrypt(cctx->V, cctx->K + 16, &cctx->ks);
+               }
+       inc_128(cctx);
+       AES_encrypt(cctx->V, cctx->V, &cctx->ks);
+       /* If 192 bit key part of V is on end of K */
+       if (cctx->keylen == 24)
+               {
+               memcpy(cctx->V + 8, cctx->V, 8);
+               memcpy(cctx->V, cctx->K + 24, 8);
+               }
+
+       if (dctx->flags & DRBG_FLAG_CTR_USE_DF)
+               {
+               /* If no input reuse existing derived value */
+               if (in1 || nonce || in2)
+                       ctr_df(cctx, in1, in1len, nonce, noncelen, in2, in2len);
+               /* If this a reuse input in1len != 0 */
+               if (in1len)
+                       ctr_XOR(cctx, cctx->KX, dctx->seedlen);
+               }
+       else
+               {
+               ctr_XOR(cctx, in1, in1len);
+               ctr_XOR(cctx, in2, in2len);
+               }
+
+       AES_set_encrypt_key(cctx->K, dctx->strength, &cctx->ks);
+#if 0
+fprintf(stderr, "K+V after update is:\n");
+BIO_dump_fp(stderr, cctx->K, cctx->keylen);
+BIO_dump_fp(stderr, cctx->V, 16);
+#endif
+       }
+
+static int drbg_ctr_instantiate(DRBG_CTX *dctx,
+                       const unsigned char *ent, size_t entlen,
+                       const unsigned char *nonce, size_t noncelen,
+                       const unsigned char *pers, size_t perslen)
+       {
+       DRBG_CTR_CTX *cctx = &dctx->d.ctr;
+       memset(cctx->K, 0, sizeof(cctx->K));
+       memset(cctx->V, 0, sizeof(cctx->V));
+       AES_set_encrypt_key(cctx->K, dctx->strength, &cctx->ks);
+       ctr_Update(dctx, ent, entlen, pers, perslen, nonce, noncelen);
+       return 1;
+       }
+
+static int drbg_ctr_reseed(DRBG_CTX *dctx, 
+                       const unsigned char *ent, size_t entlen,
+                       const unsigned char *adin, size_t adinlen)
+       {
+       ctr_Update(dctx, ent, entlen, adin, adinlen, NULL, 0);
+       return 1;
+       }
+
+static int drbg_ctr_generate(DRBG_CTX *dctx,
+                       unsigned char *out, size_t outlen,
+                       const unsigned char *adin, size_t adinlen)
+       {
+       DRBG_CTR_CTX *cctx = &dctx->d.ctr;
+       if (adin && adinlen)
+               {
+               ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0);
+               /* This means we reuse derived value */
+               if (dctx->flags & DRBG_FLAG_CTR_USE_DF)
+                       {
+                       adin = NULL;
+                       adinlen = 1;
+                       }
+               }
+       else
+               adinlen = 0;
+
+       for (;;)
+               {
+               inc_128(cctx);
+               if (outlen < 16)
+                       {
+                       /* Use K as temp space as it will be updated */
+                       AES_encrypt(cctx->V, cctx->K, &cctx->ks);
+                       memcpy(out, cctx->K, outlen);
+                       break;
+                       }
+               AES_encrypt(cctx->V, out, &cctx->ks);
+               out += 16;
+               outlen -= 16;
+               if (outlen == 0)
+                       break;
+               }
+
+       ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0);
+
+       return 1;
+
+       }
+
+int fips_drbg_ctr_init(DRBG_CTX *dctx)
+       {
+       DRBG_CTR_CTX *cctx = &dctx->d.ctr;
+
+       size_t keylen;
+
+       switch (dctx->type)
+               {
+               case NID_aes_128_ctr:
+               keylen = 16;
+
+               case NID_aes_192_ctr:
+               keylen = 24;
+
+               case NID_aes_256_ctr:
+               keylen = 32;
+
+               default:
+               return -2;
+               }
+
+       dctx->instantiate = drbg_ctr_instantiate;
+       dctx->reseed = drbg_ctr_reseed;
+       dctx->generate = drbg_ctr_generate;
+
+
+       cctx->keylen = keylen;
+       dctx->strength = keylen * 8;
+       dctx->blocklength = 16;
+       dctx->seedlen = keylen + 16;
+
+       if (dctx->flags & DRBG_FLAG_CTR_USE_DF)
+               {
+               /* df initialisation */
+               static unsigned char df_key[32] =
+                       {
+                       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+                       0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+                       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+                       0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f 
+                       };
+               /* Set key schedule for df_key */
+               AES_set_encrypt_key(df_key, dctx->strength, &cctx->df_ks);
+
+               dctx->min_entropy = dctx->seedlen;
+               dctx->max_entropy = dctx->seedlen;
+               /* Nonce not used */
+               dctx->min_nonce = 0;
+               dctx->max_nonce = 0;
+               dctx->max_pers = dctx->seedlen;
+               dctx->max_adin = dctx->seedlen;
+               }
+       else
+               {
+               dctx->min_entropy = cctx->keylen;
+               dctx->max_entropy = DRBG_MAX_ENTROPY;
+               dctx->min_nonce = dctx->min_entropy / 2;
+               dctx->max_nonce = DRBG_MAX_NONCE;
+               dctx->max_pers = DRBG_MAX_LENGTH;
+               dctx->max_adin = DRBG_MAX_LENGTH;
+               }
+
+       dctx->max_request = 1<<19;
+       dctx->reseed_counter = DRBG_MAX_LENGTH;
+
+       return 1;
+       }
diff --git a/fips/rand/fips_drbg_hash.c b/fips/rand/fips_drbg_hash.c
new file mode 100644 (file)
index 0000000..4dbcdb6
--- /dev/null
@@ -0,0 +1,374 @@
+/* fips/rand/fips_drbg_hash.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#define OPENSSL_FIPSAPI
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/fips.h>
+#include <openssl/fips_rand.h>
+#include "fips_rand_lcl.h"
+
+/* This is Hash_df from SP 800-90 10.4.1 */
+
+static int hash_df(DRBG_CTX *dctx, unsigned char *out,
+                       const unsigned char *in1, size_t in1len,
+                       const unsigned char *in2, size_t in2len,
+                       const unsigned char *in3, size_t in3len,
+                       const unsigned char *in4, size_t in4len)
+       {
+       EVP_MD_CTX *mctx = &dctx->d.hash.mctx;
+       unsigned char *vtmp = dctx->d.hash.vtmp;
+       unsigned char tmp[6];
+       /* Standard only ever needs seedlen bytes which is always less than
+        * maximum permitted so no need to check length.
+        */
+       size_t outlen = dctx->seedlen;
+       tmp[0] = 1;
+       tmp[1] = ((outlen * 8) >> 24) & 0xff;
+       tmp[2] = ((outlen * 8) >> 16) & 0xff;
+       tmp[3] = ((outlen * 8) >> 8) & 0xff;
+       tmp[4] = (outlen * 8) & 0xff;
+       if (!in1)
+               {
+               tmp[5] = (unsigned char)in1len;
+               in1 = tmp + 5;
+               in1len = 1;
+               }
+       for (;;)
+               {
+               if (!FIPS_digestinit(mctx, dctx->d.hash.md))
+                       return 0;
+               if (!FIPS_digestupdate(mctx, tmp, 5))
+                       return 0;
+               if (in1 && !FIPS_digestupdate(mctx, in1, in1len))
+                       return 0;
+               if (in2 && !FIPS_digestupdate(mctx, in2, in2len))
+                       return 0;
+               if (in3 && !FIPS_digestupdate(mctx, in3, in3len))
+                       return 0;
+               if (in4 && !FIPS_digestupdate(mctx, in4, in4len))
+                       return 0;
+               if (outlen < dctx->blocklength)
+                       {
+                       if (!FIPS_digestfinal(mctx, vtmp, NULL))
+                               return 0;
+                       memcpy(out, vtmp, outlen);
+                       OPENSSL_cleanse(vtmp, dctx->blocklength);
+                       return 1;
+                       }
+               else if(!FIPS_digestfinal(mctx, out, NULL))
+                       return 0;
+
+               outlen -= dctx->blocklength;
+               if (outlen == 0)
+                       return 1;
+               tmp[0]++;
+               out += dctx->blocklength;
+               }
+       }
+
+
+/* Add an unsigned buffer to the buf value, storing the result in buf. For
+ * this algorithm the length of input never exceeds the seed length.
+ */
+
+static void ctx_add_buf(DRBG_CTX *dctx, unsigned char *buf,
+                               unsigned char *in, size_t inlen)
+       {
+       size_t i = inlen;
+       const unsigned char *q;
+       unsigned char c, *p;
+       p = buf + dctx->seedlen;
+       q = in + inlen;
+
+       OPENSSL_assert(i <= dctx->seedlen);
+
+       /* Special case: zero length, just increment buffer */
+       if (i)
+               c = 0;
+       else 
+               c = 1;
+
+       while (i)
+               {
+               int r;
+               p--;
+               q--;
+               r = *p + *q + c;
+               /* Carry */
+               if (r > 0xff)
+                       c = 1;
+               else
+                       c = 0;
+               *p = r & 0xff;
+               i--;
+               }
+
+       i = dctx->seedlen - inlen;
+
+       /* If not adding whole buffer handle final carries */
+       if (c && i)
+               {
+               do
+                       {
+                       p--;
+                       c = *p;
+                       c++;
+                       *p = c;
+                       if(c)
+                               return;
+                       } while(i--);
+               }
+       }
+
+/* Finalise and add hash to V */
+       
+static int ctx_add_md(DRBG_CTX *dctx)
+       {
+       if (!FIPS_digestfinal(&dctx->d.hash.mctx, dctx->d.hash.vtmp, NULL))
+                       return 0;
+       ctx_add_buf(dctx, dctx->d.hash.V, dctx->d.hash.vtmp, dctx->blocklength);
+       return 1;
+       }
+
+static int hash_gen(DRBG_CTX *dctx, unsigned char *out, size_t outlen)
+       {
+       DRBG_HASH_CTX *hctx = &dctx->d.hash;
+       if (outlen == 0)
+               return 1;
+       memcpy(hctx->vtmp, hctx->V, dctx->seedlen);
+       for(;;)
+               {
+               FIPS_digestinit(&hctx->mctx, hctx->md);
+               FIPS_digestupdate(&hctx->mctx, hctx->vtmp, dctx->seedlen);
+               if (outlen < dctx->blocklength)
+                       {
+                       FIPS_digestfinal(&hctx->mctx, hctx->vtmp, NULL);
+                       memcpy(out, hctx->vtmp, outlen);
+                       return 1;
+                       }
+               FIPS_digestfinal(&hctx->mctx, out, NULL);
+               outlen -= dctx->blocklength;
+               if (outlen == 0)
+                       return 1;
+               out += dctx->blocklength;
+               ctx_add_buf(dctx, hctx->vtmp, NULL, 0);
+               }
+       }
+
+static int drbg_hash_instantiate(DRBG_CTX *dctx,
+                               const unsigned char *ent, size_t ent_len,
+                               const unsigned char *nonce, size_t nonce_len,
+                               const unsigned char *pstr, size_t pstr_len)
+       {
+       DRBG_HASH_CTX *hctx = &dctx->d.hash;
+       if (!hash_df(dctx, hctx->V, 
+                       ent, ent_len, nonce, nonce_len, pstr, pstr_len,
+                       NULL, 0))
+               return 0;
+       if (!hash_df(dctx, hctx->C, 
+                       NULL, 0, hctx->V, dctx->seedlen,
+                       NULL, 0, NULL, 0))
+               return 0;
+
+#ifdef HASH_DRBG_TRACE
+       fprintf(stderr, "V+C after instantiate:\n");
+       hexprint(stderr, hctx->V, dctx->seedlen);
+       hexprint(stderr, hctx->C, dctx->seedlen);
+#endif
+       return 1;
+       }
+
+       
+static int drbg_hash_reseed(DRBG_CTX *dctx,
+                               const unsigned char *ent, size_t ent_len,
+                               const unsigned char *adin, size_t adin_len)
+       {
+       DRBG_HASH_CTX *hctx = &dctx->d.hash;
+       /* V about to be updated so use C as output instead */
+       if (!hash_df(dctx, hctx->C,
+                       NULL, 1, hctx->V, dctx->seedlen,
+                       ent, ent_len, adin, adin_len))
+               return 0;
+       memcpy(hctx->V, hctx->C, dctx->seedlen);
+       if (!hash_df(dctx, hctx->C, NULL, 0,
+                       hctx->V, dctx->seedlen, NULL, 0, NULL, 0))
+               return 0;
+#ifdef HASH_DRBG_TRACE
+       fprintf(stderr, "V+C after reseed:\n");
+       hexprint(stderr, hctx->V, dctx->seedlen);
+       hexprint(stderr, hctx->C, dctx->seedlen);
+#endif
+       return 1;
+       }
+
+static int drbg_hash_generate(DRBG_CTX *dctx,
+                               unsigned char *out, size_t outlen,
+                               const unsigned char *adin, size_t adin_len)
+       {
+       DRBG_HASH_CTX *hctx = &dctx->d.hash;
+       EVP_MD_CTX *mctx = &hctx->mctx;
+       unsigned char tmp[4];
+       if (adin && adin_len)
+               {
+               tmp[0] = 2;
+               if (!FIPS_digestinit(mctx, hctx->md))
+                       return 0;
+               if (!EVP_DigestUpdate(mctx, tmp, 1))
+                       return 0;
+               if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
+                       return 0;
+               if (!EVP_DigestUpdate(mctx, adin, adin_len))
+                       return 0;
+               if (!ctx_add_md(dctx))
+                       return 0;
+               }
+       if (!hash_gen(dctx, out, outlen))
+               return 0;
+
+       tmp[0] = 3;
+       if (!FIPS_digestinit(mctx, hctx->md))
+               return 0;
+       if (!EVP_DigestUpdate(mctx, tmp, 1))
+               return 0;
+       if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
+               return 0;
+
+       if (!ctx_add_md(dctx))
+               return 0;
+
+       ctx_add_buf(dctx, hctx->V, hctx->C, dctx->seedlen);
+
+       tmp[0] = (dctx->reseed_counter >> 24) & 0xff;
+       tmp[1] = (dctx->reseed_counter >> 16) & 0xff;
+       tmp[2] = (dctx->reseed_counter >> 8) & 0xff;
+       tmp[3] = dctx->reseed_counter & 0xff;
+       ctx_add_buf(dctx, hctx->V, tmp, 4);
+#ifdef HASH_DRBG_TRACE
+       fprintf(stderr, "V+C after generate:\n");
+       hexprint(stderr, hctx->V, dctx->seedlen);
+       hexprint(stderr, hctx->C, dctx->seedlen);
+#endif
+       return 1;
+       }
+
+int fips_drbg_hash_init(DRBG_CTX *dctx)
+       {
+       const EVP_MD *md;
+       DRBG_HASH_CTX *hctx = &dctx->d.hash;
+       switch (dctx->type)
+               {
+               case NID_sha1:
+               md = EVP_sha1();
+               dctx->strength = 128;
+               break;
+
+               case NID_sha224:
+               md = EVP_sha224();
+               dctx->strength = 192;
+               break;
+
+               case NID_sha256:
+               md = EVP_sha256();
+               dctx->strength = 256;
+               break;
+
+               case NID_sha384:
+               md = EVP_sha384();
+               dctx->strength = 256;
+               break;
+
+               case NID_sha512:
+               md = EVP_sha512();
+               dctx->strength = 256;
+               break;
+
+               default:
+               return -2;
+               break;
+
+               }
+
+       dctx->instantiate = drbg_hash_instantiate;
+       dctx->reseed = drbg_hash_reseed;
+       dctx->generate = drbg_hash_generate;
+
+       dctx->d.hash.md = md;
+       EVP_MD_CTX_init(&hctx->mctx);
+
+       /* These are taken from SP 800-90 10.1 table 2 */
+
+       dctx->blocklength = M_EVP_MD_size(md);
+       if (dctx->blocklength > 32)
+               dctx->seedlen = 111;
+       else
+               dctx->seedlen = 55;
+
+
+       dctx->min_entropy = dctx->strength / 8;
+       dctx->max_entropy = DRBG_MAX_ENTROPY;
+
+       dctx->min_nonce = dctx->min_entropy / 2;
+       dctx->max_nonce = DRBG_MAX_NONCE;
+
+       dctx->max_pers = DRBG_MAX_LENGTH;
+       dctx->max_adin = DRBG_MAX_LENGTH;
+
+       dctx->max_request = 1<<19;
+
+       return 1;
+       }
diff --git a/fips/rand/fips_drbg_lib.c b/fips/rand/fips_drbg_lib.c
new file mode 100644 (file)
index 0000000..da9fb37
--- /dev/null
@@ -0,0 +1,226 @@
+/* fips/rand/fips_drbg_lib.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#define OPENSSL_FIPSAPI
+
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/fips_rand.h>
+#include "fips_rand_lcl.h"
+
+/* Support framework for SP800-90 DRBGs */
+
+DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags)
+       {
+       int rv;
+       DRBG_CTX *dctx;
+       dctx = OPENSSL_malloc(sizeof(DRBG_CTX));
+       memset(dctx, 0, sizeof(DRBG_CTX));
+       dctx->status = DRBG_STATUS_UNINITIALISED;
+       dctx->flags = flags;
+       dctx->type = type;
+       rv = fips_drbg_hash_init(dctx);
+       if (rv == -2)
+               rv = fips_drbg_ctr_init(dctx);
+       if (rv <= 0)
+               {
+               /* Fatal: cannot initialiase DRBG */
+               goto err;
+               }
+
+       return dctx;
+
+       err:
+       if (dctx)
+               OPENSSL_free(dctx);
+       return NULL;
+       }
+
+int FIPS_drbg_instantiate(DRBG_CTX *dctx,
+                               int strength,
+                               const unsigned char *pers, size_t perslen)
+       {
+       size_t entlen, noncelen;
+
+       if (perslen > dctx->max_pers)
+               return 0;
+
+       if (dctx->status != DRBG_STATUS_UNINITIALISED)
+               {
+               /* error */
+               return 0;
+               }
+
+       dctx->status = DRBG_STATUS_ERROR;
+
+       entlen = dctx->get_entropy(dctx, dctx->entropy, dctx->strength,
+                               dctx->min_entropy, dctx->max_entropy);
+
+       if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
+               goto end;
+
+       if (dctx->max_nonce > 0)
+               {
+
+               noncelen = dctx->get_nonce(dctx, dctx->nonce,
+                                       dctx->strength / 2,
+                                       dctx->min_nonce, dctx->max_nonce);
+
+               if (noncelen < dctx->min_nonce || noncelen > dctx->max_nonce)
+                       goto end;
+
+               }
+       else
+               noncelen = 0;
+
+       if (!dctx->instantiate(dctx, 
+                               dctx->entropy, entlen,
+                               dctx->nonce, noncelen,
+                               pers, perslen))
+               goto end;
+
+
+       dctx->status = DRBG_STATUS_READY;
+       dctx->reseed_counter = 1;
+
+       end:
+
+       OPENSSL_cleanse(dctx->entropy, sizeof(dctx->entropy));
+       OPENSSL_cleanse(dctx->nonce, sizeof(dctx->nonce));
+
+       if (dctx->status == DRBG_STATUS_READY)
+               return 1;
+
+       return 0;
+
+       }
+
+int FIPS_drbg_reseed(DRBG_CTX *dctx,
+                       const unsigned char *adin, size_t adinlen)
+       {
+       size_t entlen;
+       if (dctx->status != DRBG_STATUS_READY
+               && dctx->status != DRBG_STATUS_RESEED)
+               {
+               /* error */
+               return 0;
+               }
+
+       if (!adin)
+               adinlen = 0;
+       else if (adinlen > dctx->max_adin);
+               {
+               /* error */
+               return 0;
+               }
+
+       dctx->status = DRBG_STATUS_ERROR;
+
+       entlen = dctx->get_entropy(dctx, dctx->entropy, dctx->strength,
+                               dctx->min_entropy, dctx->max_entropy);
+
+       if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
+               goto end;
+
+       if (!dctx->reseed(dctx, dctx->entropy, entlen, adin, adinlen))
+               goto end;
+
+       dctx->status = DRBG_STATUS_READY;
+       dctx->reseed_counter = 1;
+       end:
+       OPENSSL_cleanse(dctx->entropy, sizeof(dctx->entropy));
+       if (dctx->status == DRBG_STATUS_READY)
+               return 1;
+       return 0;
+       }
+       
+
+int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen,
+                       int prediction_resistance,
+                       const unsigned char *adin, size_t adinlen)
+       {
+       if (outlen > dctx->max_request)
+               {
+               /* Too large */
+               return 0;
+               }
+       if (dctx->status == DRBG_STATUS_RESEED || prediction_resistance)
+               {
+               if (!FIPS_drbg_reseed(dctx, adin, adinlen))
+                       return 0;
+               adin = NULL;
+               adinlen = 0;
+               }
+       if (dctx->status != DRBG_STATUS_READY)
+               {
+               /* Bad error */
+               return 0;
+               }
+       if (!dctx->generate(dctx, out, outlen, adin, adinlen))
+               {
+               /* Bad error */
+               dctx->status = DRBG_STATUS_ERROR;
+               return 0;
+               }
+       if (dctx->reseed_counter > dctx->reseed_interval)
+               dctx->status = DRBG_STATUS_RESEED;
+       else
+               dctx->reseed_counter++;
+
+       return 1;
+       }
+
+
+
index 28d7610..27eb8f7 100644 (file)
@@ -70,6 +70,16 @@ int FIPS_rand_status(void);
 
 const RAND_METHOD *FIPS_rand_method(void);
 
+typedef struct drbg_ctx_st DRBG_CTX;
+
+DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags);
+int FIPS_drbg_instantiate(DRBG_CTX *dctx, int strength,
+                               const unsigned char *pers, size_t perslen);
+int FIPS_drbg_reseed(DRBG_CTX *dctx, const unsigned char *adin, size_t adinlen);
+int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen,
+                       int prediction_resistance,
+                       const unsigned char *adin, size_t adinlen);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/fips/rand/fips_rand_lcl.h b/fips/rand/fips_rand_lcl.h
new file mode 100644 (file)
index 0000000..72820bf
--- /dev/null
@@ -0,0 +1,176 @@
+/* fips/rand/fips_rand_lcl.h */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+typedef struct drbg_hash_ctx_st DRBG_HASH_CTX;
+typedef struct drbg_ctr_ctx_st DRBG_CTR_CTX;
+
+/* 888 bits from 10.1 table 2 */
+#define HASH_PRNG_MAX_SEEDLEN  111
+
+struct drbg_hash_ctx_st
+       {
+       const EVP_MD *md;
+       EVP_MD_CTX mctx;
+       unsigned char V[HASH_PRNG_MAX_SEEDLEN];
+       unsigned char C[HASH_PRNG_MAX_SEEDLEN];
+       /* Temporary value storage: should always exceed max digest length */
+       unsigned char vtmp[HASH_PRNG_MAX_SEEDLEN];
+       };
+
+struct drbg_ctr_ctx_st
+       {
+       AES_KEY ks;
+       size_t keylen;
+       unsigned char K[32];
+       unsigned char V[16];
+       /* Temp variables used by derivation function */
+       AES_KEY df_ks;
+       AES_KEY df_kxks;
+       /* Temporary block storage used by ctr_df */
+       unsigned char bltmp[16];
+       size_t bltmp_pos;
+       unsigned char KX[48];
+       };
+
+/* DRBG flags */
+
+/* Enable prediction resistance */
+#define        DRBG_FLAG_PREDICTION_RESISTANCE 0x1
+/* CTR only: use derivation function */
+#define        DRBG_FLAG_CTR_USE_DF            0x2
+/* PRNG is in test state */
+#define        DRBG_FLAG_TEST                  0x4
+
+/* DRBG status values */
+/* not initialised */
+#define DRBG_STATUS_UNINITIALISED      0
+/* ok and ready to generate random bits */
+#define DRBG_STATUS_READY              1
+/* reseed required */
+#define DRBG_STATUS_RESEED             2
+/* fatal error condition */
+#define DRBG_STATUS_ERROR              3
+
+/* Maximum values for temp entropy and nonce */
+#define DRBG_MAX_ENTROPY               1024
+#define DRBG_MAX_NONCE                 1024
+
+/* A default maximum length: larger than any reasonable value used in pratice */
+
+#define DRBG_MAX_LENGTH                        0x7fffffff
+
+/* DRBG context structure */
+
+struct drbg_ctx_st
+       {
+       /* First types common to all implementations */
+       /* DRBG type: a NID for the underlying algorithm */
+       int type;
+       /* Various flags */
+       unsigned int flags;
+
+       /* The following parameters are setup by mechanism drbg_init() call */
+       int strength;
+       size_t blocklength;
+       size_t max_request;
+
+       size_t min_entropy, max_entropy;
+       size_t min_nonce, max_nonce;
+       size_t max_pers, max_adin;
+       unsigned int reseed_counter;
+       unsigned int reseed_interval;
+       size_t seedlen;
+       int status;
+       /* Application data: typically used by test get_entropy */
+       void *app_data;
+       /* Implementation specific structures */
+       union 
+               {
+               DRBG_HASH_CTX hash;
+               DRBG_CTR_CTX  ctr;
+               } d;
+       /* Initialiase PRNG and setup callbacks below */
+       int (*init)(DRBG_CTX *ctx, int nid, int security, unsigned int flags);
+       /* Intantiate PRNG */
+       int (*instantiate)(DRBG_CTX *ctx,
+                               const unsigned char *ent, size_t entlen,
+                               const unsigned char *nonce, size_t noncelen,
+                               const unsigned char *pers, size_t perslen);
+       /* reseed */
+       int (*reseed)(DRBG_CTX *ctx,
+                               const unsigned char *ent, size_t entlen,
+                               const unsigned char *adin, size_t adinlen);
+       /* generat output */
+       int (*generate)(DRBG_CTX *ctx,
+                               unsigned char *out, size_t outlen,
+                               const unsigned char *adin, size_t adinlen);
+       /* uninstantiate */
+       int (*uninstantiate)(DRBG_CTX *ctx);
+
+       unsigned char entropy[DRBG_MAX_ENTROPY];
+
+       /* entropy gathering function */
+       size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char *out,
+                               int entropy, size_t min_len, size_t max_len);
+
+       unsigned char nonce[DRBG_MAX_NONCE];
+
+       /* nonce gathering function */
+       size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char *out,
+                               int entropy, size_t min_len, size_t max_len);
+
+       };
+
+
+int fips_drbg_ctr_init(DRBG_CTX *dctx);
+int fips_drbg_hash_init(DRBG_CTX *dctx);