summaryrefslogtreecommitdiffstats
path: root/crypto/poly1305_generic.c
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2015-06-16 05:34:16 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2015-06-17 03:35:11 -0400
commitc2b7b20aedfa10de3634877c3e4b7bc9a7d6461e (patch)
treeccc9c1ac23ae8669a5860a3e50ed8f13bbd1704b /crypto/poly1305_generic.c
parent8f69b763877a20fe06cb8d89b031a7ae73b269f2 (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.c97
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
24struct poly1305_ctx { 24struct 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
31struct 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
40static inline u64 mlt(u64 a, u64 b) 41static 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)
70static int poly1305_setkey(struct crypto_shash *tfm, 73static 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
83static 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; 93static 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
95static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx, 101static 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,
198static int poly1305_final(struct shash_desc *desc, u8 *dst) 218static 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};