blob: f1d64948f6fc8037edd0458eb1bd390d64c717d8 [file] [log] [blame]
Neil Horman17f0f4a2008-08-14 22:15:52 +10001/*
2 * Cryptographic API.
3 *
4 * RNG operations.
5 *
6 * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 */
14
Arun Sharma600634972011-07-26 16:09:06 -070015#include <linux/atomic.h>
Neil Horman17f0f4a2008-08-14 22:15:52 +100016#include <crypto/internal/rng.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/mutex.h>
20#include <linux/random.h>
21#include <linux/seq_file.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Neil Horman17f0f4a2008-08-14 22:15:52 +100023#include <linux/string.h>
Steffen Klassert792608e2011-09-27 07:47:11 +020024#include <linux/cryptouser.h>
25#include <net/netlink.h>
Neil Horman17f0f4a2008-08-14 22:15:52 +100026
Herbert Xud0e83052015-04-20 13:39:03 +080027#include "internal.h"
28
Neil Horman17f0f4a2008-08-14 22:15:52 +100029static DEFINE_MUTEX(crypto_default_rng_lock);
30struct crypto_rng *crypto_default_rng;
31EXPORT_SYMBOL_GPL(crypto_default_rng);
32static int crypto_default_rng_refcnt;
33
Herbert Xud0e83052015-04-20 13:39:03 +080034static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm)
35{
36 return container_of(tfm, struct crypto_rng, base);
37}
38
Herbert Xuff030b02015-04-20 13:39:04 +080039static int generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen,
40 u8 *dst, unsigned int dlen)
41{
42 return crypto_rng_alg(tfm)->rng_make_random(tfm, dst, dlen);
43}
44
Herbert Xu3c5d8fa2015-04-21 10:46:37 +080045static int rngapi_reset(struct crypto_rng *tfm, const u8 *seed,
46 unsigned int slen)
47{
48 u8 *buf = NULL;
49 u8 *src = (u8 *)seed;
50 int err;
51
52 if (slen) {
53 buf = kmalloc(slen, GFP_KERNEL);
54 if (!buf)
55 return -ENOMEM;
56
57 memcpy(buf, seed, slen);
58 src = buf;
59 }
60
61 err = crypto_rng_alg(tfm)->rng_reset(tfm, src, slen);
62
63 kzfree(buf);
64 return err;
65}
66
67int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
Neil Horman17f0f4a2008-08-14 22:15:52 +100068{
69 u8 *buf = NULL;
70 int err;
71
72 if (!seed && slen) {
73 buf = kmalloc(slen, GFP_KERNEL);
74 if (!buf)
75 return -ENOMEM;
76
77 get_random_bytes(buf, slen);
78 seed = buf;
79 }
80
Herbert Xu3c5d8fa2015-04-21 10:46:37 +080081 err = tfm->seed(tfm, seed, slen);
Neil Horman17f0f4a2008-08-14 22:15:52 +100082
83 kfree(buf);
84 return err;
85}
Herbert Xu3c5d8fa2015-04-21 10:46:37 +080086EXPORT_SYMBOL_GPL(crypto_rng_reset);
Neil Horman17f0f4a2008-08-14 22:15:52 +100087
Herbert Xud0e83052015-04-20 13:39:03 +080088static int crypto_rng_init_tfm(struct crypto_tfm *tfm)
Neil Horman17f0f4a2008-08-14 22:15:52 +100089{
Herbert Xud0e83052015-04-20 13:39:03 +080090 struct crypto_rng *rng = __crypto_rng_cast(tfm);
Neil Horman17f0f4a2008-08-14 22:15:52 +100091
Herbert Xuff030b02015-04-20 13:39:04 +080092 rng->generate = generate;
Herbert Xud0e83052015-04-20 13:39:03 +080093 rng->seed = rngapi_reset;
Neil Horman17f0f4a2008-08-14 22:15:52 +100094
95 return 0;
96}
97
Herbert Xu3acc8472011-11-03 23:46:07 +110098#ifdef CONFIG_NET
Steffen Klassert792608e2011-09-27 07:47:11 +020099static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
100{
101 struct crypto_report_rng rrng;
102
Mathias Krause9a5467b2013-02-05 18:19:13 +0100103 strncpy(rrng.type, "rng", sizeof(rrng.type));
Steffen Klassert792608e2011-09-27 07:47:11 +0200104
105 rrng.seedsize = alg->cra_rng.seedsize;
106
David S. Miller6662df32012-04-01 20:19:05 -0400107 if (nla_put(skb, CRYPTOCFGA_REPORT_RNG,
108 sizeof(struct crypto_report_rng), &rrng))
109 goto nla_put_failure;
Steffen Klassert792608e2011-09-27 07:47:11 +0200110 return 0;
111
112nla_put_failure:
113 return -EMSGSIZE;
114}
Herbert Xu3acc8472011-11-03 23:46:07 +1100115#else
116static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
117{
118 return -ENOSYS;
119}
120#endif
Steffen Klassert792608e2011-09-27 07:47:11 +0200121
Neil Horman17f0f4a2008-08-14 22:15:52 +1000122static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
123 __attribute__ ((unused));
124static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
125{
126 seq_printf(m, "type : rng\n");
127 seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
128}
129
Neil Horman17f0f4a2008-08-14 22:15:52 +1000130const struct crypto_type crypto_rng_type = {
Herbert Xud0e83052015-04-20 13:39:03 +0800131 .extsize = crypto_alg_extsize,
132 .init_tfm = crypto_rng_init_tfm,
Neil Horman17f0f4a2008-08-14 22:15:52 +1000133#ifdef CONFIG_PROC_FS
134 .show = crypto_rng_show,
135#endif
Steffen Klassert792608e2011-09-27 07:47:11 +0200136 .report = crypto_rng_report,
Herbert Xud0e83052015-04-20 13:39:03 +0800137 .maskclear = ~CRYPTO_ALG_TYPE_MASK,
138 .maskset = CRYPTO_ALG_TYPE_MASK,
139 .type = CRYPTO_ALG_TYPE_RNG,
140 .tfmsize = offsetof(struct crypto_rng, base),
Neil Horman17f0f4a2008-08-14 22:15:52 +1000141};
142EXPORT_SYMBOL_GPL(crypto_rng_type);
143
Herbert Xud0e83052015-04-20 13:39:03 +0800144struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask)
145{
146 return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask);
147}
148EXPORT_SYMBOL_GPL(crypto_alloc_rng);
149
Neil Horman17f0f4a2008-08-14 22:15:52 +1000150int crypto_get_default_rng(void)
151{
152 struct crypto_rng *rng;
153 int err;
154
155 mutex_lock(&crypto_default_rng_lock);
156 if (!crypto_default_rng) {
157 rng = crypto_alloc_rng("stdrng", 0, 0);
158 err = PTR_ERR(rng);
159 if (IS_ERR(rng))
160 goto unlock;
161
162 err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
163 if (err) {
164 crypto_free_rng(rng);
165 goto unlock;
166 }
167
168 crypto_default_rng = rng;
169 }
170
171 crypto_default_rng_refcnt++;
172 err = 0;
173
174unlock:
175 mutex_unlock(&crypto_default_rng_lock);
176
177 return err;
178}
179EXPORT_SYMBOL_GPL(crypto_get_default_rng);
180
181void crypto_put_default_rng(void)
182{
183 mutex_lock(&crypto_default_rng_lock);
184 if (!--crypto_default_rng_refcnt) {
185 crypto_free_rng(crypto_default_rng);
186 crypto_default_rng = NULL;
187 }
188 mutex_unlock(&crypto_default_rng_lock);
189}
190EXPORT_SYMBOL_GPL(crypto_put_default_rng);
191
192MODULE_LICENSE("GPL");
Christian Kujaua8ccc392009-08-13 11:53:56 +1000193MODULE_DESCRIPTION("Random Number Generator");