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