2008-08-11 20:26:22

by Neil Horman

[permalink] [raw]
Subject: [PATCH] crypto: obscure state information on free

Patch to obscure state information on free in prng code. Keeps prying eyes from
sifting through your trash :)

Regards
Neil

Signed-off-by: Neil Horman <[email protected]>


prng.c | 1 +
1 file changed, 1 insertion(+)


diff --git a/crypto/prng.c b/crypto/prng.c
index b203093..fc6fa28 100644
--- a/crypto/prng.c
+++ b/crypto/prng.c
@@ -296,6 +296,7 @@ EXPORT_SYMBOL_GPL(alloc_prng_context);
void free_prng_context(struct prng_context *ctx)
{
crypto_free_cipher(ctx->tfm);
+ memset(ctx, 0, sizeof(struct prng_context));
kfree(ctx);
}
EXPORT_SYMBOL_GPL(free_prng_context);
--
/****************************************************
* Neil Horman <[email protected]>
* Software Engineer, Red Hat
****************************************************/


2008-08-14 11:51:45

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH] crypto: obscure state information on free

On Mon, Aug 11, 2008 at 04:26:07PM -0400, Neil Horman wrote:
> Patch to obscure state information on free in prng code. Keeps prying eyes from
> sifting through your trash :)

Thanks Neil. I've merged this with the original patch and made
some small changes on the API side, such as adding a reset helper
and adding a krng that just uses get_random_bytes.

Here is the final result against cryptodev-2.6. Let me know if
you're OK with it and I'll push it out.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 776f90d..15823a6 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -38,6 +38,10 @@ config CRYPTO_HASH
tristate
select CRYPTO_ALGAPI

+config CRYPTO_RNG
+ tristate
+ select CRYPTO_ALGAPI
+
config CRYPTO_MANAGER
tristate "Cryptographic algorithm manager"
select CRYPTO_AEAD
@@ -681,6 +685,18 @@ config CRYPTO_LZO
help
This is the LZO algorithm.

+comment "Random Number Generation"
+
+config CRYPTO_ANSI_CPRNG
+ tristate "Pseudo Random Number Generation for Cryptographic modules"
+ select CRYPTO_AES
+ select CRYPTO_CTR
+ select CRYPTO_RNG
+ help
+ This option enables the generic pseudo random number generator
+ for cryptographic modules. Uses the Algorithm specified in
+ ANSI X9.31 A.2.4
+
source "drivers/crypto/Kconfig"

endif # if CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index 59ab500..a14ed7d 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -24,6 +24,8 @@ obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o

cryptomgr-objs := algboss.o testmgr.o

+rng-objs := rngapi.o krng.o
+
obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
@@ -71,7 +73,8 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
-
+obj-$(CONFIG_CRYPTO_RNG) += rng.o
+obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o

