aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/hmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/hmac.c')
-rw-r--r--crypto/hmac.c278
1 files changed, 203 insertions, 75 deletions
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 46120dee5ada..f403b6946047 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -4,121 +4,249 @@
4 * HMAC: Keyed-Hashing for Message Authentication (RFC2104). 4 * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
5 * 5 *
6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
7 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
7 * 8 *
8 * The HMAC implementation is derived from USAGI. 9 * The HMAC implementation is derived from USAGI.
9 * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI 10 * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
10 * 11 *
11 * This program is free software; you can redistribute it and/or modify it 12 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free 13 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option) 14 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version. 15 * any later version.
15 * 16 *
16 */ 17 */
17#include <linux/crypto.h> 18
18#include <linux/mm.h> 19#include <crypto/algapi.h>
19#include <linux/highmem.h> 20#include <linux/err.h>
20#include <linux/slab.h> 21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
21#include <linux/scatterlist.h> 24#include <linux/scatterlist.h>
22#include "internal.h" 25#include <linux/slab.h>
26#include <linux/string.h>
23 27
24static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen) 28struct hmac_ctx {
29 struct crypto_hash *child;
30};
31
32static inline void *align_ptr(void *p, unsigned int align)
25{ 33{
26 struct scatterlist tmp; 34 return (void *)ALIGN((unsigned long)p, align);
27
28 sg_set_buf(&tmp, key, keylen);
29 crypto_digest_digest(tfm, &tmp, 1, key);
30} 35}
31 36
32int crypto_alloc_hmac_block(struct crypto_tfm *tfm) 37static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
33{ 38{
34 int ret = 0; 39 return align_ptr(crypto_hash_ctx_aligned(tfm) +
40 crypto_hash_blocksize(tfm) * 2 +
41 crypto_hash_digestsize(tfm), sizeof(void *));
42}
43
44static int hmac_setkey(struct crypto_hash *parent,
45 const u8 *inkey, unsigned int keylen)
46{
47 int bs = crypto_hash_blocksize(parent);
48 int ds = crypto_hash_digestsize(parent);
49 char *ipad = crypto_hash_ctx_aligned(parent);
50 char *opad = ipad + bs;
51 char *digest = opad + bs;
52 struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
53 struct crypto_hash *tfm = ctx->child;
54 unsigned int i;
55
56 if (keylen > bs) {
57 struct hash_desc desc;
58 struct scatterlist tmp;
59 int err;
60
61 desc.tfm = tfm;
62 desc.flags = crypto_hash_get_flags(parent);
63 desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
64 sg_set_buf(&tmp, inkey, keylen);
35 65
36 BUG_ON(!crypto_tfm_alg_blocksize(tfm)); 66 err = crypto_hash_digest(&desc, &tmp, keylen, digest);
37 67 if (err)
38 tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm), 68 return err;
39 GFP_KERNEL);
40 if (tfm->crt_digest.dit_hmac_block == NULL)
41 ret = -ENOMEM;
42 69
43 return ret; 70 inkey = digest;
44 71 keylen = ds;
72 }
73
74 memcpy(ipad, inkey, keylen);
75 memset(ipad + keylen, 0, bs - keylen);
76 memcpy(opad, ipad, bs);
77
78 for (i = 0; i < bs; i++) {
79 ipad[i] ^= 0x36;
80 opad[i] ^= 0x5c;
81 }
82
83 return 0;
45} 84}
46 85
47void crypto_free_hmac_block(struct crypto_tfm *tfm) 86static int hmac_init(struct hash_desc *pdesc)
48{ 87{
49 kfree(tfm->crt_digest.dit_hmac_block); 88 struct crypto_hash *parent = pdesc->tfm;
89 int bs = crypto_hash_blocksize(parent);
90 int ds = crypto_hash_digestsize(parent);
91 char *ipad = crypto_hash_ctx_aligned(parent);
92 struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
93 struct hash_desc desc;
94 struct scatterlist tmp;
95
96 desc.tfm = ctx->child;
97 desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
98 sg_set_buf(&tmp, ipad, bs);
99
100 return unlikely(crypto_hash_init(&desc)) ?:
101 crypto_hash_update(&desc, &tmp, 1);
50} 102}
51 103
52void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen) 104static int hmac_update(struct hash_desc *pdesc,
105 struct scatterlist *sg, unsigned int nbytes)
53{ 106{
54 unsigned int i; 107 struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
108 struct hash_desc desc;
109
110 desc.tfm = ctx->child;
111 desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
112
113 return crypto_hash_update(&desc, sg, nbytes);
114}
115
116static int hmac_final(struct hash_desc *pdesc, u8 *out)
117{
118 struct crypto_hash *parent = pdesc->tfm;
119 int bs = crypto_hash_blocksize(parent);
120 int ds = crypto_hash_digestsize(parent);
121 char *opad = crypto_hash_ctx_aligned(parent) + bs;
122 char *digest = opad + bs;
123 struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
124 struct hash_desc desc;
55 struct scatterlist tmp; 125 struct scatterlist tmp;
56 char *ipad = tfm->crt_digest.dit_hmac_block;
57
58 if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
59 hash_key(tfm, key, *keylen);
60 *keylen = crypto_tfm_alg_digestsize(tfm);
61 }
62 126
63 memset(ipad, 0, crypto_tfm_alg_blocksize(tfm)); 127 desc.tfm = ctx->child;
64 memcpy(ipad, key, *keylen); 128 desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
129 sg_set_buf(&tmp, opad, bs + ds);
65 130
66 for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) 131 return unlikely(crypto_hash_final(&desc, digest)) ?:
67 ipad[i] ^= 0x36; 132 crypto_hash_digest(&desc, &tmp, bs + ds, out);
133}
68 134
69 sg_set_buf(&tmp, ipad, crypto_tfm_alg_blocksize(tfm)); 135static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
70 136 unsigned int nbytes, u8 *out)
71 crypto_digest_init(tfm); 137{
72 crypto_digest_update(tfm, &tmp, 1); 138 struct crypto_hash *parent = pdesc->tfm;
139 int bs = crypto_hash_blocksize(parent);
140 int ds = crypto_hash_digestsize(parent);
141 char *ipad = crypto_hash_ctx_aligned(parent);
142 char *opad = ipad + bs;
143 char *digest = opad + bs;
144 struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
145 struct hash_desc desc;
146 struct scatterlist sg1[2];
147 struct scatterlist sg2[1];
148
149 desc.tfm = ctx->child;
150 desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
151
152 sg_set_buf(sg1, ipad, bs);
153 sg1[1].page = (void *)sg;
154 sg1[1].length = 0;
155 sg_set_buf(sg2, opad, bs + ds);
156
157 return unlikely(crypto_hash_digest(&desc, sg1, nbytes + bs, digest)) ?:
158 crypto_hash_digest(&desc, sg2, bs + ds, out);
73} 159}
74 160
75void crypto_hmac_update(struct crypto_tfm *tfm, 161static int hmac_init_tfm(struct crypto_tfm *tfm)
76 struct scatterlist *sg, unsigned int nsg)
77{ 162{
78 crypto_digest_update(tfm, sg, nsg); 163 struct crypto_instance *inst = (void *)tfm->__crt_alg;
164 struct crypto_spawn *spawn = crypto_instance_ctx(inst);
165 struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
166
167 tfm = crypto_spawn_tfm(spawn);
168 if (IS_ERR(tfm))
169 return PTR_ERR(tfm);
170
171 ctx->child = crypto_hash_cast(tfm);
172 return 0;
79} 173}
80 174
81void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, 175static void hmac_exit_tfm(struct crypto_tfm *tfm)
82 unsigned int *keylen, u8 *out)
83{ 176{
84 unsigned int i; 177 struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
85 struct scatterlist tmp; 178 crypto_free_hash(ctx->child);
86 char *opad = tfm->crt_digest.dit_hmac_block; 179}
87
88 if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
89 hash_key(tfm, key, *keylen);
90 *keylen = crypto_tfm_alg_digestsize(tfm);
91 }
92 180
93 crypto_digest_final(tfm, out); 181static void hmac_free(struct crypto_instance *inst)
182{
183 crypto_drop_spawn(crypto_instance_ctx(inst));
184 kfree(inst);
185}
94 186
95 memset(opad, 0, crypto_tfm_alg_blocksize(tfm)); 187static struct crypto_instance *hmac_alloc(void *param, unsigned int len)
96 memcpy(opad, key, *keylen); 188{
97 189 struct crypto_instance *inst;
98 for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) 190 struct crypto_alg *alg;
99 opad[i] ^= 0x5c; 191
192 alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH,
193 CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
194 if (IS_ERR(alg))
195 return ERR_PTR(PTR_ERR(alg));
196
197 inst = crypto_alloc_instance("hmac", alg);
198 if (IS_ERR(inst))
199 goto out_put_alg;
200
201 inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
202 inst->alg.cra_priority = alg->cra_priority;
203 inst->alg.cra_blocksize = alg->cra_blocksize;
204 inst->alg.cra_alignmask = alg->cra_alignmask;
205 inst->alg.cra_type = &crypto_hash_type;
206
207 inst->alg.cra_hash.digestsize =
208 (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
209 CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
210 alg->cra_digest.dia_digestsize;
211
212 inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
213 ALIGN(inst->alg.cra_blocksize * 2 +
214 inst->alg.cra_hash.digestsize,
215 sizeof(void *));
216
217 inst->alg.cra_init = hmac_init_tfm;
218 inst->alg.cra_exit = hmac_exit_tfm;
219
220 inst->alg.cra_hash.init = hmac_init;
221 inst->alg.cra_hash.update = hmac_update;
222 inst->alg.cra_hash.final = hmac_final;
223 inst->alg.cra_hash.digest = hmac_digest;
224 inst->alg.cra_hash.setkey = hmac_setkey;
225
226out_put_alg:
227 crypto_mod_put(alg);
228 return inst;
229}
100 230
101 sg_set_buf(&tmp, opad, crypto_tfm_alg_blocksize(tfm)); 231static struct crypto_template hmac_tmpl = {
232 .name = "hmac",
233 .alloc = hmac_alloc,
234 .free = hmac_free,
235 .module = THIS_MODULE,
236};
102 237
103 crypto_digest_init(tfm); 238static int __init hmac_module_init(void)
104 crypto_digest_update(tfm, &tmp, 1); 239{
105 240 return crypto_register_template(&hmac_tmpl);
106 sg_set_buf(&tmp, out, crypto_tfm_alg_digestsize(tfm));
107
108 crypto_digest_update(tfm, &tmp, 1);
109 crypto_digest_final(tfm, out);
110} 241}
111 242
112void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, 243static void __exit hmac_module_exit(void)
113 struct scatterlist *sg, unsigned int nsg, u8 *out)
114{ 244{
115 crypto_hmac_init(tfm, key, keylen); 245 crypto_unregister_template(&hmac_tmpl);
116 crypto_hmac_update(tfm, sg, nsg);
117 crypto_hmac_final(tfm, key, keylen, out);
118} 246}
119 247
120EXPORT_SYMBOL_GPL(crypto_hmac_init); 248module_init(hmac_module_init);
121EXPORT_SYMBOL_GPL(crypto_hmac_update); 249module_exit(hmac_module_exit);
122EXPORT_SYMBOL_GPL(crypto_hmac_final);
123EXPORT_SYMBOL_GPL(crypto_hmac);
124 250
251MODULE_LICENSE("GPL");
252MODULE_DESCRIPTION("HMAC hash algorithm");