diff options
author | Martin Willi <martin@strongswan.org> | 2015-06-16 05:34:16 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2015-06-17 03:35:11 -0400 |
commit | c2b7b20aedfa10de3634877c3e4b7bc9a7d6461e (patch) | |
tree | ccc9c1ac23ae8669a5860a3e50ed8f13bbd1704b /crypto/poly1305_generic.c | |
parent | 8f69b763877a20fe06cb8d89b031a7ae73b269f2 (diff) |
crypto: poly1305 - Pass key as first two message blocks to each desc_ctx
The Poly1305 authenticator requires a unique key for each generated tag. This
implies that we can't set the key per tfm, as multiple users set individual
keys. Instead we pass a desc specific key as the first two blocks of the
message to authenticate in update().
Signed-off-by: Martin Willi <martin@strongswan.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/poly1305_generic.c')
-rw-r--r-- | crypto/poly1305_generic.c | 97 |
1 files changed, 59 insertions, 38 deletions
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c index 9c1159b991f4..387b5c887a80 100644 --- a/crypto/poly1305_generic.c +++ b/crypto/poly1305_generic.c | |||
@@ -21,20 +21,21 @@ | |||
21 | #define POLY1305_KEY_SIZE 32 | 21 | #define POLY1305_KEY_SIZE 32 |
22 | #define POLY1305_DIGEST_SIZE 16 | 22 | #define POLY1305_DIGEST_SIZE 16 |
23 | 23 | ||
24 | struct poly1305_ctx { | 24 | struct poly1305_desc_ctx { |
25 | /* key */ | 25 | /* key */ |
26 | u32 r[5]; | 26 | u32 r[5]; |
27 | /* finalize key */ | 27 | /* finalize key */ |
28 | u32 s[4]; | 28 | u32 s[4]; |
29 | }; | ||
30 | |||
31 | struct poly1305_desc_ctx { | ||
32 | /* accumulator */ | 29 | /* accumulator */ |
33 | u32 h[5]; | 30 | u32 h[5]; |
34 | /* partial buffer */ | 31 | /* partial buffer */ |
35 | u8 buf[POLY1305_BLOCK_SIZE]; | 32 | u8 buf[POLY1305_BLOCK_SIZE]; |
36 | /* bytes used in partial buffer */ | 33 | /* bytes used in partial buffer */ |
37 | unsigned int buflen; | 34 | unsigned int buflen; |
35 | /* r key has been set */ | ||
36 | bool rset; | ||
37 | /* s key has been set */ | ||
38 | bool sset; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | static inline u64 mlt(u64 a, u64 b) | 41 | static inline u64 mlt(u64 a, u64 b) |
@@ -63,6 +64,8 @@ static int poly1305_init(struct shash_desc *desc) | |||
63 | 64 | ||
64 | memset(dctx->h, 0, sizeof(dctx->h)); | 65 | memset(dctx->h, 0, sizeof(dctx->h)); |
65 | dctx->buflen = 0; | 66 | dctx->buflen = 0; |
67 | dctx->rset = false; | ||
68 | dctx->sset = false; | ||
66 | 69 | ||
67 | return 0; | 70 | return 0; |
68 | } | 71 | } |
@@ -70,42 +73,60 @@ static int poly1305_init(struct shash_desc *desc) | |||
70 | static int poly1305_setkey(struct crypto_shash *tfm, | 73 | static int poly1305_setkey(struct crypto_shash *tfm, |
71 | const u8 *key, unsigned int keylen) | 74 | const u8 *key, unsigned int keylen) |
72 | { | 75 | { |
73 | struct poly1305_ctx *ctx = crypto_shash_ctx(tfm); | 76 | /* Poly1305 requires a unique key for each tag, which implies that |
74 | 77 | * we can't set it on the tfm that gets accessed by multiple users | |
75 | if (keylen != POLY1305_KEY_SIZE) { | 78 | * simultaneously. Instead we expect the key as the first 32 bytes in |
76 | crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); | 79 | * the update() call. */ |
77 | return -EINVAL; | 80 | return -ENOTSUPP; |
78 | } | 81 | } |
79 | 82 | ||
83 | static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key) | ||
84 | { | ||
80 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ | 85 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ |
81 | ctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff; | 86 | dctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff; |
82 | ctx->r[1] = (le32_to_cpuvp(key + 3) >> 2) & 0x3ffff03; | 87 | dctx->r[1] = (le32_to_cpuvp(key + 3) >> 2) & 0x3ffff03; |
83 | ctx->r[2] = (le32_to_cpuvp(key + 6) >> 4) & 0x3ffc0ff; | 88 | dctx->r[2] = (le32_to_cpuvp(key + 6) >> 4) & 0x3ffc0ff; |
84 | ctx->r[3] = (le32_to_cpuvp(key + 9) >> 6) & 0x3f03fff; | 89 | dctx->r[3] = (le32_to_cpuvp(key + 9) >> 6) & 0x3f03fff; |
85 | ctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff; | 90 | dctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff; |
86 | 91 | } | |
87 | ctx->s[0] = le32_to_cpuvp(key + 16); | ||
88 | ctx->s[1] = le32_to_cpuvp(key + 20); | ||
89 | ctx->s[2] = le32_to_cpuvp(key + 24); | ||
90 | ctx->s[3] = le32_to_cpuvp(key + 28); | ||
91 | 92 | ||
92 | return 0; | 93 | static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key) |
94 | { | ||
95 | dctx->s[0] = le32_to_cpuvp(key + 0); | ||
96 | dctx->s[1] = le32_to_cpuvp(key + 4); | ||
97 | dctx->s[2] = le32_to_cpuvp(key + 8); | ||
98 | dctx->s[3] = le32_to_cpuvp(key + 12); | ||
93 | } | 99 | } |
94 | 100 | ||
95 | static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx, | 101 | static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx, |
96 | struct poly1305_ctx *ctx, const u8 *src, | 102 | const u8 *src, unsigned int srclen, |
97 | unsigned int srclen, u32 hibit) | 103 | u32 hibit) |
98 | { | 104 | { |
99 | u32 r0, r1, r2, r3, r4; | 105 | u32 r0, r1, r2, r3, r4; |
100 | u32 s1, s2, s3, s4; | 106 | u32 s1, s2, s3, s4; |
101 | u32 h0, h1, h2, h3, h4; | 107 | u32 h0, h1, h2, h3, h4; |
102 | u64 d0, d1, d2, d3, d4; | 108 | u64 d0, d1, d2, d3, d4; |
103 | 109 | ||
104 | r0 = ctx->r[0]; | 110 | if (unlikely(!dctx->sset)) { |
105 | r1 = ctx->r[1]; | 111 | if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { |
106 | r2 = ctx->r[2]; | 112 | poly1305_setrkey(dctx, src); |
107 | r3 = ctx->r[3]; | 113 | src += POLY1305_BLOCK_SIZE; |
108 | r4 = ctx->r[4]; | 114 | srclen -= POLY1305_BLOCK_SIZE; |
115 | dctx->rset = true; | ||
116 | } | ||
117 | if (srclen >= POLY1305_BLOCK_SIZE) { | ||
118 | poly1305_setskey(dctx, src); | ||
119 | src += POLY1305_BLOCK_SIZE; | ||
120 | srclen -= POLY1305_BLOCK_SIZE; | ||
121 | dctx->sset = true; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | r0 = dctx->r[0]; | ||
126 | r1 = dctx->r[1]; | ||
127 | r2 = dctx->r[2]; | ||
128 | r3 = dctx->r[3]; | ||
129 | r4 = dctx->r[4]; | ||
109 | 130 | ||
110 | s1 = r1 * 5; | 131 | s1 = r1 * 5; |
111 | s2 = r2 * 5; | 132 | s2 = r2 * 5; |
@@ -164,7 +185,6 @@ static int poly1305_update(struct shash_desc *desc, | |||
164 | const u8 *src, unsigned int srclen) | 185 | const u8 *src, unsigned int srclen) |
165 | { | 186 | { |
166 | struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); | 187 | struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); |
167 | struct poly1305_ctx *ctx = crypto_shash_ctx(desc->tfm); | ||
168 | unsigned int bytes; | 188 | unsigned int bytes; |
169 | 189 | ||
170 | if (unlikely(dctx->buflen)) { | 190 | if (unlikely(dctx->buflen)) { |
@@ -175,14 +195,14 @@ static int poly1305_update(struct shash_desc *desc, | |||
175 | dctx->buflen += bytes; | 195 | dctx->buflen += bytes; |
176 | 196 | ||
177 | if (dctx->buflen == POLY1305_BLOCK_SIZE) { | 197 | if (dctx->buflen == POLY1305_BLOCK_SIZE) { |
178 | poly1305_blocks(dctx, ctx, dctx->buf, | 198 | poly1305_blocks(dctx, dctx->buf, |
179 | POLY1305_BLOCK_SIZE, 1 << 24); | 199 | POLY1305_BLOCK_SIZE, 1 << 24); |
180 | dctx->buflen = 0; | 200 | dctx->buflen = 0; |
181 | } | 201 | } |
182 | } | 202 | } |
183 | 203 | ||
184 | if (likely(srclen >= POLY1305_BLOCK_SIZE)) { | 204 | if (likely(srclen >= POLY1305_BLOCK_SIZE)) { |
185 | bytes = poly1305_blocks(dctx, ctx, src, srclen, 1 << 24); | 205 | bytes = poly1305_blocks(dctx, src, srclen, 1 << 24); |
186 | src += srclen - bytes; | 206 | src += srclen - bytes; |
187 | srclen = bytes; | 207 | srclen = bytes; |
188 | } | 208 | } |
@@ -198,18 +218,20 @@ static int poly1305_update(struct shash_desc *desc, | |||
198 | static int poly1305_final(struct shash_desc *desc, u8 *dst) | 218 | static int poly1305_final(struct shash_desc *desc, u8 *dst) |
199 | { | 219 | { |
200 | struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); | 220 | struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); |
201 | struct poly1305_ctx *ctx = crypto_shash_ctx(desc->tfm); | ||
202 | __le32 *mac = (__le32 *)dst; | 221 | __le32 *mac = (__le32 *)dst; |
203 | u32 h0, h1, h2, h3, h4; | 222 | u32 h0, h1, h2, h3, h4; |
204 | u32 g0, g1, g2, g3, g4; | 223 | u32 g0, g1, g2, g3, g4; |
205 | u32 mask; | 224 | u32 mask; |
206 | u64 f = 0; | 225 | u64 f = 0; |
207 | 226 | ||
227 | if (unlikely(!dctx->sset)) | ||
228 | return -ENOKEY; | ||
229 | |||
208 | if (unlikely(dctx->buflen)) { | 230 | if (unlikely(dctx->buflen)) { |
209 | dctx->buf[dctx->buflen++] = 1; | 231 | dctx->buf[dctx->buflen++] = 1; |
210 | memset(dctx->buf + dctx->buflen, 0, | 232 | memset(dctx->buf + dctx->buflen, 0, |
211 | POLY1305_BLOCK_SIZE - dctx->buflen); | 233 | POLY1305_BLOCK_SIZE - dctx->buflen); |
212 | poly1305_blocks(dctx, ctx, dctx->buf, POLY1305_BLOCK_SIZE, 0); | 234 | poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0); |
213 | } | 235 | } |
214 | 236 | ||
215 | /* fully carry h */ | 237 | /* fully carry h */ |
@@ -253,10 +275,10 @@ static int poly1305_final(struct shash_desc *desc, u8 *dst) | |||
253 | h3 = (h3 >> 18) | (h4 << 8); | 275 | h3 = (h3 >> 18) | (h4 << 8); |
254 | 276 | ||
255 | /* mac = (h + s) % (2^128) */ | 277 | /* mac = (h + s) % (2^128) */ |
256 | f = (f >> 32) + h0 + ctx->s[0]; mac[0] = cpu_to_le32(f); | 278 | f = (f >> 32) + h0 + dctx->s[0]; mac[0] = cpu_to_le32(f); |
257 | f = (f >> 32) + h1 + ctx->s[1]; mac[1] = cpu_to_le32(f); | 279 | f = (f >> 32) + h1 + dctx->s[1]; mac[1] = cpu_to_le32(f); |
258 | f = (f >> 32) + h2 + ctx->s[2]; mac[2] = cpu_to_le32(f); | 280 | f = (f >> 32) + h2 + dctx->s[2]; mac[2] = cpu_to_le32(f); |
259 | f = (f >> 32) + h3 + ctx->s[3]; mac[3] = cpu_to_le32(f); | 281 | f = (f >> 32) + h3 + dctx->s[3]; mac[3] = cpu_to_le32(f); |
260 | 282 | ||
261 | return 0; | 283 | return 0; |
262 | } | 284 | } |
@@ -275,7 +297,6 @@ static struct shash_alg poly1305_alg = { | |||
275 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | 297 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, |
276 | .cra_alignmask = sizeof(u32) - 1, | 298 | .cra_alignmask = sizeof(u32) - 1, |
277 | .cra_blocksize = POLY1305_BLOCK_SIZE, | 299 | .cra_blocksize = POLY1305_BLOCK_SIZE, |
278 | .cra_ctxsize = sizeof(struct poly1305_ctx), | ||
279 | .cra_module = THIS_MODULE, | 300 | .cra_module = THIS_MODULE, |
280 | }, | 301 | }, |
281 | }; | 302 | }; |