1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Cryptographic API. 4 * 5 * RNG operations. 6 * 7 * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com> 8 * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au> 9 */ 10 11#include <crypto/internal/rng.h> 12#include <linux/atomic.h> 13#include <linux/cryptouser.h> 14#include <linux/err.h> 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/mutex.h> 18#include <linux/random.h> 19#include <linux/seq_file.h> 20#include <linux/slab.h> 21#include <linux/string.h> 22#include <net/netlink.h> 23 24#include "internal.h" 25 26static DEFINE_MUTEX(crypto_default_rng_lock); 27struct crypto_rng *crypto_default_rng; 28EXPORT_SYMBOL_GPL(crypto_default_rng); 29static int crypto_default_rng_refcnt; 30 31int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) 32{ 33 struct rng_alg *alg = crypto_rng_alg(tfm); 34 u8 *buf = NULL; 35 int err; 36 37 if (IS_ENABLED(CONFIG_CRYPTO_STATS)) 38 atomic64_inc(&rng_get_stat(alg)->seed_cnt); 39 40 if (!seed && slen) { 41 buf = kmalloc(slen, GFP_KERNEL); 42 err = -ENOMEM; 43 if (!buf) 44 goto out; 45 46 err = get_random_bytes_wait(buf, slen); 47 if (err) 48 goto free_buf; 49 seed = buf; 50 } 51 52 err = alg->seed(tfm, seed, slen); 53free_buf: 54 kfree_sensitive(buf); 55out: 56 return crypto_rng_errstat(alg, err); 57} 58EXPORT_SYMBOL_GPL(crypto_rng_reset); 59 60static int crypto_rng_init_tfm(struct crypto_tfm *tfm) 61{ 62 return 0; 63} 64 65static unsigned int seedsize(struct crypto_alg *alg) 66{ 67 struct rng_alg *ralg = container_of(alg, struct rng_alg, base); 68 69 return ralg->seedsize; 70} 71 72static int __maybe_unused crypto_rng_report( 73 struct sk_buff *skb, struct crypto_alg *alg) 74{ 75 struct crypto_report_rng rrng; 76 77 memset(&rrng, 0, sizeof(rrng)); 78 79 strscpy(rrng.type, "rng", sizeof(rrng.type)); 80 81 rrng.seedsize = seedsize(alg); 82 83 return nla_put(skb, CRYPTOCFGA_REPORT_RNG, sizeof(rrng), &rrng); 84} 85 86static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 87 __maybe_unused; 88static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 89{ 90 seq_printf(m, "type : rng\n"); 91 seq_printf(m, "seedsize : %u\n", seedsize(alg)); 92} 93 94static int __maybe_unused crypto_rng_report_stat( 95 struct sk_buff *skb, struct crypto_alg *alg) 96{ 97 struct rng_alg *rng = __crypto_rng_alg(alg); 98 struct crypto_istat_rng *istat; 99 struct crypto_stat_rng rrng; 100 101 istat = rng_get_stat(rng); 102 103 memset(&rrng, 0, sizeof(rrng)); 104 105 strscpy(rrng.type, "rng", sizeof(rrng.type)); 106 107 rrng.stat_generate_cnt = atomic64_read(&istat->generate_cnt); 108 rrng.stat_generate_tlen = atomic64_read(&istat->generate_tlen); 109 rrng.stat_seed_cnt = atomic64_read(&istat->seed_cnt); 110 rrng.stat_err_cnt = atomic64_read(&istat->err_cnt); 111 112 return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng); 113} 114 115static const struct crypto_type crypto_rng_type = { 116 .extsize = crypto_alg_extsize, 117 .init_tfm = crypto_rng_init_tfm, 118#ifdef CONFIG_PROC_FS 119 .show = crypto_rng_show, 120#endif 121#if IS_ENABLED(CONFIG_CRYPTO_USER) 122 .report = crypto_rng_report, 123#endif 124#ifdef CONFIG_CRYPTO_STATS 125 .report_stat = crypto_rng_report_stat, 126#endif 127 .maskclear = ~CRYPTO_ALG_TYPE_MASK, 128 .maskset = CRYPTO_ALG_TYPE_MASK, 129 .type = CRYPTO_ALG_TYPE_RNG, 130 .tfmsize = offsetof(struct crypto_rng, base), 131}; 132 133struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) 134{ 135 return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask); 136} 137EXPORT_SYMBOL_GPL(crypto_alloc_rng); 138 139int crypto_get_default_rng(void) 140{ 141 struct crypto_rng *rng; 142 int err; 143 144 mutex_lock(&crypto_default_rng_lock); 145 if (!crypto_default_rng) { 146 rng = crypto_alloc_rng("stdrng", 0, 0); 147 err = PTR_ERR(rng); 148 if (IS_ERR(rng)) 149 goto unlock; 150 151 err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); 152 if (err) { 153 crypto_free_rng(rng); 154 goto unlock; 155 } 156 157 crypto_default_rng = rng; 158 } 159 160 crypto_default_rng_refcnt++; 161 err = 0; 162 163unlock: 164 mutex_unlock(&crypto_default_rng_lock); 165 166 return err; 167} 168EXPORT_SYMBOL_GPL(crypto_get_default_rng); 169 170void crypto_put_default_rng(void) 171{ 172 mutex_lock(&crypto_default_rng_lock); 173 crypto_default_rng_refcnt--; 174 mutex_unlock(&crypto_default_rng_lock); 175} 176EXPORT_SYMBOL_GPL(crypto_put_default_rng); 177 178#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) 179int crypto_del_default_rng(void) 180{ 181 int err = -EBUSY; 182 183 mutex_lock(&crypto_default_rng_lock); 184 if (crypto_default_rng_refcnt) 185 goto out; 186 187 crypto_free_rng(crypto_default_rng); 188 crypto_default_rng = NULL; 189 190 err = 0; 191 192out: 193 mutex_unlock(&crypto_default_rng_lock); 194 195 return err; 196} 197EXPORT_SYMBOL_GPL(crypto_del_default_rng); 198#endif 199 200int crypto_register_rng(struct rng_alg *alg) 201{ 202 struct crypto_istat_rng *istat = rng_get_stat(alg); 203 struct crypto_alg *base = &alg->base; 204 205 if (alg->seedsize > PAGE_SIZE / 8) 206 return -EINVAL; 207 208 base->cra_type = &crypto_rng_type; 209 base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 210 base->cra_flags |= CRYPTO_ALG_TYPE_RNG; 211 212 if (IS_ENABLED(CONFIG_CRYPTO_STATS)) 213 memset(istat, 0, sizeof(*istat)); 214 215 return crypto_register_alg(base); 216} 217EXPORT_SYMBOL_GPL(crypto_register_rng); 218 219void crypto_unregister_rng(struct rng_alg *alg) 220{ 221 crypto_unregister_alg(&alg->base); 222} 223EXPORT_SYMBOL_GPL(crypto_unregister_rng); 224 225int crypto_register_rngs(struct rng_alg *algs, int count) 226{ 227 int i, ret; 228 229 for (i = 0; i < count; i++) { 230 ret = crypto_register_rng(algs + i); 231 if (ret) 232 goto err; 233 } 234 235 return 0; 236 237err: 238 for (--i; i >= 0; --i) 239 crypto_unregister_rng(algs + i); 240 241 return ret; 242} 243EXPORT_SYMBOL_GPL(crypto_register_rngs); 244 245void crypto_unregister_rngs(struct rng_alg *algs, int count) 246{ 247 int i; 248 249 for (i = count - 1; i >= 0; --i) 250 crypto_unregister_rng(algs + i); 251} 252EXPORT_SYMBOL_GPL(crypto_unregister_rngs); 253 254MODULE_LICENSE("GPL"); 255MODULE_DESCRIPTION("Random Number Generator"); 256