aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-08-19 08:24:23 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:46:17 -0400
commit055bcee3102dc35f019b69df9c2618e9d6dd1c09 (patch)
tree3f7c68abbbb5041d570e4cb8588f3943530bc0b7 /crypto
parent7226bc877a22244e8003924031435a4bffd52654 (diff)
[CRYPTO] digest: Added user API for new hash type
The existing digest user interface is inadequate for support asynchronous operations. For one it doesn't return a value to indicate success or failure, nor does it take a per-operation descriptor which is essential for the issuing of requests while other requests are still outstanding. This patch is the first in a series of steps to remodel the interface for asynchronous operations. For the ease of transition the new interface will be known as "hash" while the old one will remain as "digest". This patch also changes sg_next to allow chaining. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/Kconfig4
-rw-r--r--crypto/Makefile3
-rw-r--r--crypto/digest.c129
-rw-r--r--crypto/hash.c61
-rw-r--r--crypto/hmac.c12
-rw-r--r--crypto/scatterwalk.h4
6 files changed, 177 insertions, 36 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index be5eb0cb7c30..69c5f992bcd4 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -20,6 +20,10 @@ config CRYPTO_BLKCIPHER
20 tristate 20 tristate
21 select CRYPTO_ALGAPI 21 select CRYPTO_ALGAPI
22 22
23config CRYPTO_HASH
24 tristate
25 select CRYPTO_ALGAPI
26
23config CRYPTO_MANAGER 27config CRYPTO_MANAGER
24 tristate "Cryptographic algorithm manager" 28 tristate "Cryptographic algorithm manager"
25 select CRYPTO_ALGAPI 29 select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index 5e1ff4e0b1fc..72366208e291 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
10 10
11obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o 11obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
12 12
13crypto_hash-objs := hash.o
14obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
15
13obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o 16obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
14obj-$(CONFIG_CRYPTO_HMAC) += hmac.o 17obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
15obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o 18obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
diff --git a/crypto/digest.c b/crypto/digest.c
index 96244a528844..5873063db840 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -11,29 +11,89 @@
11 * any later version. 11 * any later version.
12 * 12 *
13 */ 13 */
14#include <linux/crypto.h> 14
15#include <linux/mm.h> 15#include <linux/mm.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/highmem.h> 17#include <linux/highmem.h>
18#include <asm/scatterlist.h> 18#include <linux/module.h>
19#include <linux/scatterlist.h>
20
19#include "internal.h" 21#include "internal.h"
22#include "scatterwalk.h"
20 23
21static void init(struct crypto_tfm *tfm) 24void crypto_digest_init(struct crypto_tfm *tfm)
22{ 25{
23 tfm->__crt_alg->cra_digest.dia_init(tfm); 26 struct crypto_hash *hash = crypto_hash_cast(tfm);
27 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
28
29 crypto_hash_init(&desc);
24} 30}
31EXPORT_SYMBOL_GPL(crypto_digest_init);
25 32
26static void update(struct crypto_tfm *tfm, 33void crypto_digest_update(struct crypto_tfm *tfm,
27 struct scatterlist *sg, unsigned int nsg) 34 struct scatterlist *sg, unsigned int nsg)
28{ 35{
36 struct crypto_hash *hash = crypto_hash_cast(tfm);
37 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
38 unsigned int nbytes = 0;
29 unsigned int i; 39 unsigned int i;
40
41 for (i = 0; i < nsg; i++)
42 nbytes += sg[i].length;
43
44 crypto_hash_update(&desc, sg, nbytes);
45}
46EXPORT_SYMBOL_GPL(crypto_digest_update);
47
48void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
49{
50 struct crypto_hash *hash = crypto_hash_cast(tfm);
51 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
52
53 crypto_hash_final(&desc, out);
54}
55EXPORT_SYMBOL_GPL(crypto_digest_final);
56
57void crypto_digest_digest(struct crypto_tfm *tfm,
58 struct scatterlist *sg, unsigned int nsg, u8 *out)
59{
60 struct crypto_hash *hash = crypto_hash_cast(tfm);
61 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
62 unsigned int nbytes = 0;
63 unsigned int i;
64
65 for (i = 0; i < nsg; i++)
66 nbytes += sg[i].length;
67
68 crypto_hash_digest(&desc, sg, nbytes, out);
69}
70EXPORT_SYMBOL_GPL(crypto_digest_digest);
71
72static int init(struct hash_desc *desc)
73{
74 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
75
76 tfm->__crt_alg->cra_digest.dia_init(tfm);
77 return 0;
78}
79
80static int update(struct hash_desc *desc,
81 struct scatterlist *sg, unsigned int nbytes)
82{
83 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
30 unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); 84 unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
31 85
32 for (i = 0; i < nsg; i++) { 86 if (!nbytes)
87 return 0;
88
89 for (;;) {
90 struct page *pg = sg->page;
91 unsigned int offset = sg->offset;
92 unsigned int l = sg->length;
33 93
34 struct page *pg = sg[i].page; 94 if (unlikely(l > nbytes))
35 unsigned int offset = sg[i].offset; 95 l = nbytes;
36 unsigned int l = sg[i].length; 96 nbytes -= l;
37 97
38 do { 98 do {
39 unsigned int bytes_from_page = min(l, ((unsigned int) 99 unsigned int bytes_from_page = min(l, ((unsigned int)
@@ -55,16 +115,23 @@ static void update(struct crypto_tfm *tfm,
55 tfm->__crt_alg->cra_digest.dia_update(tfm, p, 115 tfm->__crt_alg->cra_digest.dia_update(tfm, p,
56 bytes_from_page); 116 bytes_from_page);
57 crypto_kunmap(src, 0); 117 crypto_kunmap(src, 0);
58 crypto_yield(tfm->crt_flags); 118 crypto_yield(desc->flags);
59 offset = 0; 119 offset = 0;
60 pg++; 120 pg++;
61 l -= bytes_from_page; 121 l -= bytes_from_page;
62 } while (l > 0); 122 } while (l > 0);
123
124 if (!nbytes)
125 break;
126 sg = sg_next(sg);
63 } 127 }
128
129 return 0;
64} 130}
65 131
66static void final(struct crypto_tfm *tfm, u8 *out) 132static int final(struct hash_desc *desc, u8 *out)
67{ 133{
134 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
68 unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 135 unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
69 struct digest_alg *digest = &tfm->__crt_alg->cra_digest; 136 struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
70 137
@@ -78,26 +145,30 @@ static void final(struct crypto_tfm *tfm, u8 *out)
78 memcpy(out, dst, digest->dia_digestsize); 145 memcpy(out, dst, digest->dia_digestsize);
79 } else 146 } else
80 digest->dia_final(tfm, out); 147 digest->dia_final(tfm, out);
148
149 return 0;
81} 150}
82 151
83static int nosetkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 152static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
84{ 153{
85 tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 154 crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
86 return -ENOSYS; 155 return -ENOSYS;
87} 156}
88 157
89static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 158static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
90{ 159{
91 tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 160 struct crypto_tfm *tfm = crypto_hash_tfm(hash);
161
162 crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
92 return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen); 163 return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
93} 164}
94 165
95static void digest(struct crypto_tfm *tfm, 166static int digest(struct hash_desc *desc,
96 struct scatterlist *sg, unsigned int nsg, u8 *out) 167 struct scatterlist *sg, unsigned int nbytes, u8 *out)
97{ 168{
98 init(tfm); 169 init(desc);
99 update(tfm, sg, nsg); 170 update(desc, sg, nbytes);
100 final(tfm, out); 171 return final(desc, out);
101} 172}
102 173
103int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) 174int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
@@ -107,14 +178,18 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
107 178
108int crypto_init_digest_ops(struct crypto_tfm *tfm) 179int crypto_init_digest_ops(struct crypto_tfm *tfm)
109{ 180{
110 struct digest_tfm *ops = &tfm->crt_digest; 181 struct hash_tfm *ops = &tfm->crt_hash;
111 struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; 182 struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
183
184 if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
185 return -EINVAL;
112 186
113 ops->dit_init = init; 187 ops->init = init;
114 ops->dit_update = update; 188 ops->update = update;
115 ops->dit_final = final; 189 ops->final = final;
116 ops->dit_digest = digest; 190 ops->digest = digest;
117 ops->dit_setkey = dalg->dia_setkey ? setkey : nosetkey; 191 ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
192 ops->digestsize = dalg->dia_digestsize;
118 193
119 return crypto_alloc_hmac_block(tfm); 194 return crypto_alloc_hmac_block(tfm);
120} 195}
diff --git a/crypto/hash.c b/crypto/hash.c
new file mode 100644
index 000000000000..cdec23d885fe
--- /dev/null
+++ b/crypto/hash.c
@@ -0,0 +1,61 @@
1/*
2 * Cryptographic Hash operations.
3 *
4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12#include <linux/errno.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/seq_file.h>
16
17#include "internal.h"
18
19static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg)
20{
21 return alg->cra_ctxsize;
22}
23
24static int crypto_init_hash_ops(struct crypto_tfm *tfm)
25{
26 struct hash_tfm *crt = &tfm->crt_hash;
27 struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
28
29 if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
30 return -EINVAL;
31
32 crt->init = alg->init;
33 crt->update = alg->update;
34 crt->final = alg->final;
35 crt->digest = alg->digest;
36 crt->setkey = alg->setkey;
37 crt->digestsize = alg->digestsize;
38
39 return 0;
40}
41
42static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
43 __attribute_used__;
44static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
45{
46 seq_printf(m, "type : hash\n");
47 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
48 seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
49}
50
51const struct crypto_type crypto_hash_type = {
52 .ctxsize = crypto_hash_ctxsize,
53 .init = crypto_init_hash_ops,
54#ifdef CONFIG_PROC_FS
55 .show = crypto_hash_show,
56#endif
57};
58EXPORT_SYMBOL_GPL(crypto_hash_type);
59
60MODULE_LICENSE("GPL");
61MODULE_DESCRIPTION("Generic cryptographic hash type");
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 46120dee5ada..ecf7b0a95b56 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -35,9 +35,9 @@ int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
35 35
36 BUG_ON(!crypto_tfm_alg_blocksize(tfm)); 36 BUG_ON(!crypto_tfm_alg_blocksize(tfm));
37 37
38 tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm), 38 tfm->crt_hash.hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
39 GFP_KERNEL); 39 GFP_KERNEL);
40 if (tfm->crt_digest.dit_hmac_block == NULL) 40 if (tfm->crt_hash.hmac_block == NULL)
41 ret = -ENOMEM; 41 ret = -ENOMEM;
42 42
43 return ret; 43 return ret;
@@ -46,14 +46,14 @@ int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
46 46
47void crypto_free_hmac_block(struct crypto_tfm *tfm) 47void crypto_free_hmac_block(struct crypto_tfm *tfm)
48{ 48{
49 kfree(tfm->crt_digest.dit_hmac_block); 49 kfree(tfm->crt_hash.hmac_block);
50} 50}
51 51
52void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen) 52void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
53{ 53{
54 unsigned int i; 54 unsigned int i;
55 struct scatterlist tmp; 55 struct scatterlist tmp;
56 char *ipad = tfm->crt_digest.dit_hmac_block; 56 char *ipad = tfm->crt_hash.hmac_block;
57 57
58 if (*keylen > crypto_tfm_alg_blocksize(tfm)) { 58 if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
59 hash_key(tfm, key, *keylen); 59 hash_key(tfm, key, *keylen);
@@ -83,7 +83,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
83{ 83{
84 unsigned int i; 84 unsigned int i;
85 struct scatterlist tmp; 85 struct scatterlist tmp;
86 char *opad = tfm->crt_digest.dit_hmac_block; 86 char *opad = tfm->crt_hash.hmac_block;
87 87
88 if (*keylen > crypto_tfm_alg_blocksize(tfm)) { 88 if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
89 hash_key(tfm, key, *keylen); 89 hash_key(tfm, key, *keylen);
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
index ace595a2e119..f1592cc2d0f4 100644
--- a/crypto/scatterwalk.h
+++ b/crypto/scatterwalk.h
@@ -20,11 +20,9 @@
20 20
21#include "internal.h" 21#include "internal.h"
22 22
23/* Define sg_next is an inline routine now in case we want to change
24 scatterlist to a linked list later. */
25static inline struct scatterlist *sg_next(struct scatterlist *sg) 23static inline struct scatterlist *sg_next(struct scatterlist *sg)
26{ 24{
27 return sg + 1; 25 return (++sg)->length ? sg : (void *)sg->page;
28} 26}
29 27
30static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in, 28static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,