diff mbox

[v2,05/25] crypto: ansi_cprng - Eliminate ctx->I and ctx->last_rand_data

Message ID d9f54bc1e51a49edd568a31ffa557dc0569d1028.1417951990.git.linux@horizon.com (mailing list archive)
State RFC
Delegated to: Herbert Xu
Headers show

Commit Message

George Spelvin Dec. 7, 2014, 12:26 p.m. UTC
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(-)

Comments

Stephan Mueller Dec. 14, 2014, 11:50 a.m. UTC | #1
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;
George Spelvin Dec. 14, 2014, 7:22 p.m. UTC | #2
> 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 mbox

Patch

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;