diff options
Diffstat (limited to 'crypto/digest.c')
-rw-r--r-- | crypto/digest.c | 155 |
1 files changed, 119 insertions, 36 deletions
diff --git a/crypto/digest.c b/crypto/digest.c index 603006a7bef2..0155a94e4b15 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 | ||
21 | static void init(struct crypto_tfm *tfm) | 24 | void 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); | ||
30 | } | ||
31 | EXPORT_SYMBOL_GPL(crypto_digest_init); | ||
32 | |||
33 | void crypto_digest_update(struct crypto_tfm *tfm, | ||
34 | struct scatterlist *sg, unsigned int nsg) | ||
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; | ||
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 | } | ||
46 | EXPORT_SYMBOL_GPL(crypto_digest_update); | ||
47 | |||
48 | void 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); | ||
24 | } | 54 | } |
55 | EXPORT_SYMBOL_GPL(crypto_digest_final); | ||
25 | 56 | ||
26 | static void update(struct crypto_tfm *tfm, | 57 | void crypto_digest_digest(struct crypto_tfm *tfm, |
27 | struct scatterlist *sg, unsigned int nsg) | 58 | struct scatterlist *sg, unsigned int nsg, u8 *out) |
28 | { | 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; | ||
29 | unsigned int i; | 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 | } | ||
70 | EXPORT_SYMBOL_GPL(crypto_digest_digest); | ||
71 | |||
72 | static 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 | |||
80 | static 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,41 +115,60 @@ 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); | 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 | ||
66 | static void final(struct crypto_tfm *tfm, u8 *out) | 132 | static 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); |
136 | struct digest_alg *digest = &tfm->__crt_alg->cra_digest; | ||
137 | |||
69 | if (unlikely((unsigned long)out & alignmask)) { | 138 | if (unlikely((unsigned long)out & alignmask)) { |
70 | unsigned int size = crypto_tfm_alg_digestsize(tfm); | 139 | unsigned long align = alignmask + 1; |
71 | u8 buffer[size + alignmask]; | 140 | unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm); |
72 | u8 *dst = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); | 141 | u8 *dst = (u8 *)ALIGN(addr, align) + |
73 | tfm->__crt_alg->cra_digest.dia_final(tfm, dst); | 142 | ALIGN(tfm->__crt_alg->cra_ctxsize, align); |
74 | memcpy(out, dst, size); | 143 | |
144 | digest->dia_final(tfm, dst); | ||
145 | memcpy(out, dst, digest->dia_digestsize); | ||
75 | } else | 146 | } else |
76 | tfm->__crt_alg->cra_digest.dia_final(tfm, out); | 147 | digest->dia_final(tfm, out); |
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen) | ||
153 | { | ||
154 | crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK); | ||
155 | return -ENOSYS; | ||
77 | } | 156 | } |
78 | 157 | ||
79 | static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) | 158 | static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen) |
80 | { | 159 | { |
81 | u32 flags; | 160 | struct crypto_tfm *tfm = crypto_hash_tfm(hash); |
82 | if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) | 161 | |
83 | return -ENOSYS; | 162 | crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK); |
84 | return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen, &flags); | 163 | return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen); |
85 | } | 164 | } |
86 | 165 | ||
87 | static void digest(struct crypto_tfm *tfm, | 166 | static int digest(struct hash_desc *desc, |
88 | struct scatterlist *sg, unsigned int nsg, u8 *out) | 167 | struct scatterlist *sg, unsigned int nbytes, u8 *out) |
89 | { | 168 | { |
90 | init(tfm); | 169 | init(desc); |
91 | update(tfm, sg, nsg); | 170 | update(desc, sg, nbytes); |
92 | final(tfm, out); | 171 | return final(desc, out); |
93 | } | 172 | } |
94 | 173 | ||
95 | int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) | 174 | int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) |
@@ -99,18 +178,22 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) | |||
99 | 178 | ||
100 | int crypto_init_digest_ops(struct crypto_tfm *tfm) | 179 | int crypto_init_digest_ops(struct crypto_tfm *tfm) |
101 | { | 180 | { |
102 | struct digest_tfm *ops = &tfm->crt_digest; | 181 | struct hash_tfm *ops = &tfm->crt_hash; |
182 | struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; | ||
183 | |||
184 | if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm)) | ||
185 | return -EINVAL; | ||
103 | 186 | ||
104 | ops->dit_init = init; | 187 | ops->init = init; |
105 | ops->dit_update = update; | 188 | ops->update = update; |
106 | ops->dit_final = final; | 189 | ops->final = final; |
107 | ops->dit_digest = digest; | 190 | ops->digest = digest; |
108 | ops->dit_setkey = setkey; | 191 | ops->setkey = dalg->dia_setkey ? setkey : nosetkey; |
192 | ops->digestsize = dalg->dia_digestsize; | ||
109 | 193 | ||
110 | return crypto_alloc_hmac_block(tfm); | 194 | return 0; |
111 | } | 195 | } |
112 | 196 | ||
113 | void crypto_exit_digest_ops(struct crypto_tfm *tfm) | 197 | void crypto_exit_digest_ops(struct crypto_tfm *tfm) |
114 | { | 198 | { |
115 | crypto_free_hmac_block(tfm); | ||
116 | } | 199 | } |