diff options
Diffstat (limited to 'crypto/digest.c')
-rw-r--r-- | crypto/digest.c | 129 |
1 files changed, 102 insertions, 27 deletions
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 | ||
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); | ||
24 | } | 30 | } |
31 | EXPORT_SYMBOL_GPL(crypto_digest_init); | ||
25 | 32 | ||
26 | static void update(struct crypto_tfm *tfm, | 33 | void 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 | } | ||
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); | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(crypto_digest_final); | ||
56 | |||
57 | void 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 | } | ||
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,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 | ||
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); |
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 | ||
83 | static int nosetkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) | 152 | static 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 | ||
89 | 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) |
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 | ||
95 | static void digest(struct crypto_tfm *tfm, | 166 | static 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 | ||
103 | int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) | 174 | int 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 | ||
108 | int crypto_init_digest_ops(struct crypto_tfm *tfm) | 179 | int 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 | } |