aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/xcbc.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-07-22 02:37:15 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2009-07-22 02:38:10 -0400
commitac95301f271f32901e4007096aa3516def49eed2 (patch)
treeb228f9cf7d3cbd62fc61dc1eea92f74a2fbe3786 /crypto/xcbc.c
parentb588ef6e69bfc0944a17dc673ee166a00fa23de2 (diff)
crypto: xcbc - Fix shash conversion
Although xcbc was converted to shash, it didn't obey the new requirement that all hash state must be stored in the descriptor rather than the transform. This patch fixes this issue and also optimises away the rekeying by precomputing K2 and K3 within setkey. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/xcbc.c')
-rw-r--r--crypto/xcbc.c164
1 files changed, 73 insertions, 91 deletions
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 9d502e67a5c0..1e30b31f33c6 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -26,69 +26,67 @@
26static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 26static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
27 0x02020202, 0x02020202, 0x02020202, 0x02020202, 27 0x02020202, 0x02020202, 0x02020202, 0x02020202,
28 0x03030303, 0x03030303, 0x03030303, 0x03030303}; 28 0x03030303, 0x03030303, 0x03030303, 0x03030303};
29
29/* 30/*
30 * +------------------------ 31 * +------------------------
31 * | <parent tfm> 32 * | <parent tfm>
32 * +------------------------ 33 * +------------------------
33 * | crypto_xcbc_ctx 34 * | xcbc_tfm_ctx
34 * +------------------------ 35 * +------------------------
35 * | odds (block size) 36 * | consts (block size * 2)
36 * +------------------------ 37 * +------------------------
37 * | prev (block size) 38 */
39struct xcbc_tfm_ctx {
40 struct crypto_cipher *child;
41 u8 ctx[];
42};
43
44/*
38 * +------------------------ 45 * +------------------------
39 * | key (block size) 46 * | <shash desc>
40 * +------------------------ 47 * +------------------------
41 * | consts (block size * 3) 48 * | xcbc_desc_ctx
49 * +------------------------
50 * | odds (block size)
51 * +------------------------
52 * | prev (block size)
42 * +------------------------ 53 * +------------------------
43 */ 54 */
44struct crypto_xcbc_ctx { 55struct xcbc_desc_ctx {
45 struct crypto_cipher *child;
46 u8 *odds;
47 u8 *prev;
48 u8 *key;
49 u8 *consts;
50 unsigned int keylen;
51 unsigned int len; 56 unsigned int len;
57 u8 ctx[];
52}; 58};
53 59
54static int _crypto_xcbc_digest_setkey(struct crypto_shash *parent, 60static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
55 struct crypto_xcbc_ctx *ctx) 61 const u8 *inkey, unsigned int keylen)
56{ 62{
63 unsigned long alignmask = crypto_shash_alignmask(parent);
64 struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
57 int bs = crypto_shash_blocksize(parent); 65 int bs = crypto_shash_blocksize(parent);
66 u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
58 int err = 0; 67 int err = 0;
59 u8 key1[bs]; 68 u8 key1[bs];
60 69
61 if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen))) 70 if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
62 return err; 71 return err;
63 72
64 crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts); 73 crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs);
74 crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2);
75 crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks);
65 76
66 return crypto_cipher_setkey(ctx->child, key1, bs); 77 return crypto_cipher_setkey(ctx->child, key1, bs);
67}
68
69static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
70 const u8 *inkey, unsigned int keylen)
71{
72 struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent);
73
74 if (keylen != crypto_cipher_blocksize(ctx->child))
75 return -EINVAL;
76 78
77 ctx->keylen = keylen;
78 memcpy(ctx->key, inkey, keylen);
79 ctx->consts = (u8*)ks;
80
81 return _crypto_xcbc_digest_setkey(parent, ctx);
82} 79}
83 80
84static int crypto_xcbc_digest_init(struct shash_desc *pdesc) 81static int crypto_xcbc_digest_init(struct shash_desc *pdesc)
85{ 82{
86 struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(pdesc->tfm); 83 unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm);
84 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
87 int bs = crypto_shash_blocksize(pdesc->tfm); 85 int bs = crypto_shash_blocksize(pdesc->tfm);
86 u8 *prev = PTR_ALIGN(&ctx->ctx[0], alignmask + 1) + bs;
88 87
89 ctx->len = 0; 88 ctx->len = 0;
90 memset(ctx->odds, 0, bs); 89 memset(prev, 0, bs);
91 memset(ctx->prev, 0, bs);
92 90
93 return 0; 91 return 0;
94} 92}
@@ -97,39 +95,43 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
97 unsigned int len) 95 unsigned int len)
98{ 96{
99 struct crypto_shash *parent = pdesc->tfm; 97 struct crypto_shash *parent = pdesc->tfm;
100 struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); 98 unsigned long alignmask = crypto_shash_alignmask(parent);
101 struct crypto_cipher *tfm = ctx->child; 99 struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
100 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
101 struct crypto_cipher *tfm = tctx->child;
102 int bs = crypto_shash_blocksize(parent); 102 int bs = crypto_shash_blocksize(parent);
103 u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
104 u8 *prev = odds + bs;
103 105
104 /* checking the data can fill the block */ 106 /* checking the data can fill the block */
105 if ((ctx->len + len) <= bs) { 107 if ((ctx->len + len) <= bs) {
106 memcpy(ctx->odds + ctx->len, p, len); 108 memcpy(odds + ctx->len, p, len);
107 ctx->len += len; 109 ctx->len += len;
108 return 0; 110 return 0;
109 } 111 }
110 112
111 /* filling odds with new data and encrypting it */ 113 /* filling odds with new data and encrypting it */
112 memcpy(ctx->odds + ctx->len, p, bs - ctx->len); 114 memcpy(odds + ctx->len, p, bs - ctx->len);
113 len -= bs - ctx->len; 115 len -= bs - ctx->len;
114 p += bs - ctx->len; 116 p += bs - ctx->len;
115 117
116 crypto_xor(ctx->prev, ctx->odds, bs); 118 crypto_xor(prev, odds, bs);
117 crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); 119 crypto_cipher_encrypt_one(tfm, prev, prev);
118 120
119 /* clearing the length */ 121 /* clearing the length */
120 ctx->len = 0; 122 ctx->len = 0;
121 123
122 /* encrypting the rest of data */ 124 /* encrypting the rest of data */
123 while (len > bs) { 125 while (len > bs) {
124 crypto_xor(ctx->prev, p, bs); 126 crypto_xor(prev, p, bs);
125 crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); 127 crypto_cipher_encrypt_one(tfm, prev, prev);
126 p += bs; 128 p += bs;
127 len -= bs; 129 len -= bs;
128 } 130 }
129 131
130 /* keeping the surplus of blocksize */ 132 /* keeping the surplus of blocksize */
131 if (len) { 133 if (len) {
132 memcpy(ctx->odds, p, len); 134 memcpy(odds, p, len);
133 ctx->len = len; 135 ctx->len = len;
134 } 136 }
135 137
@@ -139,29 +141,20 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
139static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) 141static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out)
140{ 142{
141 struct crypto_shash *parent = pdesc->tfm; 143 struct crypto_shash *parent = pdesc->tfm;
142 struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); 144 unsigned long alignmask = crypto_shash_alignmask(parent);
143 struct crypto_cipher *tfm = ctx->child; 145 struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
146 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
147 struct crypto_cipher *tfm = tctx->child;
144 int bs = crypto_shash_blocksize(parent); 148 int bs = crypto_shash_blocksize(parent);
145 int err = 0; 149 u8 *consts = PTR_ALIGN(&tctx->ctx[0], alignmask + 1);
150 u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
151 u8 *prev = odds + bs;
152 unsigned int offset = 0;
146 153
147 if (ctx->len == bs) { 154 if (ctx->len != bs) {
148 u8 key2[bs];
149
150 if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
151 return err;
152
153 crypto_cipher_encrypt_one(tfm, key2,
154 (u8 *)(ctx->consts + bs));
155
156 crypto_xor(ctx->prev, ctx->odds, bs);
157 crypto_xor(ctx->prev, key2, bs);
158 _crypto_xcbc_digest_setkey(parent, ctx);
159
160 crypto_cipher_encrypt_one(tfm, out, ctx->prev);
161 } else {
162 u8 key3[bs];
163 unsigned int rlen; 155 unsigned int rlen;
164 u8 *p = ctx->odds + ctx->len; 156 u8 *p = odds + ctx->len;
157
165 *p = 0x80; 158 *p = 0x80;
166 p++; 159 p++;
167 160
@@ -169,19 +162,13 @@ static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out)
169 if (rlen) 162 if (rlen)
170 memset(p, 0, rlen); 163 memset(p, 0, rlen);
171 164
172 if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) 165 offset += bs;
173 return err; 166 }
174
175 crypto_cipher_encrypt_one(tfm, key3,
176 (u8 *)(ctx->consts + bs * 2));
177 167
178 crypto_xor(ctx->prev, ctx->odds, bs); 168 crypto_xor(prev, odds, bs);
179 crypto_xor(ctx->prev, key3, bs); 169 crypto_xor(prev, consts + offset, bs);
180 170
181 _crypto_xcbc_digest_setkey(parent, ctx); 171 crypto_cipher_encrypt_one(tfm, out, prev);
182
183 crypto_cipher_encrypt_one(tfm, out, ctx->prev);
184 }
185 172
186 return 0; 173 return 0;
187} 174}
@@ -191,31 +178,20 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm)
191 struct crypto_cipher *cipher; 178 struct crypto_cipher *cipher;
192 struct crypto_instance *inst = (void *)tfm->__crt_alg; 179 struct crypto_instance *inst = (void *)tfm->__crt_alg;
193 struct crypto_spawn *spawn = crypto_instance_ctx(inst); 180 struct crypto_spawn *spawn = crypto_instance_ctx(inst);
194 struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); 181 struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
195 int bs = crypto_tfm_alg_blocksize(tfm);
196 182
197 cipher = crypto_spawn_cipher(spawn); 183 cipher = crypto_spawn_cipher(spawn);
198 if (IS_ERR(cipher)) 184 if (IS_ERR(cipher))
199 return PTR_ERR(cipher); 185 return PTR_ERR(cipher);
200 186
201 switch(bs) {
202 case 16:
203 break;
204 default:
205 return -EINVAL;
206 }
207
208 ctx->child = cipher; 187 ctx->child = cipher;
209 ctx->odds = (u8*)(ctx+1);
210 ctx->prev = ctx->odds + bs;
211 ctx->key = ctx->prev + bs;
212 188
213 return 0; 189 return 0;
214}; 190};
215 191
216static void xcbc_exit_tfm(struct crypto_tfm *tfm) 192static void xcbc_exit_tfm(struct crypto_tfm *tfm)
217{ 193{
218 struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); 194 struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
219 crypto_free_cipher(ctx->child); 195 crypto_free_cipher(ctx->child);
220} 196}
221 197
@@ -254,12 +230,18 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
254 230
255 inst->alg.base.cra_priority = alg->cra_priority; 231 inst->alg.base.cra_priority = alg->cra_priority;
256 inst->alg.base.cra_blocksize = alg->cra_blocksize; 232 inst->alg.base.cra_blocksize = alg->cra_blocksize;
257 inst->alg.base.cra_alignmask = alg->cra_alignmask; 233 inst->alg.base.cra_alignmask = alg->cra_alignmask | 3;
258 234
259 inst->alg.digestsize = alg->cra_blocksize; 235 inst->alg.digestsize = alg->cra_blocksize;
260 inst->alg.base.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + 236 inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx),
261 ALIGN(alg->cra_blocksize * 3, 237 crypto_tfm_ctx_alignment()) +
262 sizeof(void *)); 238 (alg->cra_alignmask &
239 ~(crypto_tfm_ctx_alignment() - 1)) +
240 alg->cra_blocksize * 2;
241
242 inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx),
243 alg->cra_alignmask) +
244 alg->cra_blocksize * 2;
263 inst->alg.base.cra_init = xcbc_init_tfm; 245 inst->alg.base.cra_init = xcbc_init_tfm;
264 inst->alg.base.cra_exit = xcbc_exit_tfm; 246 inst->alg.base.cra_exit = xcbc_exit_tfm;
265 247