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 26 static DEFINE_MUTEX(crypto_default_rng_lock); 27 struct crypto_rng *crypto_default_rng; 28 EXPORT_SYMBOL_GPL(crypto_default_rng); 29 static int crypto_default_rng_refcnt; 30 31 int 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); 53 free_buf: 54 kfree_sensitive(buf); 55 out: 56 return crypto_rng_errstat(alg, err); 57 } 58 EXPORT_SYMBOL_GPL(crypto_rng_reset); 59 60 static int crypto_rng_init_tfm(struct crypto_tfm *tfm) 61 { 62 return 0; 63 } 64 65 static 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 72 static 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 86 static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 87 __maybe_unused; 88 static 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 94 static 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 115 static 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 #ifdef 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 133 struct 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 } 137 EXPORT_SYMBOL_GPL(crypto_alloc_rng); 138 139 int 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 163 unlock: 164 mutex_unlock(&crypto_default_rng_lock); 165 166 return err; 167 } 168 EXPORT_SYMBOL_GPL(crypto_get_default_rng); 169 170 void 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 } 176 EXPORT_SYMBOL_GPL(crypto_put_default_rng); 177 178 #if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) 179 int 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 192 out: 193 mutex_unlock(&crypto_default_rng_lock); 194 195 return err; 196 } 197 EXPORT_SYMBOL_GPL(crypto_del_default_rng); 198 #endif 199 200 int 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 } 217 EXPORT_SYMBOL_GPL(crypto_register_rng); 218 219 void crypto_unregister_rng(struct rng_alg *alg) 220 { 221 crypto_unregister_alg(&alg->base); 222 } 223 EXPORT_SYMBOL_GPL(crypto_unregister_rng); 224 225 int 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 237 err: 238 for (--i; i >= 0; --i) 239 crypto_unregister_rng(algs + i); 240 241 return ret; 242 } 243 EXPORT_SYMBOL_GPL(crypto_register_rngs); 244 245 void 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 } 252 EXPORT_SYMBOL_GPL(crypto_unregister_rngs); 253 254 MODULE_LICENSE("GPL"); 255 MODULE_DESCRIPTION("Random Number Generator"); 256