Branch data Line data Source code
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 <linux/atomic.h> 12 : : #include <crypto/internal/rng.h> 13 : : #include <linux/err.h> 14 : : #include <linux/module.h> 15 : : #include <linux/mutex.h> 16 : : #include <linux/random.h> 17 : : #include <linux/seq_file.h> 18 : : #include <linux/slab.h> 19 : : #include <linux/string.h> 20 : : #include <linux/cryptouser.h> 21 : : #include <linux/compiler.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 : 0 : int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) 32 : : { 33 : 0 : struct crypto_alg *alg = tfm->base.__crt_alg; 34 : : u8 *buf = NULL; 35 : : int err; 36 : : 37 : : crypto_stats_get(alg); 38 : 0 : if (!seed && slen) { 39 : : buf = kmalloc(slen, GFP_KERNEL); 40 : 0 : if (!buf) { 41 : 0 : crypto_alg_put(alg); 42 : 0 : return -ENOMEM; 43 : : } 44 : : 45 : 0 : err = get_random_bytes_wait(buf, slen); 46 : 0 : if (err) { 47 : 0 : crypto_alg_put(alg); 48 : 0 : goto out; 49 : : } 50 : : seed = buf; 51 : : } 52 : : 53 : 0 : err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); 54 : : crypto_stats_rng_seed(alg, err); 55 : : out: 56 : 0 : kzfree(buf); 57 : 0 : return err; 58 : : } 59 : : EXPORT_SYMBOL_GPL(crypto_rng_reset); 60 : : 61 : 0 : static int crypto_rng_init_tfm(struct crypto_tfm *tfm) 62 : : { 63 : 0 : return 0; 64 : : } 65 : : 66 : : static unsigned int seedsize(struct crypto_alg *alg) 67 : : { 68 : : struct rng_alg *ralg = container_of(alg, struct rng_alg, base); 69 : : 70 : 0 : return ralg->seedsize; 71 : : } 72 : : 73 : : #ifdef CONFIG_NET 74 : 0 : static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) 75 : : { 76 : : struct crypto_report_rng rrng; 77 : : 78 : 0 : memset(&rrng, 0, sizeof(rrng)); 79 : : 80 : 0 : strscpy(rrng.type, "rng", sizeof(rrng.type)); 81 : : 82 : 0 : rrng.seedsize = seedsize(alg); 83 : : 84 : 0 : return nla_put(skb, CRYPTOCFGA_REPORT_RNG, sizeof(rrng), &rrng); 85 : : } 86 : : #else 87 : : static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) 88 : : { 89 : : return -ENOSYS; 90 : : } 91 : : #endif 92 : : 93 : : static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 94 : : __maybe_unused; 95 : 0 : static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) 96 : : { 97 : 0 : seq_printf(m, "type : rng\n"); 98 : 0 : seq_printf(m, "seedsize : %u\n", seedsize(alg)); 99 : 0 : } 100 : : 101 : : static const struct crypto_type crypto_rng_type = { 102 : : .extsize = crypto_alg_extsize, 103 : : .init_tfm = crypto_rng_init_tfm, 104 : : #ifdef CONFIG_PROC_FS 105 : : .show = crypto_rng_show, 106 : : #endif 107 : : .report = crypto_rng_report, 108 : : .maskclear = ~CRYPTO_ALG_TYPE_MASK, 109 : : .maskset = CRYPTO_ALG_TYPE_MASK, 110 : : .type = CRYPTO_ALG_TYPE_RNG, 111 : : .tfmsize = offsetof(struct crypto_rng, base), 112 : : }; 113 : : 114 : 0 : struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) 115 : : { 116 : 0 : return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask); 117 : : } 118 : : EXPORT_SYMBOL_GPL(crypto_alloc_rng); 119 : : 120 : 0 : int crypto_get_default_rng(void) 121 : : { 122 : : struct crypto_rng *rng; 123 : : int err; 124 : : 125 : 0 : mutex_lock(&crypto_default_rng_lock); 126 : 0 : if (!crypto_default_rng) { 127 : : rng = crypto_alloc_rng("stdrng", 0, 0); 128 : : err = PTR_ERR(rng); 129 : 0 : if (IS_ERR(rng)) 130 : : goto unlock; 131 : : 132 : 0 : err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); 133 : 0 : if (err) { 134 : : crypto_free_rng(rng); 135 : : goto unlock; 136 : : } 137 : : 138 : 0 : crypto_default_rng = rng; 139 : : } 140 : : 141 : 0 : crypto_default_rng_refcnt++; 142 : : err = 0; 143 : : 144 : : unlock: 145 : 0 : mutex_unlock(&crypto_default_rng_lock); 146 : : 147 : 0 : return err; 148 : : } 149 : : EXPORT_SYMBOL_GPL(crypto_get_default_rng); 150 : : 151 : 0 : void crypto_put_default_rng(void) 152 : : { 153 : 0 : mutex_lock(&crypto_default_rng_lock); 154 : 0 : crypto_default_rng_refcnt--; 155 : 0 : mutex_unlock(&crypto_default_rng_lock); 156 : 0 : } 157 : : EXPORT_SYMBOL_GPL(crypto_put_default_rng); 158 : : 159 : : #if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) 160 : 0 : int crypto_del_default_rng(void) 161 : : { 162 : : int err = -EBUSY; 163 : : 164 : 0 : mutex_lock(&crypto_default_rng_lock); 165 : 0 : if (crypto_default_rng_refcnt) 166 : : goto out; 167 : : 168 : 0 : crypto_free_rng(crypto_default_rng); 169 : 0 : crypto_default_rng = NULL; 170 : : 171 : : err = 0; 172 : : 173 : : out: 174 : 0 : mutex_unlock(&crypto_default_rng_lock); 175 : : 176 : 0 : return err; 177 : : } 178 : : EXPORT_SYMBOL_GPL(crypto_del_default_rng); 179 : : #endif 180 : : 181 : 0 : int crypto_register_rng(struct rng_alg *alg) 182 : : { 183 : 0 : struct crypto_alg *base = &alg->base; 184 : : 185 : 0 : if (alg->seedsize > PAGE_SIZE / 8) 186 : : return -EINVAL; 187 : : 188 : 0 : base->cra_type = &crypto_rng_type; 189 : 0 : base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 190 : 0 : base->cra_flags |= CRYPTO_ALG_TYPE_RNG; 191 : : 192 : 0 : return crypto_register_alg(base); 193 : : } 194 : : EXPORT_SYMBOL_GPL(crypto_register_rng); 195 : : 196 : 0 : void crypto_unregister_rng(struct rng_alg *alg) 197 : : { 198 : 0 : crypto_unregister_alg(&alg->base); 199 : 0 : } 200 : : EXPORT_SYMBOL_GPL(crypto_unregister_rng); 201 : : 202 : 0 : int crypto_register_rngs(struct rng_alg *algs, int count) 203 : : { 204 : : int i, ret; 205 : : 206 : 0 : for (i = 0; i < count; i++) { 207 : 0 : ret = crypto_register_rng(algs + i); 208 : 0 : if (ret) 209 : : goto err; 210 : : } 211 : : 212 : : return 0; 213 : : 214 : : err: 215 : 0 : for (--i; i >= 0; --i) 216 : 0 : crypto_unregister_rng(algs + i); 217 : : 218 : 0 : return ret; 219 : : } 220 : : EXPORT_SYMBOL_GPL(crypto_register_rngs); 221 : : 222 : 0 : void crypto_unregister_rngs(struct rng_alg *algs, int count) 223 : : { 224 : : int i; 225 : : 226 : 0 : for (i = count - 1; i >= 0; --i) 227 : 0 : crypto_unregister_rng(algs + i); 228 : 0 : } 229 : : EXPORT_SYMBOL_GPL(crypto_unregister_rngs); 230 : : 231 : : MODULE_LICENSE("GPL"); 232 : : MODULE_DESCRIPTION("Random Number Generator");