#
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
new file mode 100644
index 0000000..c20642e
--- /dev/null
+++ b/crypto/ansi_cprng.c
@@ -0,0 +1,417 @@
+/*
+ * PRNG: Pseudo Random Number Generator
+ * Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
+ * AES 128 cipher
+ *
+ * (C) Neil Horman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * any later version.
+ *
+ *
+ */
+
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+#define DEFAULT_PRNG_KEY "0123456789abcdef"
+#define DEFAULT_PRNG_KSZ 16
+#define DEFAULT_BLK_SZ 16
+#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
+
+/*
+ * Flags for the prng_context flags field
+ */
+
+#define PRNG_FIXED_SIZE 0x1
+#define PRNG_NEED_RESET 0x2
+
+/*
+ * 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;
+ u32 flags;
+};
+
+static int dbg;
+
+static void hexdump(char *note, unsigned char *buf, unsigned int len)
+{
+ if (dbg) {
+ printk(KERN_CRIT "%s", note);
+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+ 16, 1,
+ buf, len, false);
+ }
+}
+
+#define dbgprint(format, args...) do {\
+if (dbg)\
+ printk(format, ##args);\
+} while (0)
+
+static void xor_vectors(unsigned char *in1, unsigned char *in2,
+ unsigned char *out, unsigned int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ out[i] = in1[i] ^ in2[i];
+
+}
+/*
+ * Returns DEFAULT_BLK_SZ bytes of random data per call
+ * returns 0 if generation succeded, <0 if something went wrong
+ */
+static int _get_more_prng_bytes(struct prng_context *ctx)
+{
+ int i;
+ unsigned char tmp[DEFAULT_BLK_SZ];
+ unsigned char *output = NULL;
+
+
+ dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",
+ ctx);
+
+ hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
+ hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
+ hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
+
+ /*
+ * This algorithm is a 3 stage state machine
+ */
+ for (i = 0; i < 3; i++) {
+
+ switch (i) {
+ case 0:
+ /*
+ * Start by encrypting the counter value
+ * This gives us an intermediate value I
+ */
+ memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
+ output = ctx->I;
+ hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
+ break;
+ case 1:
+
+ /*
+ * Next xor I with our secret vector V
+ * encrypt that result to obtain our
+ * pseudo random data which we output
+ */
+ xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
+ hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
+ output = ctx->rand_data;
+ break;
+ case 2:
+ /*
+ * First check that we didn't produce the same
+ * random data that we did last time around through this
+ */
+ if (!memcmp(ctx->rand_data, ctx->last_rand_data,
+ DEFAULT_BLK_SZ)) {
+ printk(KERN_ERR
+ "ctx %p Failed repetition check!\n",
+ ctx);
+ ctx->flags |= PRNG_NEED_RESET;
+ return -EINVAL;
+ }
+ memcpy(ctx->last_rand_data, ctx->rand_data,
+ DEFAULT_BLK_SZ);
+
+ /*
+ * 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);
+ output = ctx->V;
+ hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
+ break;
+ }
+
+
+ /* do the encryption */
+ crypto_cipher_encrypt_one(ctx->tfm, output, tmp);
+
+ }
+
+ /*
+ * Now update our DT value
+ */
+ for (i = 0; i < DEFAULT_BLK_SZ; i++) {
+ ctx->DT[i] += 1;
+ if (ctx->DT[i] != 0)
+ break;
+ }
+
+ dbgprint("Returning new block for context %p\n", ctx);
+ ctx->rand_data_valid = 0;
+
+ hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
+ hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
+ hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
+ hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
+
+ return 0;
+}
+
+/* Our exported functions */
+static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
+{
+ unsigned long flags;
+ unsigned char *ptr = buf;
+ unsigned int byte_count = (unsigned int)nbytes;
+ int err;
+
+
+ if (nbytes < 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ctx->prng_lock, flags);
+
+ err = -EINVAL;
+ if (ctx->flags & PRNG_NEED_RESET)
+ goto done;
+
+ /*
+ * If the FIXED_SIZE flag is on, only return whole blocks of
+ * pseudo random data
+ */
+ err = -EINVAL;
+ if (ctx->flags & PRNG_FIXED_SIZE) {
+ if (nbytes < DEFAULT_BLK_SZ)
+ goto done;
+ byte_count = DEFAULT_BLK_SZ;
+ }
+
+ err = byte_count;
+
+ dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",
+ byte_count, ctx);
+
+
+remainder:
+ if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
+ if (_get_more_prng_bytes(ctx) < 0) {
+ memset(buf, 0, nbytes);
+ err = -EINVAL;
+ goto done;
+ }
+ }
+
+ /*
+ * Copy up to the next whole block size
+ */
+ if (byte_count < DEFAULT_BLK_SZ) {
+ for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
+ ctx->rand_data_valid++) {
+ *ptr = ctx->rand_data[ctx->rand_data_valid];
+ ptr++;
+ byte_count--;
+ if (byte_count == 0)
+ goto done;
+ }
+ }
+
+ /*
+ * Now copy whole blocks
+ */
+ for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
+ if (_get_more_prng_bytes(ctx) < 0) {
+ memset(buf, 0, nbytes);
+ err = -EINVAL;
+ goto done;
+ }
+ memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
+ ctx->rand_data_valid += DEFAULT_BLK_SZ;
+ ptr += DEFAULT_BLK_SZ;
+ }
+
+ /*
+ * Now copy any extra partial data
+ */
+ if (byte_count)
+ goto remainder;
+
+done:
+ spin_unlock_irqrestore(&ctx->prng_lock, flags);
+ dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",
+ err, ctx);
+ return err;
+}
+
+static void free_prng_context(struct prng_context *ctx)
+{
+ crypto_free_cipher(ctx->tfm);
+}
+
+static int reset_prng_context(struct prng_context *ctx,
+ unsigned char *key, size_t klen,
+ unsigned char *V, unsigned char *DT)
+{
+ int ret;
+ int rc = -EINVAL;
+ unsigned char *prng_key;
+
+ spin_lock(&ctx->prng_lock);
+ ctx->flags |= PRNG_NEED_RESET;
+
+ prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY;
+
+ if (!key)
+ klen = DEFAULT_PRNG_KSZ;
+
+ if (V)
+ memcpy(ctx->V, V, DEFAULT_BLK_SZ);
+ else
+ memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ);
+
+ if (DT)
+ memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
+ else
+ memset(ctx->DT, 0, DEFAULT_BLK_SZ);
+
+ memset(ctx->rand_data, 0, DEFAULT_BLK_SZ);
+ memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ);
+
+ if (ctx->tfm)
+ crypto_free_cipher(ctx->tfm);
+
+ ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
+ if (IS_ERR(ctx->tfm)) {
+ dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
+ ctx);
+ ctx->tfm = NULL;
+ goto out;
+ }
+
+ ctx->rand_data_valid = DEFAULT_BLK_SZ;
+
+ ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen);
+ if (ret) {
+ dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
+ crypto_cipher_get_flags(ctx->tfm));
+ crypto_free_cipher(ctx->tfm);
+ goto out;
+ }
+
+ rc = 0;
+ ctx->flags &= ~PRNG_NEED_RESET;
+out:
+ spin_unlock(&ctx->prng_lock);
+
+ return rc;
+
+}
+
+static int cprng_init(struct crypto_tfm *tfm)
+{
+ struct prng_context *ctx = crypto_tfm_ctx(tfm);
+
+ spin_lock_init(&ctx->prng_lock);
+
+ return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL);
+}
+
+static void cprng_exit(struct crypto_tfm *tfm)
+{
+ free_prng_context(crypto_tfm_ctx(tfm));
+}
+
+static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
+ unsigned int dlen)
+{
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+
+ return get_prng_bytes(rdata, dlen, prng);
+}
+
+static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+ u8 *key = seed + DEFAULT_PRNG_KSZ;
+
+ if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
+ return -EINVAL;
+
+ reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL);
+
+ if (prng->flags & PRNG_NEED_RESET)
+ return -EINVAL;
+ return 0;
+}
+
+static struct crypto_alg rng_alg = {
+ .cra_name = "stdrng",
+ .cra_driver_name = "ansi_cprng",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_RNG,
+ .cra_ctxsize = sizeof(struct prng_context),
+ .cra_type = &crypto_rng_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(rng_alg.cra_list),
+ .cra_init = cprng_init,
+ .cra_exit = cprng_exit,
+ .cra_u = {
+ .rng = {
+ .rng_make_random = cprng_get_random,
+ .rng_reset = cprng_reset,
+ .seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ,
+ }
+ }
+};
+
+
+/* Module initalization */
+static int __init prng_mod_init(void)
+{
+ int ret = 0;
+
+ if (fips_enabled)
+ rng_alg.cra_priority += 200;
+
+ ret = crypto_register_alg(&rng_alg);
+
+ if (ret)
+ goto out;
+out:
+ return 0;
+}
+
+static void __exit prng_mod_fini(void)
+{
+ crypto_unregister_alg(&rng_alg);
+ return;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
+MODULE_AUTHOR("Neil Horman <[email protected]>");
+module_param(dbg, int, 0);
+MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
+module_init(prng_mod_init);
+module_exit(prng_mod_fini);
+MODULE_ALIAS("stdrng");
diff --git a/crypto/krng.c b/crypto/krng.c
new file mode 100644
index 0000000..8ef62a9
--- /dev/null
+++ b/crypto/krng.c
@@ -0,0 +1,66 @@
+/*
+ * RNG implementation using standard kernel RNG.
+ *
+ * Copyright (c) 2008 Herbert Xu <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * any later version.
+ *
+ */
+
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/random.h>
+
+static int krng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen)
+{
+ get_random_bytes(rdata, dlen);
+ return 0;
+}
+
+static int krng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ return 0;
+}
+
+static struct crypto_alg krng_alg = {
+ .cra_name = "stdrng",
+ .cra_driver_name = "krng",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_TYPE_RNG,
+ .cra_ctxsize = 0,
+ .cra_type = &crypto_rng_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(krng_alg.cra_list),
+ .cra_u = {
+ .rng = {
+ .rng_make_random = krng_get_random,
+ .rng_reset = krng_reset,
+ .seedsize = 0,
+ }
+ }
+};
+
+
+/* Module initalization */
+static int __init krng_mod_init(void)
+{
+ return crypto_register_alg(&krng_alg);
+}
+
+static void __exit krng_mod_fini(void)
+{
+ crypto_unregister_alg(&krng_alg);
+ return;
+}
+
+module_init(krng_mod_init);
+module_exit(krng_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Random Number Generator API");
+MODULE_ALIAS("stdrng");
diff --git a/crypto/rngapi.c b/crypto/rngapi.c
new file mode 100644
index 0000000..ea57697
--- /dev/null
+++ b/crypto/rngapi.c
@@ -0,0 +1,74 @@
+/*
+ * Cryptographic API.
+ *
+ * RNG operations.
+ *
+ * Copyright (c) 2008 Neil Horman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/internal/rng.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ u8 *buf = NULL;
+ int err;
+
+ if (!seed && slen) {
+ buf = kmalloc(slen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ get_random_bytes(buf, slen);
+ seed = buf;
+ }
+
+ err = crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
+
+ kfree(buf);
+ return err;
+}
+
+static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+ struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
+ struct rng_tfm *ops = &tfm->crt_rng;
+
+ ops->rng_gen_random = alg->rng_make_random;
+ ops->rng_reset = rngapi_reset;
+
+ return 0;
+}
+
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ seq_printf(m, "type : rng\n");
+ seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
+}
+
+static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
+{
+ return alg->cra_ctxsize;
+}
+
+const struct crypto_type crypto_rng_type = {
+ .ctxsize = crypto_rng_ctxsize,
+ .init = crypto_init_rng_ops,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_rng_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_rng_type);
diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h
new file mode 100644
index 0000000..8969733
--- /dev/null
+++ b/include/crypto/internal/rng.h
@@ -0,0 +1,26 @@
+/*
+ * RNG: Random Number Generator algorithms under the crypto API
+ *
+ * Copyright (c) 2008 Neil Horman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_RNG_H
+#define _CRYPTO_INTERNAL_RNG_H
+
+#include <crypto/algapi.h>
+#include <crypto/rng.h>
+
+extern const struct crypto_type crypto_rng_type;
+
+static inline void *crypto_rng_ctx(struct crypto_rng *tfm)
+{
+ return crypto_tfm_ctx(&tfm->base);
+}
+
+#endif
diff --git a/include/crypto/rng.h b/include/crypto/rng.h
new file mode 100644
index 0000000..7a33c63
--- /dev/null
+++ b/include/crypto/rng.h
@@ -0,0 +1,70 @@
+/*
+ * RNG: Random Number Generator algorithms under the crypto API
+ *
+ * Copyright (c) 2008 Neil Horman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_RNG_H
+#define _CRYPTO_RNG_H
+
+#include <linux/crypto.h>
+
+static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm)
+{
+ return (struct crypto_rng *)tfm;
+}
+
+static inline struct crypto_rng *crypto_alloc_rng(const char *alg_name)
+{
+ u32 type, mask;
+
+ mask = CRYPTO_ALG_TYPE_MASK;
+ type = CRYPTO_ALG_TYPE_RNG;
+
+ return __crypto_rng_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_rng_tfm(struct crypto_rng *tfm)
+{
+ return &tfm->base;
+}
+
+static inline struct rng_alg *crypto_rng_alg(struct crypto_rng *tfm)
+{
+ return &crypto_rng_tfm(tfm)->__crt_alg->cra_rng;
+}
+
+static inline struct rng_tfm *crypto_rng_crt(struct crypto_rng *tfm)
+{
+ return &crypto_rng_tfm(tfm)->crt_rng;
+}
+
+static inline void crypto_free_rng(struct crypto_rng *tfm)
+{
+ crypto_free_tfm(crypto_rng_tfm(tfm));
+}
+
+static inline int crypto_rng_get_bytes(struct crypto_rng *tfm,
+ u8 *rdata, unsigned int dlen)
+{
+ return crypto_rng_crt(tfm)->rng_gen_random(tfm, rdata, dlen);
+}
+
+static inline int crypto_rng_reset(struct crypto_rng *tfm,
+ u8 *seed, unsigned int slen)
+{
+ return crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
+}
+
+static inline int crypto_rng_seedsize(struct crypto_rng *tfm)
+{
+ return crypto_rng_alg(tfm)->seedsize;
+}
+
+#endif
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 81d994a..3d2317e 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -38,6 +38,7 @@
#define CRYPTO_ALG_TYPE_DIGEST 0x00000008
#define CRYPTO_ALG_TYPE_HASH 0x00000009
#define CRYPTO_ALG_TYPE_AHASH 0x0000000a
+#define CRYPTO_ALG_TYPE_RNG 0x0000000c

#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000c
@@ -113,6 +114,7 @@ struct crypto_aead;
struct crypto_blkcipher;
struct crypto_hash;
struct crypto_ahash;
+struct crypto_rng;
struct crypto_tfm;
struct crypto_type;
struct aead_givcrypt_request;
@@ -298,6 +300,15 @@ struct compress_alg {
unsigned int slen, u8 *dst, unsigned int *dlen);
};

+struct rng_alg {
+ int (*rng_make_random)(struct crypto_rng *tfm, u8 *rdata,
+ unsigned int dlen);
+ int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
+
+ unsigned int seedsize;
+};
+
+
#define cra_ablkcipher cra_u.ablkcipher
#define cra_aead cra_u.aead
#define cra_blkcipher cra_u.blkcipher
@@ -306,6 +317,7 @@ struct compress_alg {
#define cra_hash cra_u.hash
#define cra_ahash cra_u.ahash
#define cra_compress cra_u.compress
+#define cra_rng cra_u.rng

struct crypto_alg {
struct list_head cra_list;
@@ -333,6 +345,7 @@ struct crypto_alg {
struct hash_alg hash;
struct ahash_alg ahash;
struct compress_alg compress;
+ struct rng_alg rng;
} cra_u;

int (*cra_init)(struct crypto_tfm *tfm);
@@ -438,6 +451,12 @@ struct compress_tfm {
u8 *dst, unsigned int *dlen);
};

+struct rng_tfm {
+ int (*rng_gen_random)(struct crypto_rng *tfm, u8 *rdata,
+ unsigned int dlen);
+ int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
+};
+
#define crt_ablkcipher crt_u.ablkcipher
#define crt_aead crt_u.aead
#define crt_blkcipher crt_u.blkcipher
@@ -445,6 +464,7 @@ struct compress_tfm {
#define crt_hash crt_u.hash
#define crt_ahash crt_u.ahash
#define crt_compress crt_u.compress
+#define crt_rng crt_u.rng

struct crypto_tfm {

@@ -458,6 +478,7 @@ struct crypto_tfm {
struct hash_tfm hash;
struct ahash_tfm ahash;
struct compress_tfm compress;
+ struct rng_tfm rng;
} crt_u;

struct crypto_alg *__crt_alg;
@@ -489,6 +510,10 @@ struct crypto_hash {
struct crypto_tfm base;
};

+struct crypto_rng {
+ struct crypto_tfm base;
+};
+
enum {
CRYPTOA_UNSPEC,
CRYPTOA_ALG,

2008-08-14 12:21:59

by Neil Horman

[permalink] [raw]
Subject: Re: [PATCH] crypto: obscure state information on free

On Thu, Aug 14, 2008 at 09:51:38PM +1000, Herbert Xu wrote:
> On Mon, Aug 11, 2008 at 04:26:07PM -0400, Neil Horman wrote:
> > Patch to obscure state information on free in prng code. Keeps prying eyes from
> > sifting through your trash :)
>
> Thanks Neil. I've merged this with the original patch and made
> some small changes on the API side, such as adding a reset helper
> and adding a krng that just uses get_random_bytes.
>
> Here is the final result against cryptodev-2.6. Let me know if
> you're OK with it and I'll push it out.
>
> Cheers,


Looks great to me. Thanks Herbert!

Best
Neil

> --
> Visit Openswan at http://www.openswan.org/
> Email: Herbert Xu ~{PmV>HI~} <[email protected]>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
> --
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 776f90d..15823a6 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -38,6 +38,10 @@ config CRYPTO_HASH
> tristate
> select CRYPTO_ALGAPI
>
> +config CRYPTO_RNG
> + tristate
> + select CRYPTO_ALGAPI
> +
> config CRYPTO_MANAGER
> tristate "Cryptographic algorithm manager"
> select CRYPTO_AEAD
> @@ -681,6 +685,18 @@ config CRYPTO_LZO
> help
> This is the LZO algorithm.
>
> +comment "Random Number Generation"
> +
> +config CRYPTO_ANSI_CPRNG
> + tristate "Pseudo Random Number Generation for Cryptographic modules"
> + select CRYPTO_AES
> + select CRYPTO_CTR
> + select CRYPTO_RNG
> + help
> + This option enables the generic pseudo random number generator
> + for cryptographic modules. Uses the Algorithm specified in
> + ANSI X9.31 A.2.4
> +
> source "drivers/crypto/Kconfig"
>
> endif # if CRYPTO
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 59ab500..a14ed7d 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -24,6 +24,8 @@ obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
>
> cryptomgr-objs := algboss.o testmgr.o
>
> +rng-objs := rngapi.o krng.o
> +
> obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
> obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
> obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
> @@ -71,7 +73,8 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
> obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
> obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
> obj-$(CONFIG_CRYPTO_LZO) += lzo.o
> -
> +obj-$(CONFIG_CRYPTO_RNG) += rng.o
> +obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
> obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
>
> #
> diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
> new file mode 100644
> index 0000000..c20642e
> --- /dev/null
> +++ b/crypto/ansi_cprng.c
> @@ -0,0 +1,417 @@
> +/*
> + * PRNG: Pseudo Random Number Generator
> + * Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
> + * AES 128 cipher
> + *
> + * (C) Neil Horman <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * any later version.
> + *
> + *
> + */
> +
> +#include <crypto/internal/rng.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/string.h>
> +
> +#include "internal.h"
> +
> +#define DEFAULT_PRNG_KEY "0123456789abcdef"
> +#define DEFAULT_PRNG_KSZ 16
> +#define DEFAULT_BLK_SZ 16
> +#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
> +
> +/*
> + * Flags for the prng_context flags field
> + */
> +
> +#define PRNG_FIXED_SIZE 0x1
> +#define PRNG_NEED_RESET 0x2
> +
> +/*
> + * 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;
> + u32 flags;
> +};
> +
> +static int dbg;
> +
> +static void hexdump(char *note, unsigned char *buf, unsigned int len)
> +{
> + if (dbg) {
> + printk(KERN_CRIT "%s", note);
> + print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
> + 16, 1,
> + buf, len, false);
> + }
> +}
> +
> +#define dbgprint(format, args...) do {\
> +if (dbg)\
> + printk(format, ##args);\
> +} while (0)
> +
> +static void xor_vectors(unsigned char *in1, unsigned char *in2,
> + unsigned char *out, unsigned int size)
> +{
> + int i;
> +
> + for (i = 0; i < size; i++)
> + out[i] = in1[i] ^ in2[i];
> +
> +}
> +/*
> + * Returns DEFAULT_BLK_SZ bytes of random data per call
> + * returns 0 if generation succeded, <0 if something went wrong
> + */
> +static int _get_more_prng_bytes(struct prng_context *ctx)
> +{
> + int i;
> + unsigned char tmp[DEFAULT_BLK_SZ];
> + unsigned char *output = NULL;
> +
> +
> + dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",
> + ctx);
> +
> + hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
> + hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
> + hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
> +
> + /*
> + * This algorithm is a 3 stage state machine
> + */
> + for (i = 0; i < 3; i++) {
> +
> + switch (i) {
> + case 0:
> + /*
> + * Start by encrypting the counter value
> + * This gives us an intermediate value I
> + */
> + memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
> + output = ctx->I;
> + hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
> + break;
> + case 1:
> +
> + /*
> + * Next xor I with our secret vector V
> + * encrypt that result to obtain our
> + * pseudo random data which we output
> + */
> + xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
> + hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
> + output = ctx->rand_data;
> + break;
> + case 2:
> + /*
> + * First check that we didn't produce the same
> + * random data that we did last time around through this
> + */
> + if (!memcmp(ctx->rand_data, ctx->last_rand_data,
> + DEFAULT_BLK_SZ)) {
> + printk(KERN_ERR
> + "ctx %p Failed repetition check!\n",
> + ctx);
> + ctx->flags |= PRNG_NEED_RESET;
> + return -EINVAL;
> + }
> + memcpy(ctx->last_rand_data, ctx->rand_data,
> + DEFAULT_BLK_SZ);
> +
> + /*
> + * 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);
> + output = ctx->V;
> + hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
> + break;
> + }
> +
> +
> + /* do the encryption */
> + crypto_cipher_encrypt_one(ctx->tfm, output, tmp);
> +
> + }
> +
> + /*
> + * Now update our DT value
> + */
> + for (i = 0; i < DEFAULT_BLK_SZ; i++) {
> + ctx->DT[i] += 1;
> + if (ctx->DT[i] != 0)
> + break;
> + }
> +
> + dbgprint("Returning new block for context %p\n", ctx);
> + ctx->rand_data_valid = 0;
> +
> + hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
> + hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
> + hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
> + hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
> +
> + return 0;
> +}
> +
> +/* Our exported functions */
> +static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
> +{
> + unsigned long flags;
> + unsigned char *ptr = buf;
> + unsigned int byte_count = (unsigned int)nbytes;
> + int err;
> +
> +
> + if (nbytes < 0)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&ctx->prng_lock, flags);
> +
> + err = -EINVAL;
> + if (ctx->flags & PRNG_NEED_RESET)
> + goto done;
> +
> + /*
> + * If the FIXED_SIZE flag is on, only return whole blocks of
> + * pseudo random data
> + */
> + err = -EINVAL;
> + if (ctx->flags & PRNG_FIXED_SIZE) {
> + if (nbytes < DEFAULT_BLK_SZ)
> + goto done;
> + byte_count = DEFAULT_BLK_SZ;
> + }
> +
> + err = byte_count;
> +
> + dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",
> + byte_count, ctx);
> +
> +
> +remainder:
> + if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
> + if (_get_more_prng_bytes(ctx) < 0) {
> + memset(buf, 0, nbytes);
> + err = -EINVAL;
> + goto done;
> + }
> + }
> +
> + /*
> + * Copy up to the next whole block size
> + */
> + if (byte_count < DEFAULT_BLK_SZ) {
> + for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
> + ctx->rand_data_valid++) {
> + *ptr = ctx->rand_data[ctx->rand_data_valid];
> + ptr++;
> + byte_count--;
> + if (byte_count == 0)
> + goto done;
> + }
> + }
> +
> + /*
> + * Now copy whole blocks
> + */
> + for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
> + if (_get_more_prng_bytes(ctx) < 0) {
> + memset(buf, 0, nbytes);
> + err = -EINVAL;
> + goto done;
> + }
> + memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
> + ctx->rand_data_valid += DEFAULT_BLK_SZ;
> + ptr += DEFAULT_BLK_SZ;
> + }
> +
> + /*
> + * Now copy any extra partial data
> + */
> + if (byte_count)
> + goto remainder;
> +
> +done:
> + spin_unlock_irqrestore(&ctx->prng_lock, flags);
> + dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",
> + err, ctx);
> + return err;
> +}
> +
> +static void free_prng_context(struct prng_context *ctx)
> +{
> + crypto_free_cipher(ctx->tfm);
> +}
> +
> +static int reset_prng_context(struct prng_context *ctx,
> + unsigned char *key, size_t klen,
> + unsigned char *V, unsigned char *DT)
> +{
> + int ret;
> + int rc = -EINVAL;
> + unsigned char *prng_key;
> +
> + spin_lock(&ctx->prng_lock);
> + ctx->flags |= PRNG_NEED_RESET;
> +
> + prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY;
> +
> + if (!key)
> + klen = DEFAULT_PRNG_KSZ;
> +
> + if (V)
> + memcpy(ctx->V, V, DEFAULT_BLK_SZ);
> + else
> + memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ);
> +
> + if (DT)
> + memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
> + else
> + memset(ctx->DT, 0, DEFAULT_BLK_SZ);
> +
> + memset(ctx->rand_data, 0, DEFAULT_BLK_SZ);
> + memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ);
> +
> + if (ctx->tfm)
> + crypto_free_cipher(ctx->tfm);
> +
> + ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
> + if (IS_ERR(ctx->tfm)) {
> + dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
> + ctx);
> + ctx->tfm = NULL;
> + goto out;
> + }
> +
> + ctx->rand_data_valid = DEFAULT_BLK_SZ;
> +
> + ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen);
> + if (ret) {
> + dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
> + crypto_cipher_get_flags(ctx->tfm));
> + crypto_free_cipher(ctx->tfm);
> + goto out;
> + }
> +
> + rc = 0;
> + ctx->flags &= ~PRNG_NEED_RESET;
> +out:
> + spin_unlock(&ctx->prng_lock);
> +
> + return rc;
> +
> +}
> +
> +static int cprng_init(struct crypto_tfm *tfm)
> +{
> + struct prng_context *ctx = crypto_tfm_ctx(tfm);
> +
> + spin_lock_init(&ctx->prng_lock);
> +
> + return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL);
> +}
> +
> +static void cprng_exit(struct crypto_tfm *tfm)
> +{
> + free_prng_context(crypto_tfm_ctx(tfm));
> +}
> +
> +static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
> + unsigned int dlen)
> +{
> + struct prng_context *prng = crypto_rng_ctx(tfm);
> +
> + return get_prng_bytes(rdata, dlen, prng);
> +}
> +
> +static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
> +{
> + struct prng_context *prng = crypto_rng_ctx(tfm);
> + u8 *key = seed + DEFAULT_PRNG_KSZ;
> +
> + if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
> + return -EINVAL;
> +
> + reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL);
> +
> + if (prng->flags & PRNG_NEED_RESET)
> + return -EINVAL;
> + return 0;
> +}
> +
> +static struct crypto_alg rng_alg = {
> + .cra_name = "stdrng",
> + .cra_driver_name = "ansi_cprng",
> + .cra_priority = 100,
> + .cra_flags = CRYPTO_ALG_TYPE_RNG,
> + .cra_ctxsize = sizeof(struct prng_context),
> + .cra_type = &crypto_rng_type,
> + .cra_module = THIS_MODULE,
> + .cra_list = LIST_HEAD_INIT(rng_alg.cra_list),
> + .cra_init = cprng_init,
> + .cra_exit = cprng_exit,
> + .cra_u = {
> + .rng = {
> + .rng_make_random = cprng_get_random,
> + .rng_reset = cprng_reset,
> + .seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ,
> + }
> + }
> +};
> +
> +
> +/* Module initalization */
> +static int __init prng_mod_init(void)
> +{
> + int ret = 0;
> +
> + if (fips_enabled)
> + rng_alg.cra_priority += 200;
> +
> + ret = crypto_register_alg(&rng_alg);
> +
> + if (ret)
> + goto out;
> +out:
> + return 0;
> +}
> +
> +static void __exit prng_mod_fini(void)
> +{
> + crypto_unregister_alg(&rng_alg);
> + return;
> +}
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
> +MODULE_AUTHOR("Neil Horman <[email protected]>");
> +module_param(dbg, int, 0);
> +MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
> +module_init(prng_mod_init);
> +module_exit(prng_mod_fini);
> +MODULE_ALIAS("stdrng");
> diff --git a/crypto/krng.c b/crypto/krng.c
> new file mode 100644
> index 0000000..8ef62a9
> --- /dev/null
> +++ b/crypto/krng.c
> @@ -0,0 +1,66 @@
> +/*
> + * RNG implementation using standard kernel RNG.
> + *
> + * Copyright (c) 2008 Herbert Xu <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * any later version.
> + *
> + */
> +
> +#include <crypto/internal/rng.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/random.h>
> +
> +static int krng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen)
> +{
> + get_random_bytes(rdata, dlen);
> + return 0;
> +}
> +
> +static int krng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
> +{
> + return 0;
> +}
> +
> +static struct crypto_alg krng_alg = {
> + .cra_name = "stdrng",
> + .cra_driver_name = "krng",
> + .cra_priority = 200,
> + .cra_flags = CRYPTO_ALG_TYPE_RNG,
> + .cra_ctxsize = 0,
> + .cra_type = &crypto_rng_type,
> + .cra_module = THIS_MODULE,
> + .cra_list = LIST_HEAD_INIT(krng_alg.cra_list),
> + .cra_u = {
> + .rng = {
> + .rng_make_random = krng_get_random,
> + .rng_reset = krng_reset,
> + .seedsize = 0,
> + }
> + }
> +};
> +
> +
> +/* Module initalization */
> +static int __init krng_mod_init(void)
> +{
> + return crypto_register_alg(&krng_alg);
> +}
> +
> +static void __exit krng_mod_fini(void)
> +{
> + crypto_unregister_alg(&krng_alg);
> + return;
> +}
> +
> +module_init(krng_mod_init);
> +module_exit(krng_mod_fini);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Random Number Generator API");
> +MODULE_ALIAS("stdrng");
> diff --git a/crypto/rngapi.c b/crypto/rngapi.c
> new file mode 100644
> index 0000000..ea57697
> --- /dev/null
> +++ b/crypto/rngapi.c
> @@ -0,0 +1,74 @@
> +/*
> + * Cryptographic API.
> + *
> + * RNG operations.
> + *
> + * Copyright (c) 2008 Neil Horman <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + *
> + */
> +
> +#include <crypto/internal/rng.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/random.h>
> +#include <linux/seq_file.h>
> +#include <linux/string.h>
> +
> +static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
> +{
> + u8 *buf = NULL;
> + int err;
> +
> + if (!seed && slen) {
> + buf = kmalloc(slen, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + get_random_bytes(buf, slen);
> + seed = buf;
> + }
> +
> + err = crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
> +
> + kfree(buf);
> + return err;
> +}
> +
> +static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
> +{
> + struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
> + struct rng_tfm *ops = &tfm->crt_rng;
> +
> + ops->rng_gen_random = alg->rng_make_random;
> + ops->rng_reset = rngapi_reset;
> +
> + return 0;
> +}
> +
> +static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
> + __attribute__ ((unused));
> +static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
> +{
> + seq_printf(m, "type : rng\n");
> + seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
> +}
> +
> +static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
> + u32 mask)
> +{
> + return alg->cra_ctxsize;
> +}
> +
> +const struct crypto_type crypto_rng_type = {
> + .ctxsize = crypto_rng_ctxsize,
> + .init = crypto_init_rng_ops,
> +#ifdef CONFIG_PROC_FS
> + .show = crypto_rng_show,
> +#endif
> +};
> +EXPORT_SYMBOL_GPL(crypto_rng_type);
> diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h
> new file mode 100644
> index 0000000..8969733
> --- /dev/null
> +++ b/include/crypto/internal/rng.h
> @@ -0,0 +1,26 @@
> +/*
> + * RNG: Random Number Generator algorithms under the crypto API
> + *
> + * Copyright (c) 2008 Neil Horman <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + *
> + */
> +
> +#ifndef _CRYPTO_INTERNAL_RNG_H
> +#define _CRYPTO_INTERNAL_RNG_H
> +
> +#include <crypto/algapi.h>
> +#include <crypto/rng.h>
> +
> +extern const struct crypto_type crypto_rng_type;
> +
> +static inline void *crypto_rng_ctx(struct crypto_rng *tfm)
> +{
> + return crypto_tfm_ctx(&tfm->base);
> +}
> +
> +#endif
> diff --git a/include/crypto/rng.h b/include/crypto/rng.h
> new file mode 100644
> index 0000000..7a33c63
> --- /dev/null
> +++ b/include/crypto/rng.h
> @@ -0,0 +1,70 @@
> +/*
> + * RNG: Random Number Generator algorithms under the crypto API
> + *
> + * Copyright (c) 2008 Neil Horman <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + *
> + */
> +
> +#ifndef _CRYPTO_RNG_H
> +#define _CRYPTO_RNG_H
> +
> +#include <linux/crypto.h>
> +
> +static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm)
> +{
> + return (struct crypto_rng *)tfm;
> +}
> +
> +static inline struct crypto_rng *crypto_alloc_rng(const char *alg_name)
> +{
> + u32 type, mask;
> +
> + mask = CRYPTO_ALG_TYPE_MASK;
> + type = CRYPTO_ALG_TYPE_RNG;
> +
> + return __crypto_rng_cast(crypto_alloc_base(alg_name, type, mask));
> +}
> +
> +static inline struct crypto_tfm *crypto_rng_tfm(struct crypto_rng *tfm)
> +{
> + return &tfm->base;
> +}
> +
> +static inline struct rng_alg *crypto_rng_alg(struct crypto_rng *tfm)
> +{
> + return &crypto_rng_tfm(tfm)->__crt_alg->cra_rng;
> +}
> +
> +static inline struct rng_tfm *crypto_rng_crt(struct crypto_rng *tfm)
> +{
> + return &crypto_rng_tfm(tfm)->crt_rng;
> +}
> +
> +static inline void crypto_free_rng(struct crypto_rng *tfm)
> +{
> + crypto_free_tfm(crypto_rng_tfm(tfm));
> +}
> +
> +static inline int crypto_rng_get_bytes(struct crypto_rng *tfm,
> + u8 *rdata, unsigned int dlen)
> +{
> + return crypto_rng_crt(tfm)->rng_gen_random(tfm, rdata, dlen);
> +}
> +
> +static inline int crypto_rng_reset(struct crypto_rng *tfm,
> + u8 *seed, unsigned int slen)
> +{
> + return crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
> +}
> +
> +static inline int crypto_rng_seedsize(struct crypto_rng *tfm)
> +{
> + return crypto_rng_alg(tfm)->seedsize;
> +}
> +
> +#endif
> diff --git a/include/linux/crypto.h b/include/linux/crypto.h
> index 81d994a..3d2317e 100644
> --- a/include/linux/crypto.h
> +++ b/include/linux/crypto.h
> @@ -38,6 +38,7 @@
> #define CRYPTO_ALG_TYPE_DIGEST 0x00000008
> #define CRYPTO_ALG_TYPE_HASH 0x00000009
> #define CRYPTO_ALG_TYPE_AHASH 0x0000000a
> +#define CRYPTO_ALG_TYPE_RNG 0x0000000c
>
> #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
> #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000c
> @@ -113,6 +114,7 @@ struct crypto_aead;
> struct crypto_blkcipher;
> struct crypto_hash;
> struct crypto_ahash;
> +struct crypto_rng;
> struct crypto_tfm;
> struct crypto_type;
> struct aead_givcrypt_request;
> @@ -298,6 +300,15 @@ struct compress_alg {
> unsigned int slen, u8 *dst, unsigned int *dlen);
> };
>
> +struct rng_alg {
> + int (*rng_make_random)(struct crypto_rng *tfm, u8 *rdata,
> + unsigned int dlen);
> + int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
> +
> + unsigned int seedsize;
> +};
> +
> +
> #define cra_ablkcipher cra_u.ablkcipher
> #define cra_aead cra_u.aead
> #define cra_blkcipher cra_u.blkcipher
> @@ -306,6 +317,7 @@ struct compress_alg {
> #define cra_hash cra_u.hash
> #define cra_ahash cra_u.ahash
> #define cra_compress cra_u.compress
> +#define cra_rng cra_u.rng
>
> struct crypto_alg {
> struct list_head cra_list;
> @@ -333,6 +345,7 @@ struct crypto_alg {
> struct hash_alg hash;
> struct ahash_alg ahash;
> struct compress_alg compress;
> + struct rng_alg rng;
> } cra_u;
>
> int (*cra_init)(struct crypto_tfm *tfm);
> @@ -438,6 +451,12 @@ struct compress_tfm {
> u8 *dst, unsigned int *dlen);
> };
>
> +struct rng_tfm {
> + int (*rng_gen_random)(struct crypto_rng *tfm, u8 *rdata,
> + unsigned int dlen);
> + int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);
> +};
> +
> #define crt_ablkcipher crt_u.ablkcipher
> #define crt_aead crt_u.aead
> #define crt_blkcipher crt_u.blkcipher
> @@ -445,6 +464,7 @@ struct compress_tfm {
> #define crt_hash crt_u.hash
> #define crt_ahash crt_u.ahash
> #define crt_compress crt_u.compress
> +#define crt_rng crt_u.rng
>
> struct crypto_tfm {
>
> @@ -458,6 +478,7 @@ struct crypto_tfm {
> struct hash_tfm hash;
> struct ahash_tfm ahash;
> struct compress_tfm compress;
> + struct rng_tfm rng;
> } crt_u;
>
> struct crypto_alg *__crt_alg;
> @@ -489,6 +510,10 @@ struct crypto_hash {
> struct crypto_tfm base;
> };
>
> +struct crypto_rng {
> + struct crypto_tfm base;
> +};
> +
> enum {
> CRYPTOA_UNSPEC,
> CRYPTOA_ALG,

--
/***************************************************
*Neil Horman
*[email protected]
*gpg keyid: 1024D / 0x92A74FA1
*http://pgp.mit.edu
***************************************************/

2008-08-14 12:23:35

by Herbert Xu

[permalink] [raw]
Subject: crypto: skcipher - Use RNG interface instead of get_random_bytes

On Thu, Aug 14, 2008 at 09:51:37PM +1000, Herbert Xu wrote:
>
> Here is the final result against cryptodev-2.6. Let me know if
> you're OK with it and I'll push it out.

And here is the IV generator patch on top.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
commit 560a63d94d36641c83a8f533ed87bab95f6298bb
Author: Herbert Xu <[email protected]>
Date: Thu Aug 14 22:21:31 2008 +1000

crypto: skcipher - Use RNG interface instead of get_random_bytes

This patch makes the IV generators use the new RNG interface so
that the user can pick an RNG other than the default get_random_bytes.

Signed-off-by: Herbert Xu <[email protected]>

diff --git a/crypto/Kconfig b/crypto/Kconfig
index b00860f..a985065 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -33,6 +33,7 @@ config CRYPTO_AEAD
config CRYPTO_BLKCIPHER
tristate
select CRYPTO_ALGAPI
+ select CRYPTO_RNG

config CRYPTO_HASH
tristate
@@ -117,6 +118,7 @@ config CRYPTO_SEQIV
tristate "Sequence Number IV Generator"
select CRYPTO_AEAD
select CRYPTO_BLKCIPHER
+ select CRYPTO_RNG
help
This IV generator generates an IV based on a sequence number by
xoring it with a salt. This algorithm is mainly useful for CTR
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index 9affade..330b5e4 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -14,11 +14,11 @@
*/

#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/workqueue.h>
@@ -44,6 +44,8 @@ struct async_chainiv_ctx {
char iv[];
};

+static struct crypto_rng *rng;
+
static int chainiv_givencrypt(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
@@ -83,6 +85,7 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt !=
@@ -90,11 +93,15 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
- get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(rng, ctx->iv,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return chainiv_givencrypt(req);
}

@@ -203,6 +210,7 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
goto out;
@@ -212,11 +220,15 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
- get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(rng, ctx->iv,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
clear_bit(CHAINIV_STATE_INUSE, &ctx->state);

+ if (err)
+ return err;
+
out:
return async_chainiv_givencrypt(req);
}
@@ -322,10 +334,30 @@ static struct crypto_template chainiv_tmpl = {

int __init chainiv_module_init(void)
{
- return crypto_register_template(&chainiv_tmpl);
+ int err;
+
+ rng = crypto_alloc_rng("stdrng", 0, 0);
+ if (IS_ERR(rng))
+ return PTR_ERR(rng);
+
+ err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+ if (err)
+ goto free_rng;
+
+ err = crypto_register_template(&chainiv_tmpl);
+ if (err)
+ goto free_rng;
+
+out:
+ return err;
+
+free_rng:
+ crypto_free_rng(rng);
+ goto out;
}

void chainiv_module_exit(void)
{
crypto_unregister_template(&chainiv_tmpl);
+ crypto_free_rng(rng);
}
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index 881d309..b450943 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -16,13 +16,13 @@
*/

#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -39,6 +39,8 @@ struct eseqiv_ctx {
char salt[];
};

+static struct crypto_rng *rng;
+
static void eseqiv_complete2(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
@@ -163,17 +165,22 @@ static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
- get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return eseqiv_givencrypt(req);
}

@@ -250,10 +257,30 @@ static struct crypto_template eseqiv_tmpl = {

int __init eseqiv_module_init(void)
{
- return crypto_register_template(&eseqiv_tmpl);
+ int err;
+
+ rng = crypto_alloc_rng("stdrng", 0, 0);
+ if (IS_ERR(rng))
+ return PTR_ERR(rng);
+
+ err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+ if (err)
+ goto free_rng;
+
+ err = crypto_register_template(&eseqiv_tmpl);
+ if (err)
+ goto free_rng;
+
+out:
+ return err;
+
+free_rng:
+ crypto_free_rng(rng);
+ goto out;
}

void __exit eseqiv_module_exit(void)
{
crypto_unregister_template(&eseqiv_tmpl);
+ crypto_free_rng(rng);
}
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index b903aab..1b95c0e 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -15,11 +15,11 @@

#include <crypto/internal/aead.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/string.h>

@@ -28,6 +28,8 @@ struct seqiv_ctx {
u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
};

+static struct crypto_rng *rng;
+
static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
{
struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
@@ -189,17 +191,22 @@ static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
- get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return seqiv_givencrypt(req);
}

@@ -207,17 +214,21 @@ static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
{
struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
goto unlock;

crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
- get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
+ err = crypto_rng_get_bytes(rng, ctx->salt, crypto_aead_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return seqiv_aead_givencrypt(req);
}

@@ -330,12 +341,32 @@ static struct crypto_template seqiv_tmpl = {

static int __init seqiv_module_init(void)
{
- return crypto_register_template(&seqiv_tmpl);
+ int err;
+
+ rng = crypto_alloc_rng("stdrng", 0, 0);
+ if (IS_ERR(rng))
+ return PTR_ERR(rng);
+
+ err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+ if (err)
+ goto free_rng;
+
+ err = crypto_register_template(&seqiv_tmpl);
+ if (err)
+ goto free_rng;
+
+out:
+ return err;
+
+free_rng:
+ crypto_free_rng(rng);
+ goto out;
}

static void __exit seqiv_module_exit(void)
{
crypto_unregister_template(&seqiv_tmpl);
+ crypto_free_rng(rng);
}

module_init(seqiv_module_init);

2008-08-14 15:28:49

by Neil Horman

[permalink] [raw]
Subject: Re: crypto: skcipher - Use RNG interface instead of get_random_bytes

On Thu, Aug 14, 2008 at 10:23:31PM +1000, Herbert Xu wrote:
> On Thu, Aug 14, 2008 at 09:51:37PM +1000, Herbert Xu wrote:
> >
> > Here is the final result against cryptodev-2.6. Let me know if
> > you're OK with it and I'll push it out.
>
> And here is the IV generator patch on top.
>


Thumbs up. Thanks Herbert!

Acked-by: Neil Horman <[email protected]>


> Cheers,
> --
> Visit Openswan at http://www.openswan.org/
> Email: Herbert Xu ~{PmV>HI~} <[email protected]>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
> --
> commit 560a63d94d36641c83a8f533ed87bab95f6298bb
> Author: Herbert Xu <[email protected]>
> Date: Thu Aug 14 22:21:31 2008 +1000
>
> crypto: skcipher - Use RNG interface instead of get_random_bytes
>
> This patch makes the IV generators use the new RNG interface so
> that the user can pick an RNG other than the default get_random_bytes.
>
> Signed-off-by: Herbert Xu <[email protected]>
>
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index b00860f..a985065 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -33,6 +33,7 @@ config CRYPTO_AEAD
> config CRYPTO_BLKCIPHER
> tristate
> select CRYPTO_ALGAPI
> + select CRYPTO_RNG
>
> config CRYPTO_HASH
> tristate
> @@ -117,6 +118,7 @@ config CRYPTO_SEQIV
> tristate "Sequence Number IV Generator"
> select CRYPTO_AEAD
> select CRYPTO_BLKCIPHER
> + select CRYPTO_RNG
> help
> This IV generator generates an IV based on a sequence number by
> xoring it with a salt. This algorithm is mainly useful for CTR
> diff --git a/crypto/chainiv.c b/crypto/chainiv.c
> index 9affade..330b5e4 100644
> --- a/crypto/chainiv.c
> +++ b/crypto/chainiv.c
> @@ -14,11 +14,11 @@
> */
>
> #include <crypto/internal/skcipher.h>
> +#include <crypto/rng.h>
> #include <linux/err.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> #include <linux/module.h>
> -#include <linux/random.h>
> #include <linux/spinlock.h>
> #include <linux/string.h>
> #include <linux/workqueue.h>
> @@ -44,6 +44,8 @@ struct async_chainiv_ctx {
> char iv[];
> };
>
> +static struct crypto_rng *rng;
> +
> static int chainiv_givencrypt(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> @@ -83,6 +85,7 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
> + int err = 0;
>
> spin_lock_bh(&ctx->lock);
> if (crypto_ablkcipher_crt(geniv)->givencrypt !=
> @@ -90,11 +93,15 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> goto unlock;
>
> crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
> - get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
> + err = crypto_rng_get_bytes(rng, ctx->iv,
> + crypto_ablkcipher_ivsize(geniv));
>
> unlock:
> spin_unlock_bh(&ctx->lock);
>
> + if (err)
> + return err;
> +
> return chainiv_givencrypt(req);
> }
>
> @@ -203,6 +210,7 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
> + int err = 0;
>
> if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
> goto out;
> @@ -212,11 +220,15 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> goto unlock;
>
> crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
> - get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
> + err = crypto_rng_get_bytes(rng, ctx->iv,
> + crypto_ablkcipher_ivsize(geniv));
>
> unlock:
> clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
>
> + if (err)
> + return err;
> +
> out:
> return async_chainiv_givencrypt(req);
> }
> @@ -322,10 +334,30 @@ static struct crypto_template chainiv_tmpl = {
>
> int __init chainiv_module_init(void)
> {
> - return crypto_register_template(&chainiv_tmpl);
> + int err;
> +
> + rng = crypto_alloc_rng("stdrng", 0, 0);
> + if (IS_ERR(rng))
> + return PTR_ERR(rng);
> +
> + err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
> + if (err)
> + goto free_rng;
> +
> + err = crypto_register_template(&chainiv_tmpl);
> + if (err)
> + goto free_rng;
> +
> +out:
> + return err;
> +
> +free_rng:
> + crypto_free_rng(rng);
> + goto out;
> }
>
> void chainiv_module_exit(void)
> {
> crypto_unregister_template(&chainiv_tmpl);
> + crypto_free_rng(rng);
> }
> diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
> index 881d309..b450943 100644
> --- a/crypto/eseqiv.c
> +++ b/crypto/eseqiv.c
> @@ -16,13 +16,13 @@
> */
>
> #include <crypto/internal/skcipher.h>
> +#include <crypto/rng.h>
> #include <crypto/scatterwalk.h>
> #include <linux/err.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> #include <linux/mm.h>
> #include <linux/module.h>
> -#include <linux/random.h>
> #include <linux/scatterlist.h>
> #include <linux/spinlock.h>
> #include <linux/string.h>
> @@ -39,6 +39,8 @@ struct eseqiv_ctx {
> char salt[];
> };
>
> +static struct crypto_rng *rng;
> +
> static void eseqiv_complete2(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> @@ -163,17 +165,22 @@ static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
> + int err = 0;
>
> spin_lock_bh(&ctx->lock);
> if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
> goto unlock;
>
> crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
> - get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
> + err = crypto_rng_get_bytes(rng, ctx->salt,
> + crypto_ablkcipher_ivsize(geniv));
>
> unlock:
> spin_unlock_bh(&ctx->lock);
>
> + if (err)
> + return err;
> +
> return eseqiv_givencrypt(req);
> }
>
> @@ -250,10 +257,30 @@ static struct crypto_template eseqiv_tmpl = {
>
> int __init eseqiv_module_init(void)
> {
> - return crypto_register_template(&eseqiv_tmpl);
> + int err;
> +
> + rng = crypto_alloc_rng("stdrng", 0, 0);
> + if (IS_ERR(rng))
> + return PTR_ERR(rng);
> +
> + err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
> + if (err)
> + goto free_rng;
> +
> + err = crypto_register_template(&eseqiv_tmpl);
> + if (err)
> + goto free_rng;
> +
> +out:
> + return err;
> +
> +free_rng:
> + crypto_free_rng(rng);
> + goto out;
> }
>
> void __exit eseqiv_module_exit(void)
> {
> crypto_unregister_template(&eseqiv_tmpl);
> + crypto_free_rng(rng);
> }
> diff --git a/crypto/seqiv.c b/crypto/seqiv.c
> index b903aab..1b95c0e 100644
> --- a/crypto/seqiv.c
> +++ b/crypto/seqiv.c
> @@ -15,11 +15,11 @@
>
> #include <crypto/internal/aead.h>
> #include <crypto/internal/skcipher.h>
> +#include <crypto/rng.h>
> #include <linux/err.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> #include <linux/module.h>
> -#include <linux/random.h>
> #include <linux/spinlock.h>
> #include <linux/string.h>
>
> @@ -28,6 +28,8 @@ struct seqiv_ctx {
> u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
> };
>
> +static struct crypto_rng *rng;
> +
> static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
> {
> struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
> @@ -189,17 +191,22 @@ static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
> {
> struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
> struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
> + int err = 0;
>
> spin_lock_bh(&ctx->lock);
> if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
> goto unlock;
>
> crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
> - get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
> + err = crypto_rng_get_bytes(rng, ctx->salt,
> + crypto_ablkcipher_ivsize(geniv));
>
> unlock:
> spin_unlock_bh(&ctx->lock);
>
> + if (err)
> + return err;
> +
> return seqiv_givencrypt(req);
> }
>
> @@ -207,17 +214,21 @@ static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
> {
> struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
> struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
> + int err = 0;
>
> spin_lock_bh(&ctx->lock);
> if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
> goto unlock;
>
> crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
> - get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
> + err = crypto_rng_get_bytes(rng, ctx->salt, crypto_aead_ivsize(geniv));
>
> unlock:
> spin_unlock_bh(&ctx->lock);
>
> + if (err)
> + return err;
> +
> return seqiv_aead_givencrypt(req);
> }
>
> @@ -330,12 +341,32 @@ static struct crypto_template seqiv_tmpl = {
>
> static int __init seqiv_module_init(void)
> {
> - return crypto_register_template(&seqiv_tmpl);
> + int err;
> +
> + rng = crypto_alloc_rng("stdrng", 0, 0);
> + if (IS_ERR(rng))
> + return PTR_ERR(rng);
> +
> + err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
> + if (err)
> + goto free_rng;
> +
> + err = crypto_register_template(&seqiv_tmpl);
> + if (err)
> + goto free_rng;
> +
> +out:
> + return err;
> +
> +free_rng:
> + crypto_free_rng(rng);
> + goto out;
> }
>
> static void __exit seqiv_module_exit(void)
> {
> crypto_unregister_template(&seqiv_tmpl);
> + crypto_free_rng(rng);
> }
>
> module_init(seqiv_module_init);

--
/***************************************************
*Neil Horman
*[email protected]
*gpg keyid: 1024D / 0x92A74FA1
*http://pgp.mit.edu
***************************************************/

2008-08-17 12:20:51

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH] crypto: obscure state information on free

On Thu, Aug 14, 2008 at 08:21:37AM -0400, Neil Horman wrote:
>
> Looks great to me. Thanks Herbert!

Unfortunately it didn't quite work :)

First of all there was a module dependency loop between cryptomgr,
rng and crypto_blkcipher. This is fixed by putting krng in its
own module. Also I made a typo in the rng_reset helper so it
ended up calling itself over and over again.

Here is an incremental patch to fix this up. I've also renamed
rngapi.c to rng.c for consistency.

There is also a new global rng object for everyone to use rather
than having it allocated by every user separately.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/crypto/Makefile b/crypto/Makefile
index a14ed7d..42e3980 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -24,8 +24,6 @@ obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o

cryptomgr-objs := algboss.o testmgr.o

-rng-objs := rngapi.o krng.o
-
obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
@@ -74,6 +72,7 @@ obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
obj-$(CONFIG_CRYPTO_RNG) += rng.o
+obj-$(CONFIG_CRYPTO_RNG) += krng.o
obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o

diff --git a/crypto/krng.c b/crypto/krng.c
index 8ef62a9..4328bb3 100644
--- a/crypto/krng.c
+++ b/crypto/krng.c
@@ -62,5 +62,5 @@ module_init(krng_mod_init);
module_exit(krng_mod_fini);

MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Random Number Generator API");
+MODULE_DESCRIPTION("Kernel Random Number Generator");
MODULE_ALIAS("stdrng");
diff --git a/crypto/rng.c b/crypto/rng.c
new file mode 100644
index 0000000..6e94bc7
--- /dev/null
+++ b/crypto/rng.c
@@ -0,0 +1,126 @@
+/*
+ * Cryptographic API.
+ *
+ * RNG operations.
+ *
+ * Copyright (c) 2008 Neil Horman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <crypto/internal/rng.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+static DEFINE_MUTEX(crypto_default_rng_lock);
+struct crypto_rng *crypto_default_rng;
+EXPORT_SYMBOL_GPL(crypto_default_rng);
+static int crypto_default_rng_refcnt;
+
+static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ u8 *buf = NULL;
+ int err;
+
+ if (!seed && slen) {
+ buf = kmalloc(slen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ get_random_bytes(buf, slen);
+ seed = buf;
+ }
+
+ err = crypto_rng_alg(tfm)->rng_reset(tfm, seed, slen);
+
+ kfree(buf);
+ return err;
+}
+
+static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+ struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
+ struct rng_tfm *ops = &tfm->crt_rng;
+
+ ops->rng_gen_random = alg->rng_make_random;
+ ops->rng_reset = rngapi_reset;
+
+ return 0;
+}
+
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ seq_printf(m, "type : rng\n");
+ seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
+}
+
+static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
+{
+ return alg->cra_ctxsize;
+}
+
+const struct crypto_type crypto_rng_type = {
+ .ctxsize = crypto_rng_ctxsize,
+ .init = crypto_init_rng_ops,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_rng_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_rng_type);
+
+int crypto_get_default_rng(void)
+{
+ struct crypto_rng *rng;
+ int err;
+
+ mutex_lock(&crypto_default_rng_lock);
+ if (!crypto_default_rng) {
+ rng = crypto_alloc_rng("stdrng", 0, 0);
+ err = PTR_ERR(rng);
+ if (IS_ERR(rng))
+ goto unlock;
+
+ err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+ if (err) {
+ crypto_free_rng(rng);
+ goto unlock;
+ }
+
+ crypto_default_rng = rng;
+ }
+
+ crypto_default_rng_refcnt++;
+ err = 0;
+
+unlock:
+ mutex_unlock(&crypto_default_rng_lock);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_get_default_rng);
+
+void crypto_put_default_rng(void)
+{
+ mutex_lock(&crypto_default_rng_lock);
+ if (!--crypto_default_rng_refcnt) {
+ crypto_free_rng(crypto_default_rng);
+ crypto_default_rng = NULL;
+ }
+ mutex_unlock(&crypto_default_rng_lock);
+}
+EXPORT_SYMBOL_GPL(crypto_put_default_rng);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Random Number Genertor");
diff --git a/crypto/rngapi.c b/crypto/rngapi.c
deleted file mode 100644
index ea57697..0000000
--- a/crypto/rngapi.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Cryptographic API.
- *
- * RNG operations.
- *
- * Copyright (c) 2008 Neil Horman <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-
-#include <crypto/internal/rng.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/random.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-
-static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
-{
- u8 *buf = NULL;
- int err;
-
- if (!seed && slen) {
- buf = kmalloc(slen, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- get_random_bytes(buf, slen);
- seed = buf;
- }
-
- err = crypto_rng_crt(tfm)->rng_reset(tfm, seed, slen);
-
- kfree(buf);
- return err;
-}
-
-static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
-{
- struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
- struct rng_tfm *ops = &tfm->crt_rng;
-
- ops->rng_gen_random = alg->rng_make_random;
- ops->rng_reset = rngapi_reset;
-
- return 0;
-}
-
-static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute__ ((unused));
-static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
-{
- seq_printf(m, "type : rng\n");
- seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
-}
-
-static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
-{
- return alg->cra_ctxsize;
-}

2008-08-17 12:22:36

by Herbert Xu

[permalink] [raw]
Subject: Re: crypto: skcipher - Use RNG interface instead of get_random_bytes

On Thu, Aug 14, 2008 at 10:23:31PM +1000, Herbert Xu wrote:
>
> And here is the IV generator patch on top.

This also dead-locked if built as modules. I've split out the
IV generators from crypto_blkcipher so it doesn't interfere with
cryptomgr.

commit 106475b7c368794f22493fc67d98b874eb0f9383
Author: Herbert Xu <[email protected]>
Date: Sun Aug 17 18:04:30 2008 +1000

crypto: skcipher - Move IV generators into their own modules

This patch moves the default IV generators into their own modules
in order to break a dependency loop between cryptomgr, rng, and
blkcipher.

Signed-off-by: Herbert Xu <[email protected]>

diff --git a/crypto/Makefile b/crypto/Makefile
index 42e3980..ed2be05 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -13,9 +13,9 @@ obj-$(CONFIG_CRYPTO_AEAD) += aead.o

crypto_blkcipher-objs := ablkcipher.o
crypto_blkcipher-objs += blkcipher.o
-crypto_blkcipher-objs += chainiv.o
-crypto_blkcipher-objs += eseqiv.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o

crypto_hash-objs := hash.o
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 185f955..4a7e65c 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -696,34 +696,5 @@ void skcipher_geniv_exit(struct crypto_tfm *tfm)
}
EXPORT_SYMBOL_GPL(skcipher_geniv_exit);

-static int __init blkcipher_module_init(void)
-{
- int err;
-
- err = chainiv_module_init();
- if (err)
- goto out;
-
- err = eseqiv_module_init();
- if (err)
- goto eseqiv_err;
-
-out:
- return err;
-
-eseqiv_err:
- chainiv_module_exit();
- goto out;
-}
-
-static void __exit blkcipher_module_exit(void)
-{
- eseqiv_module_exit();
- chainiv_module_exit();
-}
-
-module_init(blkcipher_module_init);
-module_exit(blkcipher_module_exit);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic block chaining cipher type");
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index 9affade..cf68d43 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -320,12 +320,18 @@ static struct crypto_template chainiv_tmpl = {
.module = THIS_MODULE,
};

-int __init chainiv_module_init(void)
+static int __init chainiv_module_init(void)
{
return crypto_register_template(&chainiv_tmpl);
}

-void chainiv_module_exit(void)
+static void chainiv_module_exit(void)
{
crypto_unregister_template(&chainiv_tmpl);
}
+
+module_init(chainiv_module_init);
+module_exit(chainiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Chain IV Generator");
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index 881d309..f5def21 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -248,12 +248,18 @@ static struct crypto_template eseqiv_tmpl = {
.module = THIS_MODULE,
};

-int __init eseqiv_module_init(void)
+static int __init eseqiv_module_init(void)
{
return crypto_register_template(&eseqiv_tmpl);
}

-void __exit eseqiv_module_exit(void)
+static void __exit eseqiv_module_exit(void)
{
crypto_unregister_template(&eseqiv_tmpl);
}
+
+module_init(eseqiv_module_init);
+module_exit(eseqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator");
diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
index ccc32ba..2ba42cd 100644
--- a/include/crypto/internal/skcipher.h
+++ b/include/crypto/internal/skcipher.h
@@ -15,7 +15,6 @@

#include <crypto/algapi.h>
#include <crypto/skcipher.h>
-#include <linux/init.h>
#include <linux/types.h>

struct rtattr;
@@ -65,11 +64,6 @@ void skcipher_geniv_free(struct crypto_instance *inst);
int skcipher_geniv_init(struct crypto_tfm *tfm);
void skcipher_geniv_exit(struct crypto_tfm *tfm);

-int __init eseqiv_module_init(void);
-void __exit eseqiv_module_exit(void);
-int __init chainiv_module_init(void);
-void chainiv_module_exit(void);

2008-08-17 12:23:53

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH] crypto: obscure state information on free

On Sun, Aug 17, 2008 at 10:20:47PM +1000, Herbert Xu wrote:
>
> There is also a new global rng object for everyone to use rather
> than having it allocated by every user separately.

And here is the new IV generator patch to use the global RNG object.

commit 1da64c8d0d573dcb1b67c42d41c0adf511f81dfc
Author: Herbert Xu <[email protected]>
Date: Thu Aug 14 22:21:31 2008 +1000

crypto: skcipher - Use RNG interface instead of get_random_bytes

This patch makes the IV generators use the new RNG interface so
that the user can pick an RNG other than the default get_random_bytes.

Signed-off-by: Herbert Xu <[email protected]>

diff --git a/crypto/Kconfig b/crypto/Kconfig
index b00860f..a985065 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -33,6 +33,7 @@ config CRYPTO_AEAD
config CRYPTO_BLKCIPHER
tristate
select CRYPTO_ALGAPI
+ select CRYPTO_RNG

config CRYPTO_HASH
tristate
@@ -117,6 +118,7 @@ config CRYPTO_SEQIV
tristate "Sequence Number IV Generator"
select CRYPTO_AEAD
select CRYPTO_BLKCIPHER
+ select CRYPTO_RNG
help
This IV generator generates an IV based on a sequence number by
xoring it with a salt. This algorithm is mainly useful for CTR
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index cf68d43..7c37a49 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -14,11 +14,11 @@
*/

#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/workqueue.h>
@@ -83,6 +83,7 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt !=
@@ -90,11 +91,15 @@ static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
- get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return chainiv_givencrypt(req);
}

@@ -203,6 +208,7 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
goto out;
@@ -212,11 +218,15 @@ static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
- get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
clear_bit(CHAINIV_STATE_INUSE, &ctx->state);

+ if (err)
+ return err;
+
out:
return async_chainiv_givencrypt(req);
}
@@ -284,9 +294,13 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
if (IS_ERR(algt))
return ERR_PTR(err);

+ err = crypto_get_default_rng();
+ if (err)
+ return ERR_PTR(err);
+
inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
if (IS_ERR(inst))
- goto out;
+ goto put_rng;

inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first;

@@ -311,12 +325,22 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)

out:
return inst;
+
+put_rng:
+ crypto_put_default_rng();
+ goto out;
+}
+
+static void chainiv_free(struct crypto_instance *inst)
+{
+ skcipher_geniv_free(inst);
+ crypto_put_default_rng();
}

static struct crypto_template chainiv_tmpl = {
.name = "chainiv",
.alloc = chainiv_alloc,
- .free = skcipher_geniv_free,
+ .free = chainiv_free,
.module = THIS_MODULE,
};

diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index f5def21..2a342c8 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -16,13 +16,13 @@
*/

#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -163,17 +163,22 @@ static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
- get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return eseqiv_givencrypt(req);
}

@@ -216,9 +221,13 @@ static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
struct crypto_instance *inst;
int err;

+ err = crypto_get_default_rng();
+ if (err)
+ return ERR_PTR(err);
+
inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
if (IS_ERR(inst))
- goto out;
+ goto put_rng;

err = -EINVAL;
if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
@@ -238,13 +247,21 @@ out:
free_inst:
skcipher_geniv_free(inst);
inst = ERR_PTR(err);
+put_rng:
+ crypto_put_default_rng();
goto out;
}

+static void eseqiv_free(struct crypto_instance *inst)
+{
+ skcipher_geniv_free(inst);
+ crypto_put_default_rng();
+}
+
static struct crypto_template eseqiv_tmpl = {
.name = "eseqiv",
.alloc = eseqiv_alloc,
- .free = skcipher_geniv_free,
+ .free = eseqiv_free,
.module = THIS_MODULE,
};

diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index b903aab..5a013a8 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -15,11 +15,11 @@

#include <crypto/internal/aead.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/rng.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/string.h>

@@ -189,17 +189,22 @@ static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
{
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
goto unlock;

crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
- get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return seqiv_givencrypt(req);
}

@@ -207,17 +212,22 @@ static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
{
struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err = 0;

spin_lock_bh(&ctx->lock);
if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
goto unlock;

crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
- get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_aead_ivsize(geniv));

unlock:
spin_unlock_bh(&ctx->lock);

+ if (err)
+ return err;
+
return seqiv_aead_givencrypt(req);
}

@@ -298,19 +308,27 @@ static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
if (IS_ERR(algt))
return ERR_PTR(err);

+ err = crypto_get_default_rng();
+ if (err)
+ return ERR_PTR(err);
+
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
inst = seqiv_ablkcipher_alloc(tb);
else
inst = seqiv_aead_alloc(tb);

if (IS_ERR(inst))
- goto out;
+ goto put_rng;

inst->alg.cra_alignmask |= __alignof__(u32) - 1;
inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);

out:
return inst;
+
+put_rng:
+ crypto_put_default_rng();
+ goto out;
}

static void seqiv_free(struct crypto_instance *inst)
@@ -319,6 +337,7 @@ static void seqiv_free(struct crypto_instance *inst)
skcipher_geniv_free(inst);
else
aead_geniv_free(inst);
+ crypto_put_default_rng();
}

static struct crypto_template seqiv_tmpl = {

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt