Message ID | d9f54bc1e51a49edd568a31ffa557dc0569d1028.1417951990.git.linux@horizon.com (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Herbert Xu |
Headers | show |
Am Sonntag, 7. Dezember 2014, 07:26:13 schrieb George Spelvin: Hi George, > Careful use of the other available buffers avoids the need for > these, shrinking the context by 32 bytes. > > Neither the debug output nor the FIPS-required anti-repetition check > are changed in the slightest. > > Signed-off-by: George Spelvin <linux@horizon.com> > --- > crypto/ansi_cprng.c | 50 ++++++++++++++++++++++++-------------------------- > 1 file changed, 24 insertions(+), 26 deletions(-) > > diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c > index 325aa727d..2edac42e 100644 > --- a/crypto/ansi_cprng.c > +++ b/crypto/ansi_cprng.c > @@ -37,19 +37,14 @@ > > /* > * Note: DT is our counter value > - * I is our intermediate value > * V is our seed vector > * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf > * for implementation details > */ > - > - > struct prng_context { > spinlock_t prng_lock; > unsigned char rand_data[DEFAULT_BLK_SZ]; > - unsigned char last_rand_data[DEFAULT_BLK_SZ]; > unsigned char DT[DEFAULT_BLK_SZ]; > - unsigned char I[DEFAULT_BLK_SZ]; > unsigned char V[DEFAULT_BLK_SZ]; > u32 rand_data_valid; > struct crypto_cipher *tfm; > @@ -97,27 +92,27 @@ static int _get_more_prng_bytes(struct prng_context > *ctx, int cont_test) > > /* > * Start by encrypting the counter value > - * This gives us an intermediate value I > + * This gives us an intermediate value I (stored in tmp) > */ > - memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ); > - crypto_cipher_encrypt_one(ctx->tfm, ctx->I, tmp); > - hexdump("I", ctx->I); > + crypto_cipher_encrypt_one(ctx->tfm, tmp, ctx->DT); > + hexdump("I", tmp); > > /* > - * Next xor I with our secret vector V > - * encrypt that result to obtain our > - * pseudo random data which we output > + * Next xor I with our secret vector V. Encrypt that result > + * to obtain our pseudo random data which we output. But > + * keep that output in ctx->V for the moment; we need the > + * previous rand_data for ons more thing. > */ > - xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ); > - hexdump("V^I", tmp); > - crypto_cipher_encrypt_one(ctx->tfm, ctx->rand_data, tmp); > - hexdump("R", ctx->rand_data); > + xor_vectors(tmp, ctx->V, ctx->V, DEFAULT_BLK_SZ); > + hexdump("V^I", ctx->V); > + crypto_cipher_encrypt_one(ctx->tfm, ctx->V, ctx->V); > + hexdump("R", ctx->V); > > /* > - * First check that we didn't produce the same > - * random data that we did last time around through this > + * Check that we didn't produce the same random data that we > + * did last time around. > */ > - if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) { > + if (!memcmp(ctx->V, ctx->rand_data, DEFAULT_BLK_SZ)) { Due to the huge number of diffs, I may have missed the following point. Therefore, please help me: NIST requires that ctx->rand_data must be "primed" before the first random number is returned to the aller (see FIPS 140-2 section 4.9.2). That means, the very first random number that was generated must go into what is now ctx- >rand_data, but shall not be returned to the caller. Only starting with the 2nd random number these values shall be returned to the caller. Where do I see that priming? Note, this priming should have an ability to be disabled for performing the CAVS tests as they (as stupid as it may sound) want the very first random number after the seeding. > if (cont_test) { > panic("cprng %p Failed repetition check!\n", ctx); > } > @@ -127,15 +122,19 @@ static int _get_more_prng_bytes(struct prng_context > *ctx, int cont_test) ctx->flags |= PRNG_NEED_RESET; > return -EINVAL; > } > - memcpy(ctx->last_rand_data, ctx->rand_data, DEFAULT_BLK_SZ); > + /* > + * Okay, the new data is okay, copy it to the buffer. > + */ > + memcpy(ctx->rand_data, ctx->V, DEFAULT_BLK_SZ); > > /* > - * Lastly xor the random data with I > - * and encrypt that to obtain a new secret vector V > + * Lastly xor the random data with I and encrypt that to obtain > + * a new secret vector V. > */ > - xor_vectors(ctx->rand_data, ctx->I, tmp, DEFAULT_BLK_SZ); > - hexdump("R^I", tmp); > - crypto_cipher_encrypt_one(ctx->tfm, ctx->V, tmp); > + xor_vectors(tmp, ctx->V, ctx->V, DEFAULT_BLK_SZ); > + hexdump("R^I", ctx->V); > + memzero_explicit(tmp, DEFAULT_BLK_SZ); > + crypto_cipher_encrypt_one(ctx->tfm, ctx->V, ctx->V); > hexdump("V'", ctx->V); > > /* > @@ -272,7 +271,6 @@ static int reset_prng_context(struct prng_context *ctx, > memset(ctx->DT, 0, DEFAULT_BLK_SZ); > > memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); > - memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); > > ctx->rand_data_valid = DEFAULT_BLK_SZ;
> Due to the huge number of diffs, I may have missed the following point. > Therefore, please help me: No problem at all! If you're doing me the kindness of actually reading and reviewing this, I have *lots* of time to act as a tour guide. I've just had my nose in this code, and your memory is presumably a bit rustier on some details, even if you understand the larger system better than I do. (I hope that English figure of speech isn't too obscure for you.) > Where do I see that priming? It's in the same place as it always has been: in fips_cprng_reset, just below the comment "this primes our continuity test". Patch 12 changes the priming call from get_prng_bytes to _get_more_prng_bytes in order to get rid of the "rdata" stack buffer. Patches 5 and 21 make inconsequential syntactic changes to the area. > Note, this priming should have an ability to be disabled for performing the > CAVS tests as they (as stupid as it may sound) want the very first random > number after the seeding. In this regard, I didn't touch the existing code, which distinguishes the functions "fips_cprng_reset" which does the priming, and "cprng_reset" which doesn't, and exports two struct crypto_alg interfaces to make them both available. -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 325aa727d..2edac42e 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -37,19 +37,14 @@ /* * Note: DT is our counter value - * I is our intermediate value * V is our seed vector * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf * for implementation details */ - - struct prng_context { spinlock_t prng_lock; unsigned char rand_data[DEFAULT_BLK_SZ]; - unsigned char last_rand_data[DEFAULT_BLK_SZ]; unsigned char DT[DEFAULT_BLK_SZ]; - unsigned char I[DEFAULT_BLK_SZ]; unsigned char V[DEFAULT_BLK_SZ]; u32 rand_data_valid; struct crypto_cipher *tfm; @@ -97,27 +92,27 @@ static int _get_more_prng_bytes(struct prng_context *ctx, int cont_test) /* * Start by encrypting the counter value - * This gives us an intermediate value I + * This gives us an intermediate value I (stored in tmp) */ - memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ); - crypto_cipher_encrypt_one(ctx->tfm, ctx->I, tmp); - hexdump("I", ctx->I); + crypto_cipher_encrypt_one(ctx->tfm, tmp, ctx->DT); + hexdump("I", tmp); /* - * Next xor I with our secret vector V - * encrypt that result to obtain our - * pseudo random data which we output + * Next xor I with our secret vector V. Encrypt that result + * to obtain our pseudo random data which we output. But + * keep that output in ctx->V for the moment; we need the + * previous rand_data for ons more thing. */ - xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ); - hexdump("V^I", tmp); - crypto_cipher_encrypt_one(ctx->tfm, ctx->rand_data, tmp); - hexdump("R", ctx->rand_data); + xor_vectors(tmp, ctx->V, ctx->V, DEFAULT_BLK_SZ); + hexdump("V^I", ctx->V); + crypto_cipher_encrypt_one(ctx->tfm, ctx->V, ctx->V); + hexdump("R", ctx->V); /* - * First check that we didn't produce the same - * random data that we did last time around through this + * Check that we didn't produce the same random data that we + * did last time around. */ - if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) { + if (!memcmp(ctx->V, ctx->rand_data, DEFAULT_BLK_SZ)) { if (cont_test) { panic("cprng %p Failed repetition check!\n", ctx); } @@ -127,15 +122,19 @@ static int _get_more_prng_bytes(struct prng_context *ctx, int cont_test) ctx->flags |= PRNG_NEED_RESET; return -EINVAL; } - memcpy(ctx->last_rand_data, ctx->rand_data, DEFAULT_BLK_SZ); + /* + * Okay, the new data is okay, copy it to the buffer. + */ + memcpy(ctx->rand_data, ctx->V, DEFAULT_BLK_SZ); /* - * Lastly xor the random data with I - * and encrypt that to obtain a new secret vector V + * Lastly xor the random data with I and encrypt that to obtain + * a new secret vector V. */ - xor_vectors(ctx->rand_data, ctx->I, tmp, DEFAULT_BLK_SZ); - hexdump("R^I", tmp); - crypto_cipher_encrypt_one(ctx->tfm, ctx->V, tmp); + xor_vectors(tmp, ctx->V, ctx->V, DEFAULT_BLK_SZ); + hexdump("R^I", ctx->V); + memzero_explicit(tmp, DEFAULT_BLK_SZ); + crypto_cipher_encrypt_one(ctx->tfm, ctx->V, ctx->V); hexdump("V'", ctx->V); /* @@ -272,7 +271,6 @@ static int reset_prng_context(struct prng_context *ctx, memset(ctx->DT, 0, DEFAULT_BLK_SZ); memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); - memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); ctx->rand_data_valid = DEFAULT_BLK_SZ;
Careful use of the other available buffers avoids the need for these, shrinking the context by 32 bytes. Neither the debug output nor the FIPS-required anti-repetition check are changed in the slightest. Signed-off-by: George Spelvin <linux@horizon.com> --- crypto/ansi_cprng.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-)