117f0f4a4SNeil Horman /* 217f0f4a4SNeil Horman * Cryptographic API. 317f0f4a4SNeil Horman * 417f0f4a4SNeil Horman * RNG operations. 517f0f4a4SNeil Horman * 617f0f4a4SNeil Horman * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com> 794f1bb15SHerbert Xu * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au> 817f0f4a4SNeil Horman * 917f0f4a4SNeil Horman * This program is free software; you can redistribute it and/or modify it 1017f0f4a4SNeil Horman * under the terms of the GNU General Public License as published by the Free 1117f0f4a4SNeil Horman * Software Foundation; either version 2 of the License, or (at your option) 1217f0f4a4SNeil Horman * any later version. 1317f0f4a4SNeil Horman * 1417f0f4a4SNeil Horman */ 1517f0f4a4SNeil Horman 1660063497SArun Sharma #include <linux/atomic.h> 1717f0f4a4SNeil Horman #include <crypto/internal/rng.h> 1817f0f4a4SNeil Horman #include <linux/err.h> 1917f0f4a4SNeil Horman #include <linux/module.h> 2017f0f4a4SNeil Horman #include <linux/mutex.h> 2117f0f4a4SNeil Horman #include <linux/random.h> 2217f0f4a4SNeil Horman #include <linux/seq_file.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 2417f0f4a4SNeil Horman #include <linux/string.h> 25792608e9SSteffen Klassert #include <linux/cryptouser.h> 26792608e9SSteffen Klassert #include <net/netlink.h> 2717f0f4a4SNeil Horman 28d0e83059SHerbert Xu #include "internal.h" 29d0e83059SHerbert Xu 3017f0f4a4SNeil Horman static DEFINE_MUTEX(crypto_default_rng_lock); 3117f0f4a4SNeil Horman struct crypto_rng *crypto_default_rng; 3217f0f4a4SNeil Horman EXPORT_SYMBOL_GPL(crypto_default_rng); 3317f0f4a4SNeil Horman static int crypto_default_rng_refcnt; 3417f0f4a4SNeil Horman 35d0e83059SHerbert Xu static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm) 36d0e83059SHerbert Xu { 37d0e83059SHerbert Xu return container_of(tfm, struct crypto_rng, base); 38d0e83059SHerbert Xu } 39d0e83059SHerbert Xu 403c5d8fa9SHerbert Xu int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) 4117f0f4a4SNeil Horman { 4217f0f4a4SNeil Horman u8 *buf = NULL; 4317f0f4a4SNeil Horman int err; 4417f0f4a4SNeil Horman 4517f0f4a4SNeil Horman if (!seed && slen) { 4617f0f4a4SNeil Horman buf = kmalloc(slen, GFP_KERNEL); 4717f0f4a4SNeil Horman if (!buf) 4817f0f4a4SNeil Horman return -ENOMEM; 4917f0f4a4SNeil Horman 5017f0f4a4SNeil Horman get_random_bytes(buf, slen); 5117f0f4a4SNeil Horman seed = buf; 5217f0f4a4SNeil Horman } 5317f0f4a4SNeil Horman 5494f1bb15SHerbert Xu err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); 5517f0f4a4SNeil Horman 56b617b702SHerbert Xu kzfree(buf); 5717f0f4a4SNeil Horman return err; 5817f0f4a4SNeil Horman } 593c5d8fa9SHerbert Xu EXPORT_SYMBOL_GPL(crypto_rng_reset); 6017f0f4a4SNeil Horman 61d0e83059SHerbert Xu static int crypto_rng_init_tfm(struct crypto_tfm *tfm) 6217f0f4a4SNeil Horman { 6317f0f4a4SNeil Horman return 0; 6417f0f4a4SNeil Horman } 6517f0f4a4SNeil Horman 66acec27ffSHerbert Xu static unsigned int seedsize(struct crypto_alg *alg) 67acec27ffSHerbert Xu { 68acec27ffSHerbert Xu struct rng_alg *ralg = container_of(alg, struct rng_alg, base); 69acec27ffSHerbert Xu 7094f1bb15SHerbert Xu return ralg->seedsize; 71acec27ffSHerbert Xu } 72acec27ffSHerbert Xu 733acc8473SHerbert Xu #ifdef CONFIG_NET 74792608e9SSteffen Klassert static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) 75792608e9SSteffen Klassert { 76792608e9SSteffen Klassert struct crypto_report_rng rrng; 77792608e9SSteffen Klassert 789a5467bfSMathias Krause strncpy(rrng.type, "rng", sizeof(rrng.type)); 79792608e9SSteffen Klassert 80acec27ffSHerbert Xu rrng.seedsize = seedsize(alg); 81792608e9SSteffen Klassert 826662df33SDavid S. Miller if (nla_put(skb, CRYPTOCFGA_REPORT_RNG, 836662df33SDavid S. Miller sizeof(struct crypto_report_rng), &rrng)) 846662df33SDavid S. Miller goto nla_put_failure; 85792608e9SSteffen Klassert return 0; 86792608e9SSteffen Klassert 87792608e9SSteffen Klassert nla_put_failure: 88792608e9SSteffen Klassert return -EMSGSIZE; 89792608e9SSteffen Klassert } 903acc8473SHerbert Xu #else 913acc8473SHerbert Xu static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) 923acc8473SHerbert Xu { 933acc8473SHerbert Xu return -ENOSYS; 943acc8473SHerbert Xu } 953acc8473SHerbert Xu #endif 96792608e9SSteffen Klassert 9717f0f4a4SNeil Horman static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 9817f0f4a4SNeil Horman __attribute__ ((unused)); 9917f0f4a4SNeil Horman static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 10017f0f4a4SNeil Horman { 10117f0f4a4SNeil Horman seq_printf(m, "type : rng\n"); 102acec27ffSHerbert Xu seq_printf(m, "seedsize : %u\n", seedsize(alg)); 10317f0f4a4SNeil Horman } 10417f0f4a4SNeil Horman 10594f1bb15SHerbert Xu static const struct crypto_type crypto_rng_type = { 106d0e83059SHerbert Xu .extsize = crypto_alg_extsize, 107d0e83059SHerbert Xu .init_tfm = crypto_rng_init_tfm, 10817f0f4a4SNeil Horman #ifdef CONFIG_PROC_FS 10917f0f4a4SNeil Horman .show = crypto_rng_show, 11017f0f4a4SNeil Horman #endif 111792608e9SSteffen Klassert .report = crypto_rng_report, 112d0e83059SHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK, 113d0e83059SHerbert Xu .maskset = CRYPTO_ALG_TYPE_MASK, 114d0e83059SHerbert Xu .type = CRYPTO_ALG_TYPE_RNG, 115d0e83059SHerbert Xu .tfmsize = offsetof(struct crypto_rng, base), 11617f0f4a4SNeil Horman }; 11717f0f4a4SNeil Horman 118d0e83059SHerbert Xu struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) 119d0e83059SHerbert Xu { 120d0e83059SHerbert Xu return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask); 121d0e83059SHerbert Xu } 122d0e83059SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_rng); 123d0e83059SHerbert Xu 12417f0f4a4SNeil Horman int crypto_get_default_rng(void) 12517f0f4a4SNeil Horman { 12617f0f4a4SNeil Horman struct crypto_rng *rng; 12717f0f4a4SNeil Horman int err; 12817f0f4a4SNeil Horman 12917f0f4a4SNeil Horman mutex_lock(&crypto_default_rng_lock); 13017f0f4a4SNeil Horman if (!crypto_default_rng) { 13117f0f4a4SNeil Horman rng = crypto_alloc_rng("stdrng", 0, 0); 13217f0f4a4SNeil Horman err = PTR_ERR(rng); 13317f0f4a4SNeil Horman if (IS_ERR(rng)) 13417f0f4a4SNeil Horman goto unlock; 13517f0f4a4SNeil Horman 13617f0f4a4SNeil Horman err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); 13717f0f4a4SNeil Horman if (err) { 13817f0f4a4SNeil Horman crypto_free_rng(rng); 13917f0f4a4SNeil Horman goto unlock; 14017f0f4a4SNeil Horman } 14117f0f4a4SNeil Horman 14217f0f4a4SNeil Horman crypto_default_rng = rng; 14317f0f4a4SNeil Horman } 14417f0f4a4SNeil Horman 14517f0f4a4SNeil Horman crypto_default_rng_refcnt++; 14617f0f4a4SNeil Horman err = 0; 14717f0f4a4SNeil Horman 14817f0f4a4SNeil Horman unlock: 14917f0f4a4SNeil Horman mutex_unlock(&crypto_default_rng_lock); 15017f0f4a4SNeil Horman 15117f0f4a4SNeil Horman return err; 15217f0f4a4SNeil Horman } 15317f0f4a4SNeil Horman EXPORT_SYMBOL_GPL(crypto_get_default_rng); 15417f0f4a4SNeil Horman 15517f0f4a4SNeil Horman void crypto_put_default_rng(void) 15617f0f4a4SNeil Horman { 15717f0f4a4SNeil Horman mutex_lock(&crypto_default_rng_lock); 1587cecadb7SHerbert Xu crypto_default_rng_refcnt--; 15917f0f4a4SNeil Horman mutex_unlock(&crypto_default_rng_lock); 16017f0f4a4SNeil Horman } 16117f0f4a4SNeil Horman EXPORT_SYMBOL_GPL(crypto_put_default_rng); 16217f0f4a4SNeil Horman 1637cecadb7SHerbert Xu #if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) 1647cecadb7SHerbert Xu int crypto_del_default_rng(void) 1657cecadb7SHerbert Xu { 1667cecadb7SHerbert Xu int err = -EBUSY; 1677cecadb7SHerbert Xu 1687cecadb7SHerbert Xu mutex_lock(&crypto_default_rng_lock); 1697cecadb7SHerbert Xu if (crypto_default_rng_refcnt) 1707cecadb7SHerbert Xu goto out; 1717cecadb7SHerbert Xu 1727cecadb7SHerbert Xu crypto_free_rng(crypto_default_rng); 1737cecadb7SHerbert Xu crypto_default_rng = NULL; 1747cecadb7SHerbert Xu 1757cecadb7SHerbert Xu err = 0; 1767cecadb7SHerbert Xu 1777cecadb7SHerbert Xu out: 1787cecadb7SHerbert Xu mutex_unlock(&crypto_default_rng_lock); 1797cecadb7SHerbert Xu 1807cecadb7SHerbert Xu return err; 1817cecadb7SHerbert Xu } 1827cecadb7SHerbert Xu EXPORT_SYMBOL_GPL(crypto_del_default_rng); 1837cecadb7SHerbert Xu #endif 1847cecadb7SHerbert Xu 185acec27ffSHerbert Xu int crypto_register_rng(struct rng_alg *alg) 186acec27ffSHerbert Xu { 187acec27ffSHerbert Xu struct crypto_alg *base = &alg->base; 188acec27ffSHerbert Xu 189acec27ffSHerbert Xu if (alg->seedsize > PAGE_SIZE / 8) 190acec27ffSHerbert Xu return -EINVAL; 191acec27ffSHerbert Xu 192acec27ffSHerbert Xu base->cra_type = &crypto_rng_type; 193acec27ffSHerbert Xu base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 194acec27ffSHerbert Xu base->cra_flags |= CRYPTO_ALG_TYPE_RNG; 195acec27ffSHerbert Xu 196acec27ffSHerbert Xu return crypto_register_alg(base); 197acec27ffSHerbert Xu } 198acec27ffSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_rng); 199acec27ffSHerbert Xu 200acec27ffSHerbert Xu void crypto_unregister_rng(struct rng_alg *alg) 201acec27ffSHerbert Xu { 202acec27ffSHerbert Xu crypto_unregister_alg(&alg->base); 203acec27ffSHerbert Xu } 204acec27ffSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_rng); 205acec27ffSHerbert Xu 206881cd6c5SHerbert Xu int crypto_register_rngs(struct rng_alg *algs, int count) 207881cd6c5SHerbert Xu { 208881cd6c5SHerbert Xu int i, ret; 209881cd6c5SHerbert Xu 210881cd6c5SHerbert Xu for (i = 0; i < count; i++) { 211881cd6c5SHerbert Xu ret = crypto_register_rng(algs + i); 212881cd6c5SHerbert Xu if (ret) 213881cd6c5SHerbert Xu goto err; 214881cd6c5SHerbert Xu } 215881cd6c5SHerbert Xu 216881cd6c5SHerbert Xu return 0; 217881cd6c5SHerbert Xu 218881cd6c5SHerbert Xu err: 219881cd6c5SHerbert Xu for (--i; i >= 0; --i) 220881cd6c5SHerbert Xu crypto_unregister_rng(algs + i); 221881cd6c5SHerbert Xu 222881cd6c5SHerbert Xu return ret; 223881cd6c5SHerbert Xu } 224881cd6c5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_rngs); 225881cd6c5SHerbert Xu 226881cd6c5SHerbert Xu void crypto_unregister_rngs(struct rng_alg *algs, int count) 227881cd6c5SHerbert Xu { 228881cd6c5SHerbert Xu int i; 229881cd6c5SHerbert Xu 230881cd6c5SHerbert Xu for (i = count - 1; i >= 0; --i) 231881cd6c5SHerbert Xu crypto_unregister_rng(algs + i); 232881cd6c5SHerbert Xu } 233881cd6c5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_rngs); 234881cd6c5SHerbert Xu 23517f0f4a4SNeil Horman MODULE_LICENSE("GPL"); 236a8ccc393SChristian Kujau MODULE_DESCRIPTION("Random Number Generator"); 237