• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Cryptographic API.
3  *
4  * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
5  *
6  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
7  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
8  *
9  * The HMAC implementation is derived from USAGI.
10  * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the Free
14  * Software Foundation; either version 2 of the License, or (at your option)
15  * any later version.
16  *
17  */
18 
19 #include <crypto/internal/hash.h>
20 #include <crypto/scatterwalk.h>
21 #include <linux/err.h>
22 #include <linux/init.h>
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/scatterlist.h>
26 #include <linux/slab.h>
27 #include <linux/string.h>
28 
29 struct hmac_ctx {
30 	struct crypto_hash *child;
31 };
32 
align_ptr(void * p,unsigned int align)33 static inline void *align_ptr(void *p, unsigned int align)
34 {
35 	return (void *)ALIGN((unsigned long)p, align);
36 }
37 
hmac_ctx(struct crypto_hash * tfm)38 static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
39 {
40 	return align_ptr(crypto_hash_ctx_aligned(tfm) +
41 			 crypto_hash_blocksize(tfm) * 2 +
42 			 crypto_hash_digestsize(tfm), sizeof(void *));
43 }
44 
hmac_setkey(struct crypto_hash * parent,const u8 * inkey,unsigned int keylen)45 static int hmac_setkey(struct crypto_hash *parent,
46 		       const u8 *inkey, unsigned int keylen)
47 {
48 	int bs = crypto_hash_blocksize(parent);
49 	int ds = crypto_hash_digestsize(parent);
50 	char *ipad = crypto_hash_ctx_aligned(parent);
51 	char *opad = ipad + bs;
52 	char *digest = opad + bs;
53 	struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
54 	struct crypto_hash *tfm = ctx->child;
55 	unsigned int i;
56 
57 	if (keylen > bs) {
58 		struct hash_desc desc;
59 		struct scatterlist tmp;
60 		int tmplen;
61 		int err;
62 
63 		desc.tfm = tfm;
64 		desc.flags = crypto_hash_get_flags(parent);
65 		desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
66 
67 		err = crypto_hash_init(&desc);
68 		if (err)
69 			return err;
70 
71 		tmplen = bs * 2 + ds;
72 		sg_init_one(&tmp, ipad, tmplen);
73 
74 		for (; keylen > tmplen; inkey += tmplen, keylen -= tmplen) {
75 			memcpy(ipad, inkey, tmplen);
76 			err = crypto_hash_update(&desc, &tmp, tmplen);
77 			if (err)
78 				return err;
79 		}
80 
81 		if (keylen) {
82 			memcpy(ipad, inkey, keylen);
83 			err = crypto_hash_update(&desc, &tmp, keylen);
84 			if (err)
85 				return err;
86 		}
87 
88 		err = crypto_hash_final(&desc, digest);
89 		if (err)
90 			return err;
91 
92 		inkey = digest;
93 		keylen = ds;
94 	}
95 
96 	memcpy(ipad, inkey, keylen);
97 	memset(ipad + keylen, 0, bs - keylen);
98 	memcpy(opad, ipad, bs);
99 
100 	for (i = 0; i < bs; i++) {
101 		ipad[i] ^= 0x36;
102 		opad[i] ^= 0x5c;
103 	}
104 
105 	return 0;
106 }
107 
hmac_init(struct hash_desc * pdesc)108 static int hmac_init(struct hash_desc *pdesc)
109 {
110 	struct crypto_hash *parent = pdesc->tfm;
111 	int bs = crypto_hash_blocksize(parent);
112 	int ds = crypto_hash_digestsize(parent);
113 	char *ipad = crypto_hash_ctx_aligned(parent);
114 	struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
115 	struct hash_desc desc;
116 	struct scatterlist tmp;
117 	int err;
118 
119 	desc.tfm = ctx->child;
120 	desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
121 	sg_init_one(&tmp, ipad, bs);
122 
123 	err = crypto_hash_init(&desc);
124 	if (unlikely(err))
125 		return err;
126 
127 	return crypto_hash_update(&desc, &tmp, bs);
128 }
129 
hmac_update(struct hash_desc * pdesc,struct scatterlist * sg,unsigned int nbytes)130 static int hmac_update(struct hash_desc *pdesc,
131 		       struct scatterlist *sg, unsigned int nbytes)
132 {
133 	struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
134 	struct hash_desc desc;
135 
136 	desc.tfm = ctx->child;
137 	desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
138 
139 	return crypto_hash_update(&desc, sg, nbytes);
140 }
141 
hmac_final(struct hash_desc * pdesc,u8 * out)142 static int hmac_final(struct hash_desc *pdesc, u8 *out)
143 {
144 	struct crypto_hash *parent = pdesc->tfm;
145 	int bs = crypto_hash_blocksize(parent);
146 	int ds = crypto_hash_digestsize(parent);
147 	char *opad = crypto_hash_ctx_aligned(parent) + bs;
148 	char *digest = opad + bs;
149 	struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
150 	struct hash_desc desc;
151 	struct scatterlist tmp;
152 	int err;
153 
154 	desc.tfm = ctx->child;
155 	desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
156 	sg_init_one(&tmp, opad, bs + ds);
157 
158 	err = crypto_hash_final(&desc, digest);
159 	if (unlikely(err))
160 		return err;
161 
162 	return crypto_hash_digest(&desc, &tmp, bs + ds, out);
163 }
164 
hmac_digest(struct hash_desc * pdesc,struct scatterlist * sg,unsigned int nbytes,u8 * out)165 static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
166 		       unsigned int nbytes, u8 *out)
167 {
168 	struct crypto_hash *parent = pdesc->tfm;
169 	int bs = crypto_hash_blocksize(parent);
170 	int ds = crypto_hash_digestsize(parent);
171 	char *ipad = crypto_hash_ctx_aligned(parent);
172 	char *opad = ipad + bs;
173 	char *digest = opad + bs;
174 	struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
175 	struct hash_desc desc;
176 	struct scatterlist sg1[2];
177 	struct scatterlist sg2[1];
178 	int err;
179 
180 	desc.tfm = ctx->child;
181 	desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
182 
183 	sg_init_table(sg1, 2);
184 	sg_set_buf(sg1, ipad, bs);
185 	scatterwalk_sg_chain(sg1, 2, sg);
186 
187 	sg_init_table(sg2, 1);
188 	sg_set_buf(sg2, opad, bs + ds);
189 
190 	err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
191 	if (unlikely(err))
192 		return err;
193 
194 	return crypto_hash_digest(&desc, sg2, bs + ds, out);
195 }
196 
hmac_init_tfm(struct crypto_tfm * tfm)197 static int hmac_init_tfm(struct crypto_tfm *tfm)
198 {
199 	struct crypto_hash *hash;
200 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
201 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
202 	struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
203 
204 	hash = crypto_spawn_hash(spawn);
205 	if (IS_ERR(hash))
206 		return PTR_ERR(hash);
207 
208 	ctx->child = hash;
209 	return 0;
210 }
211 
hmac_exit_tfm(struct crypto_tfm * tfm)212 static void hmac_exit_tfm(struct crypto_tfm *tfm)
213 {
214 	struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
215 	crypto_free_hash(ctx->child);
216 }
217 
hmac_free(struct crypto_instance * inst)218 static void hmac_free(struct crypto_instance *inst)
219 {
220 	crypto_drop_spawn(crypto_instance_ctx(inst));
221 	kfree(inst);
222 }
223 
hmac_alloc(struct rtattr ** tb)224 static struct crypto_instance *hmac_alloc(struct rtattr **tb)
225 {
226 	struct crypto_instance *inst;
227 	struct crypto_alg *alg;
228 	int err;
229 	int ds;
230 
231 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
232 	if (err)
233 		return ERR_PTR(err);
234 
235 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
236 				  CRYPTO_ALG_TYPE_HASH_MASK);
237 	if (IS_ERR(alg))
238 		return ERR_CAST(alg);
239 
240 	inst = ERR_PTR(-EINVAL);
241 	ds = alg->cra_type == &crypto_hash_type ?
242 	     alg->cra_hash.digestsize :
243 	     alg->cra_type ?
244 	     __crypto_shash_alg(alg)->digestsize :
245 	     alg->cra_digest.dia_digestsize;
246 	if (ds > alg->cra_blocksize)
247 		goto out_put_alg;
248 
249 	inst = crypto_alloc_instance("hmac", alg);
250 	if (IS_ERR(inst))
251 		goto out_put_alg;
252 
253 	inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
254 	inst->alg.cra_priority = alg->cra_priority;
255 	inst->alg.cra_blocksize = alg->cra_blocksize;
256 	inst->alg.cra_alignmask = alg->cra_alignmask;
257 	inst->alg.cra_type = &crypto_hash_type;
258 
259 	inst->alg.cra_hash.digestsize = ds;
260 
261 	inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
262 				ALIGN(inst->alg.cra_blocksize * 2 + ds,
263 				      sizeof(void *));
264 
265 	inst->alg.cra_init = hmac_init_tfm;
266 	inst->alg.cra_exit = hmac_exit_tfm;
267 
268 	inst->alg.cra_hash.init = hmac_init;
269 	inst->alg.cra_hash.update = hmac_update;
270 	inst->alg.cra_hash.final = hmac_final;
271 	inst->alg.cra_hash.digest = hmac_digest;
272 	inst->alg.cra_hash.setkey = hmac_setkey;
273 
274 out_put_alg:
275 	crypto_mod_put(alg);
276 	return inst;
277 }
278 
279 static struct crypto_template hmac_tmpl = {
280 	.name = "hmac",
281 	.alloc = hmac_alloc,
282 	.free = hmac_free,
283 	.module = THIS_MODULE,
284 };
285 
hmac_module_init(void)286 static int __init hmac_module_init(void)
287 {
288 	return crypto_register_template(&hmac_tmpl);
289 }
290 
hmac_module_exit(void)291 static void __exit hmac_module_exit(void)
292 {
293 	crypto_unregister_template(&hmac_tmpl);
294 }
295 
296 module_init(hmac_module_init);
297 module_exit(hmac_module_exit);
298 
299 MODULE_LICENSE("GPL");
300 MODULE_DESCRIPTION("HMAC hash algorithm");
301