From patchwork Sun Dec 7 12:26:32 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: George Spelvin X-Patchwork-Id: 5451621 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Original-To: patchwork-linux-crypto@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 88ED8BEEA8 for ; Sun, 7 Dec 2014 12:27:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 98E7820154 for ; Sun, 7 Dec 2014 12:27:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ACBFF20155 for ; Sun, 7 Dec 2014 12:27:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753102AbaLGM1R (ORCPT ); Sun, 7 Dec 2014 07:27:17 -0500 Received: from ns.horizon.com ([71.41.210.147]:50263 "HELO ns.horizon.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1753211AbaLGM1H (ORCPT ); Sun, 7 Dec 2014 07:27:07 -0500 Received: (qmail 20897 invoked by uid 1000); 7 Dec 2014 07:26:57 -0500 From: George Spelvin To: nhorman@tuxdriver.com, linux-crypto@vger.kernel.org Cc: smueller@chronox.de, herbert@gondor.apana.org.au, linux@horizon.com Subject: [PATCH v2 24/25] crypto: ansi_cprng - Introduce non-deterministic mode Date: Sun, 7 Dec 2014 07:26:32 -0500 Message-Id: <915716fb77852c29ffb7f0b38b979b2fdd8ad405.1417951990.git.linux@horizon.com> X-Mailer: git-send-email 2.1.3 In-Reply-To: References: In-Reply-To: References: Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If DT is not provided, use timetamp data for the DT vector. This is permitted by the NIST spec (although the determinstic mode is still required for testing purposes), and encouraged by the X9.31 and X9.17 standards the RNG is adopted from. The question, however, is whether it's okay to have a "CPRNG" that's not deterministic. Signed-off-by: George Spelvin --- crypto/ansi_cprng.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 4d256d74..d39ce301 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -40,6 +40,7 @@ union cipherblock { */ #define PRNG_NEED_RESET 0x1 +#define PRNG_DETERMINISTIC 0x02 /* * Note: DT is our counter value @@ -47,10 +48,12 @@ union cipherblock { * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf * for implementation details. * - * Note that even though DT stands for "date/time", since this is a - * deterministic pseudo-random generator, it is a determinsitic counter, - * not a timestamp. Its function is not to inject seed entropy, but to - * ensure a long period in the output. + * Note that even though DT stands for "date/time", this generator may be + * operated in a fully determinsitic mode by specifying it in the initial + * seed. In this case, it does not inject any timestamp-based entropy, + * but operates as a simple counter to ensure a long period in the output. + * + * Both options are permitted by the NIST recommendation. */ struct prng_context { spinlock_t prng_lock; @@ -97,6 +100,16 @@ static int _get_more_prng_bytes(struct prng_context *ctx, bool cont_test) dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n", ctx); + /* + * get_random_int produces a result based on the system jiffies + * and random_get_entropy(), the highest-resolution timestamp + * available. This meets the spirit of the X9.17/X9.31 generation + * specifications, but it's masked by hashing, so it can't be used + * to leak information about /dev/random's seed material. + */ + if (!(ctx->flags & PRNG_DETERMINISTIC)) + ctx->DT.i[0] = get_random_int(); + hexdump("DT", &ctx->DT); hexdump("V", &ctx->V); @@ -150,12 +163,16 @@ static int _get_more_prng_bytes(struct prng_context *ctx, bool cont_test) /* * Now update our DT value */ - for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) { - ctx->DT.b[i] += 1; - if (ctx->DT.b[i] != 0) - break; + if (ctx->flags & PRNG_DETERMINISTIC) { + for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) { + ctx->DT.b[i] += 1; + if (ctx->DT.b[i] != 0) + break; + } + hexdump("DT'", &ctx->DT); + } else { + ctx->DT.i[0] = 0; /* Prevent backtracking */ } - hexdump("DT'", &ctx->DT); dbgprint("Returning new block for context %p\n", ctx); @@ -226,13 +243,24 @@ static int reset_prng_context(struct prng_context *ctx, const u8 *key, int ret; spin_lock_bh(&ctx->prng_lock); - ctx->flags |= PRNG_NEED_RESET; + ctx->flags = PRNG_NEED_RESET; ctx->rand_read_pos = DEFAULT_BLK_SZ; memset(ctx->rand_data.b, 0, DEFAULT_BLK_SZ); - if (!DT) - DT = ctx->rand_data.b; /* Use all-zeros if NULL */ + if (DT) { + ctx->flags |= PRNG_DETERMINISTIC; + memcpy(ctx->DT.b, DT, DEFAULT_BLK_SZ); + } else { + int i; + /* + * We will generate a fresh DT based on timestamp each time. + * Also pad rest of buffer with seed, on general principles. + * We reserve the first int for fresh entropy. + */ + for (i = 1; i < BLK_INTS; i++) + ctx->DT.i[i] = get_random_int(); + } memcpy(ctx->DT.b, DT, DEFAULT_BLK_SZ); memcpy(ctx->V.b, V, DEFAULT_BLK_SZ);