* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-/* This is a known-answer test for the DRBG-AES. The test vectors
- * and test structures are taken from libgcrypt's DRBG-AES implementation.
- * We differ however, in the fact we always discard an AES block when
- * the key is changed. That's why the 2nd and 3rd test vectors differ
- * from libgcrypt's vectors by 1.
+/* This is a known-answer test for the DRBG-CTR-AES.
*/
#include <config.h>
#include <drbg-aes.h>
#include <string.h>
+#include <stdio.h>
struct self_test_st {
- const uint8_t key[16];
- const uint8_t dt[16];
- const uint8_t v[16];
- const uint8_t r[3][16];
+ const uint8_t entropy[DRBG_AES_SEED_SIZE];
+ const char* pstring;
+ const uint8_t res[4][16];
};
struct priv_st {
struct drbg_aes_ctx *ctx;
- const uint8_t *dt;
- unsigned counter;
};
-static int get_dt(void *_priv, uint8_t dt[AES_BLOCK_SIZE])
-{
- struct priv_st *priv = _priv;
-
- memcpy(dt, priv->dt, AES_BLOCK_SIZE);
-
- dt[12] = priv->counter >> 24;
- dt[13] = priv->counter >> 16;
- dt[14] = priv->counter >> 8;
- dt[15] = priv->counter;
-
- priv->counter++;
-
- return 1;
-}
-
-/* Run a Know-Answer-Test using a dedicated test context. Note that
- we can't use the samples from the NISR RNGVS document because they
- don't take the requirement to throw away the first block and use
- that for duplicate check in account. Thus we made up our own test
- vectors. */
+/* Run a Know-Answer-Test using a dedicated test context. */
int drbg_aes_self_test(void)
{
static const struct self_test_st tv[] = {
- {
+ {
+ .entropy =
{0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42,
- 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe},
- {0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
+ 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe,
+ 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
+ 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe,
+ 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00},
- {0x52, 0x17, 0x8d, 0x29, 0xa2, 0xd5, 0x84, 0x12,
- 0x9d, 0x89, 0x9a, 0x45, 0x82, 0x02, 0xf7, 0x77},
- {
- {0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40,
- 0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3},
- {0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73,
- 0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa},
- {0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46,
- 0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d}
+ .pstring = "test test test",
+ .res = {
+ {0xb9, 0x4b, 0x00, 0x40, 0x5d, 0x10, 0x58, 0x84,
+ 0x97, 0x85, 0x5d, 0x49, 0x4f, 0x66, 0x4f, 0xa3},
+ {0xe8, 0x34, 0xae, 0x3e, 0x26, 0x36, 0xe0, 0x6e,
+ 0xb7, 0x15, 0x97, 0xc3, 0xf4, 0x7c, 0x98, 0xb0},
+ {0x8b, 0xf3, 0x85, 0xe9, 0x2b, 0x7f, 0x99, 0x7f,
+ 0x76, 0x97, 0x8b, 0x60, 0x25, 0x0a, 0x80, 0x60},
+ {0x4d, 0xfd, 0x8c, 0xc0, 0x5a, 0x20, 0xc8, 0x2d,
+ 0x5c, 0x33, 0x7f, 0x1c, 0x90, 0xa0, 0xe4, 0xa7}
}
},
- {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{
- {0xc8, 0xd1, 0xe5, 0x11, 0x59, 0x52, 0xf7, 0xfa,
- 0x37, 0x38, 0xb4, 0xc5, 0xce, 0xb2, 0xb0, 0x9a},
- {0x0d, 0x9c, 0xc5, 0x0d, 0x16, 0xe1, 0xbc, 0xed,
- 0xcf, 0x60, 0x62, 0x09, 0x9d, 0x20, 0x83, 0x7e},
- {0x6f, 0x39, 0xe0, 0xcb, 0x76, 0x7c, 0x0d, 0xeb,
- 0xff, 0xa0, 0x0e, 0x54, 0xe8, 0x9b, 0xa6, 0x79}
+ .entropy = {
+ 0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42,
+ 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe,
+ 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
+ 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe,
+ 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
+ 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00},
+ .pstring = "tost tost test",
+ .res = {
+ {0x12, 0x54, 0x35, 0x0f, 0x48, 0x7b, 0x6b, 0xed,
+ 0x2b, 0x3a, 0x2f, 0xa5, 0x53, 0x2c, 0x7b, 0xcb},
+ {0x39, 0x7a, 0x88, 0xd7, 0x56, 0xf2, 0xd0, 0x64,
+ 0x37, 0xa0, 0x8f, 0xf9, 0x64, 0xb2, 0x2b, 0x2b},
+ {0x4f, 0x12, 0x38, 0x71, 0x64, 0x90, 0xae, 0xb3,
+ 0xea, 0x1e, 0x01, 0xee, 0x2b, 0x03, 0x4a, 0xd3},
+ {0x9a, 0x0a, 0x9f, 0x42, 0x9b, 0x3f, 0xea, 0x63,
+ 0x84, 0xdb, 0xf2, 0x7b, 0x96, 0x38, 0x86, 0x41}
}
},
- {
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
- {0x80, 0x00, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03,
- 0xa0, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xa3, 0x23},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{
- {0x7a, 0x14, 0x76, 0x77, 0x95, 0x17, 0x7e, 0xc8,
- 0x92, 0xe8, 0xdd, 0x15, 0xcb, 0x1f, 0xbc, 0xb1},
- {0x25, 0x3e, 0x2e, 0xa2, 0x41, 0x1b, 0xdd, 0xf5,
- 0x21, 0x48, 0x41, 0x71, 0xb3, 0x8d, 0x2f, 0x4c},
- {0xc3, 0xa0, 0x56, 0xc4, 0x98, 0x56, 0xe7, 0xa5,
- 0x19, 0x42, 0x73, 0x43, 0xdc, 0x07, 0xe0, 0x7f}
+ .entropy = {
+ 0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40,
+ 0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3,
+ 0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73,
+ 0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa,
+ 0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46,
+ 0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d},
+ .pstring = "one two",
+ .res = {
+ {0x82, 0x6e, 0x20, 0xf2, 0x85, 0xc2, 0xf7, 0xc7,
+ 0x90, 0x1f, 0xff, 0x83, 0x6b, 0xaf, 0xaa, 0xd3},
+ {0x84, 0x4a, 0x39, 0x8a, 0xfe, 0xc0, 0x77, 0x30,
+ 0xf5, 0xed, 0x11, 0xa2, 0xd2, 0x20, 0xf5, 0x6c},
+ {0x83, 0x49, 0xd3, 0x41, 0x50, 0xd7, 0xc2, 0x81,
+ 0x1a, 0xdc, 0x42, 0x62, 0x49, 0xf5, 0xf9, 0x56},
+ {0xd2, 0xf2, 0x0d, 0xee, 0x9c, 0x63, 0xe6, 0xcc,
+ 0xc6, 0x41, 0x32, 0x27, 0xe0, 0xe0, 0x93, 0x85}
}
- }
+ },
};
unsigned i, j;
struct drbg_aes_ctx test_ctx;
for (i = 0; i < sizeof(tv) / sizeof(tv[0]); i++) {
/* Setup the key. */
- ret = drbg_aes_set_key(&test_ctx, 16, tv[i].key);
+ ret = drbg_aes_init(&test_ctx, DRBG_AES_SEED_SIZE, tv[i].entropy,
+ strlen(tv[i].pstring), (void*)tv[i].pstring);
if (ret == 0)
return 0;
- priv.dt = tv[i].dt;
- priv.counter =
- ((tv[i].dt[12] << 24) | (tv[i].dt[13] << 16) | (tv[i].
- dt[14]
- << 8) |
- (tv[i].dt[15]));
-
- /* Setup the seed. */
- drbg_aes_seed(&test_ctx, tv[i].v, &priv, get_dt);
-
if (drbg_aes_is_seeded(&test_ctx) == 0)
return 0;
return 0;
/* Compare it to the known value. */
- if (memcmp(result, tv[i].r[j], 16) != 0)
+ if (memcmp(result, tv[i].res[j], 16) != 0) {
return 0;
+ }
+ }
+
+ ret = drbg_aes_reseed(&test_ctx, DRBG_AES_SEED_SIZE, tv[i].entropy,
+ 0, NULL);
+ if (ret == 0)
+ return 0;
+
+ if (drbg_aes_random(&test_ctx, 16, result) == 0)
+ return 0;
+
+ if (memcmp(result, tv[i].res[3], 16) != 0) {
+ return 0;
}
}
#include <config.h>
#include <drbg-aes.h>
#include <nettle/memxor.h>
+#include <minmax.h>
#include <string.h>
#include <stdio.h>
int
-drbg_aes_set_key(struct drbg_aes_ctx *ctx, unsigned length,
- const uint8_t * key)
+drbg_aes_init(struct drbg_aes_ctx *ctx,
+ unsigned entropy_size, const uint8_t * entropy,
+ unsigned pstring_size, const uint8_t * pstring)
{
- if (length != 16 && length != 24 && length != 32)
- return 0;
-
- aes_set_encrypt_key(&ctx->key, length, key);
- ctx->seeded = 0;
- ctx->reseed_counter = 0;
- ctx->prev_block_present = 0;
+ memset(ctx, 0, sizeof(*ctx));
- return 1;
+ return drbg_aes_reseed(ctx, entropy_size, entropy,
+ pstring_size, pstring);
}
-/* Set's V value */
-void
-drbg_aes_seed(struct drbg_aes_ctx *ctx, const uint8_t seed[AES_BLOCK_SIZE],
- void *dt_priv, aes_dt dt_func)
+/* Sets V and key based on pdata */
+static void
+drbg_aes_update(struct drbg_aes_ctx *ctx,
+ unsigned pdata_size, const uint8_t * pdata)
{
- memcpy(ctx->v, seed, AES_BLOCK_SIZE);
-
- dt_func(dt_priv, ctx->dt);
-
- ctx->reseed_counter = 0;
+ unsigned len = 0;
+ uint8_t tmp[DRBG_AES_SEED_SIZE];
+ uint8_t *t = tmp;
+
+ while (len < DRBG_AES_SEED_SIZE) {
+ INCREMENT(sizeof(ctx->v), ctx->v);
+ aes_encrypt(&ctx->key, AES_BLOCK_SIZE, t, ctx->v);
+ t += AES_BLOCK_SIZE;
+ len += AES_BLOCK_SIZE;
+ }
+
+ memxor(tmp, pdata, DRBG_AES_SEED_SIZE);
+
+ aes_set_encrypt_key(&ctx->key, DRBG_AES_KEY_SIZE, tmp);
+
+ ctx->prev_block_present = 0;
+
+ memcpy(ctx->v, &tmp[AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+
+ ctx->reseed_counter = 1;
ctx->seeded = 1;
}
-
+
int
-drbg_aes_random(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst)
+drbg_aes_reseed(struct drbg_aes_ctx *ctx,
+ unsigned entropy_size, const uint8_t * entropy,
+ unsigned add_size, const uint8_t * add)
+{
+ uint8_t tmp[DRBG_AES_SEED_SIZE];
+ unsigned len = 0;
+
+ if (add_size > DRBG_AES_SEED_SIZE || entropy_size != DRBG_AES_SEED_SIZE)
+ return 0;
+
+ if (add_size <= DRBG_AES_SEED_SIZE && add_size > 0) {
+ memcpy(tmp, add, add_size);
+ len = add_size;
+ }
+
+ if (len != DRBG_AES_SEED_SIZE)
+ memset(&tmp[len], 0, DRBG_AES_SEED_SIZE - len);
+
+ memxor(tmp, entropy, entropy_size);
+
+ drbg_aes_update(ctx, DRBG_AES_SEED_SIZE, tmp);
+
+ return 1;
+}
+
+/* we don't use additional input */
+int drbg_aes_random(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst)
{
- uint8_t intermediate[AES_BLOCK_SIZE];
uint8_t tmp[AES_BLOCK_SIZE];
unsigned left;
/* Throw the first block generated. FIPS 140-2 requirement
*/
if (ctx->prev_block_present == 0) {
- /* I = AES_K(dt) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, intermediate, ctx->dt);
-
- /* tmp = I XOR V */
- memxor3(tmp, ctx->v, intermediate, AES_BLOCK_SIZE);
-
- /* dst = R = AES_K(I XOR V) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, ctx->prev_block,
- tmp);
-
- /* V = AES_K(R XOR I) */
- memxor3(tmp, ctx->prev_block, intermediate,
- AES_BLOCK_SIZE);
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, ctx->v, tmp);
+ INCREMENT(sizeof(ctx->v), ctx->v);
+ aes_encrypt(&ctx->key, AES_BLOCK_SIZE, ctx->prev_block, ctx->v);
ctx->prev_block_present = 1;
-
- INCREMENT(sizeof(ctx->dt), ctx->dt);
}
/* Perform the actual encryption */
for (left = length; left >= AES_BLOCK_SIZE;
left -= AES_BLOCK_SIZE, dst += AES_BLOCK_SIZE) {
- /* I = AES_K(dt) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, intermediate, ctx->dt);
-
- /* tmp = I XOR V */
- memxor3(tmp, ctx->v, intermediate, AES_BLOCK_SIZE);
-
- /* dst = R = AES_K(I XOR V) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, dst, tmp);
+ INCREMENT(sizeof(ctx->v), ctx->v);
+ aes_encrypt(&ctx->key, AES_BLOCK_SIZE, dst, ctx->v);
/* if detected loop */
if (memcmp(dst, ctx->prev_block, AES_BLOCK_SIZE) == 0)
return 0;
memcpy(ctx->prev_block, dst, AES_BLOCK_SIZE);
-
- /* V = AES_K(R XOR I) */
- memxor3(tmp, dst, intermediate, AES_BLOCK_SIZE);
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, ctx->v, tmp);
-
- INCREMENT(sizeof(ctx->dt), ctx->dt);
}
if (left > 0) { /* partial fill */
- /* I = AES_K(dt) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, intermediate, ctx->dt);
- memxor3(tmp, ctx->v, intermediate, AES_BLOCK_SIZE);
-
- /* tmp = R = AES_K(I XOR V) */
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, tmp, tmp);
+ INCREMENT(sizeof(ctx->v), ctx->v);
+ aes_encrypt(&ctx->key, AES_BLOCK_SIZE, tmp, ctx->v);
/* if detected loop */
if (memcmp(tmp, ctx->prev_block, AES_BLOCK_SIZE) == 0)
memcpy(ctx->prev_block, tmp, AES_BLOCK_SIZE);
memcpy(dst, tmp, left);
-
- /* V = AES_K(R XOR I) */
- memxor(tmp, intermediate, AES_BLOCK_SIZE);
- aes_encrypt(&ctx->key, AES_BLOCK_SIZE, ctx->v, tmp);
-
- INCREMENT(sizeof(ctx->dt), ctx->dt);
}
-
+
if (ctx->reseed_counter > DRBG_AES_RESEED_TIME)
return 0;
ctx->reseed_counter++;
-/* random-fips.c - FIPS140-2 random number generator
+/*
* Copyright (C) 2013 Red Hat
*
* This file is part of GnuTLS.
#include <locks.h>
#include <rnd-common.h>
+/* This provides a random generator for gnutls. It uses
+ * three instances of the DRBG-AES-CTR generator, one for
+ * each level of randomness. It uses /dev/urandom for their
+ * seeding.
+ */
+
#define RND_LOCK if (gnutls_mutex_lock(&rnd_mutex)!=0) abort()
#define RND_UNLOCK if (gnutls_mutex_unlock(&rnd_mutex)!=0) abort()
#endif
};
-static int _rngfips_reinit(struct fips_ctx* fctx);
+static int _rngfips_ctx_reinit(struct fips_ctx *fctx);
+static int _rngfips_ctx_init(struct fips_ctx *fctx);
-
-static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx* fctx,
- void *buffer, size_t length)
+static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
+ void *buffer, size_t length)
{
int ret;
if (ctx->reseed_counter > DRBG_AES_RESEED_TIME
#ifdef HAVE_GETPID
- || fctx->pid != getpid()
+ || fctx->pid != getpid()
#endif
- ) {
+ ) {
- ret = _rngfips_reinit(fctx);
+ ret = _rngfips_ctx_reinit(fctx);
if (ret < 0)
return gnutls_assert_val(ret);
}
return 0;
}
-static int _rngfips_reinit(struct fips_ctx* fctx)
+static int _rngfips_ctx_init(struct fips_ctx *fctx)
{
-int ret;
+ int ret;
/* strong */
- ret = drbg_generate_key(&fctx->strong_context);
+ ret = drbg_init(&fctx->strong_context);
if (ret < 0)
return gnutls_assert_val(ret);
-
- ret = drbg_reseed(&fctx->strong_context);
+
+ /* normal */
+ ret = drbg_init(&fctx->normal_context);
if (ret < 0)
return gnutls_assert_val(ret);
- /* normal */
- ret = drbg_generate_key(&fctx->normal_context);
+ /* nonce */
+ ret = drbg_init(&fctx->nonce_context);
if (ret < 0)
return gnutls_assert_val(ret);
-
- ret = drbg_reseed(&fctx->normal_context);
+
+#ifdef HAVE_GETPID
+ fctx->pid = getpid();
+#endif
+ return 0;
+}
+
+static int _rngfips_ctx_reinit(struct fips_ctx *fctx)
+{
+ int ret;
+
+ /* strong */
+ ret = drbg_reseed(&fctx->strong_context);
if (ret < 0)
return gnutls_assert_val(ret);
- /* nonce */
- ret = drbg_generate_key(&fctx->nonce_context);
+ /* normal */
+ ret = drbg_reseed(&fctx->normal_context);
if (ret < 0)
return gnutls_assert_val(ret);
-
+
+ /* nonce */
ret = drbg_reseed(&fctx->nonce_context);
if (ret < 0)
return gnutls_assert_val(ret);
#ifdef HAVE_GETPID
fctx->pid = getpid();
#endif
-
return 0;
}
/* Initialize this random subsystem. */
-static int _rngfips_init(void** _ctx)
+static int _rngfips_init(void **_ctx)
{
/* Basic initialization is required to initialize mutexes and
do a few checks on the implementation. */
- struct fips_ctx* ctx;
+ struct fips_ctx *ctx;
int ret;
ret = _rnd_system_entropy_init();
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _rngfips_reinit(ctx);
+ ret = _rngfips_ctx_init(ctx);
if (ret < 0)
return gnutls_assert_val(ret);
return 0;
}
-static int
-_rngfips_rnd(void *_ctx, int level, void *buffer, size_t length)
+static int _rngfips_rnd(void *_ctx, int level, void *buffer, size_t length)
{
-struct fips_ctx* ctx = _ctx;
-int ret;
+ struct fips_ctx *ctx = _ctx;
+ int ret;
RND_LOCK;
- switch(level) {
- case GNUTLS_RND_RANDOM:
- ret = get_random(&ctx->normal_context, ctx, buffer, length);
- case GNUTLS_RND_KEY:
- ret = get_random(&ctx->strong_context, ctx, buffer, length);
- default:
- ret = get_random(&ctx->nonce_context, ctx, buffer, length);
+ switch (level) {
+ case GNUTLS_RND_RANDOM:
+ ret = get_random(&ctx->normal_context, ctx, buffer, length);
+ case GNUTLS_RND_KEY:
+ ret = get_random(&ctx->strong_context, ctx, buffer, length);
+ default:
+ ret = get_random(&ctx->nonce_context, ctx, buffer, length);
}
RND_UNLOCK;
-
+
return ret;
}
-static void _rngfips_deinit(void * _ctx)
+static void _rngfips_deinit(void *_ctx)
{
- struct fips_ctx* ctx = _ctx;
+ struct fips_ctx *ctx = _ctx;
gnutls_mutex_deinit(&rnd_mutex);
rnd_mutex = NULL;
static int selftest_kat(void)
{
int ret;
-
+
RND_LOCK;
ret = drbg_aes_self_test();
RND_UNLOCK;
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
} else
_gnutls_debug_log("DRBG-AES self test succeeded\n");
-
+
return 0;
}