summaryrefslogtreecommitdiffstats
path: root/crypto/poly1305_generic.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2018-11-16 20:26:28 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2018-11-20 01:26:56 -0500
commit1b6fd3d5d18bbc1b1abf3b0cbc4b95a9a63d407b (patch)
tree39ec42053ca0a1346fa2a41a2c1b5db33b2d41ca /crypto/poly1305_generic.c
parent878afc35cd28bcd93cd3c5e1985ef39a104a4d45 (diff)
crypto: poly1305 - add Poly1305 core API
Expose a low-level Poly1305 API which implements the ε-almost-∆-universal (εA∆U) hash function underlying the Poly1305 MAC and supports block-aligned inputs only. This is needed for Adiantum hashing, which builds an εA∆U hash function from NH and a polynomial evaluation in GF(2^{130}-5); this polynomial evaluation is identical to the one the Poly1305 MAC does. However, the crypto_shash Poly1305 API isn't very appropriate for this because its calling convention assumes it is used as a MAC, with a 32-byte "one-time key" provided for every digest. But by design, in Adiantum hashing the performance of the polynomial evaluation isn't nearly as critical as NH. So it suffices to just have some C helper functions. Thus, this patch adds such functions. Acked-by: Martin Willi <martin@strongswan.org> Signed-off-by: Eric Biggers <ebiggers@google.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/poly1305_generic.c')
-rw-r--r--crypto/poly1305_generic.c174
1 files changed, 99 insertions, 75 deletions
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
index a23173f351b7..2a06874204e8 100644
--- a/crypto/poly1305_generic.c
+++ b/crypto/poly1305_generic.c
@@ -38,7 +38,7 @@ int crypto_poly1305_init(struct shash_desc *desc)
38{ 38{
39 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); 39 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
40 40
41 memset(dctx->h.h, 0, sizeof(dctx->h.h)); 41 poly1305_core_init(&dctx->h);
42 dctx->buflen = 0; 42 dctx->buflen = 0;
43 dctx->rset = false; 43 dctx->rset = false;
44 dctx->sset = false; 44 dctx->sset = false;
@@ -47,23 +47,16 @@ int crypto_poly1305_init(struct shash_desc *desc)
47} 47}
48EXPORT_SYMBOL_GPL(crypto_poly1305_init); 48EXPORT_SYMBOL_GPL(crypto_poly1305_init);
49 49
50static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key) 50void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
51{ 51{
52 /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 52 /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
53 dctx->r.r[0] = (get_unaligned_le32(key + 0) >> 0) & 0x3ffffff; 53 key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff;
54 dctx->r.r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03; 54 key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03;
55 dctx->r.r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff; 55 key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff;
56 dctx->r.r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff; 56 key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff;
57 dctx->r.r[4] = (get_unaligned_le32(key + 12) >> 8) & 0x00fffff; 57 key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
58}
59
60static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
61{
62 dctx->s[0] = get_unaligned_le32(key + 0);
63 dctx->s[1] = get_unaligned_le32(key + 4);
64 dctx->s[2] = get_unaligned_le32(key + 8);
65 dctx->s[3] = get_unaligned_le32(key + 12);
66} 58}
59EXPORT_SYMBOL_GPL(poly1305_core_setkey);
67 60
68/* 61/*
69 * Poly1305 requires a unique key for each tag, which implies that we can't set 62 * Poly1305 requires a unique key for each tag, which implies that we can't set
@@ -75,13 +68,16 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
75{ 68{
76 if (!dctx->sset) { 69 if (!dctx->sset) {
77 if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { 70 if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
78 poly1305_setrkey(dctx, src); 71 poly1305_core_setkey(&dctx->r, src);
79 src += POLY1305_BLOCK_SIZE; 72 src += POLY1305_BLOCK_SIZE;
80 srclen -= POLY1305_BLOCK_SIZE; 73 srclen -= POLY1305_BLOCK_SIZE;
81 dctx->rset = true; 74 dctx->rset = true;
82 } 75 }
83 if (srclen >= POLY1305_BLOCK_SIZE) { 76 if (srclen >= POLY1305_BLOCK_SIZE) {
84 poly1305_setskey(dctx, src); 77 dctx->s[0] = get_unaligned_le32(src + 0);
78 dctx->s[1] = get_unaligned_le32(src + 4);
79 dctx->s[2] = get_unaligned_le32(src + 8);
80 dctx->s[3] = get_unaligned_le32(src + 12);
85 src += POLY1305_BLOCK_SIZE; 81 src += POLY1305_BLOCK_SIZE;
86 srclen -= POLY1305_BLOCK_SIZE; 82 srclen -= POLY1305_BLOCK_SIZE;
87 dctx->sset = true; 83 dctx->sset = true;
@@ -91,41 +87,37 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
91} 87}
92EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey); 88EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey);
93 89
94static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx, 90static void poly1305_blocks_internal(struct poly1305_state *state,
95 const u8 *src, unsigned int srclen, 91 const struct poly1305_key *key,
96 u32 hibit) 92 const void *src, unsigned int nblocks,
93 u32 hibit)
97{ 94{
98 u32 r0, r1, r2, r3, r4; 95 u32 r0, r1, r2, r3, r4;
99 u32 s1, s2, s3, s4; 96 u32 s1, s2, s3, s4;
100 u32 h0, h1, h2, h3, h4; 97 u32 h0, h1, h2, h3, h4;
101 u64 d0, d1, d2, d3, d4; 98 u64 d0, d1, d2, d3, d4;
102 unsigned int datalen;
103 99
104 if (unlikely(!dctx->sset)) { 100 if (!nblocks)
105 datalen = crypto_poly1305_setdesckey(dctx, src, srclen); 101 return;
106 src += srclen - datalen;
107 srclen = datalen;
108 }
109 102
110 r0 = dctx->r.r[0]; 103 r0 = key->r[0];
111 r1 = dctx->r.r[1]; 104 r1 = key->r[1];
112 r2 = dctx->r.r[2]; 105 r2 = key->r[2];
113 r3 = dctx->r.r[3]; 106 r3 = key->r[3];
114 r4 = dctx->r.r[4]; 107 r4 = key->r[4];
115 108
116 s1 = r1 * 5; 109 s1 = r1 * 5;
117 s2 = r2 * 5; 110 s2 = r2 * 5;
118 s3 = r3 * 5; 111 s3 = r3 * 5;
119 s4 = r4 * 5; 112 s4 = r4 * 5;
120 113
121 h0 = dctx->h.h[0]; 114 h0 = state->h[0];
122 h1 = dctx->h.h[1]; 115 h1 = state->h[1];
123 h2 = dctx->h.h[2]; 116 h2 = state->h[2];
124 h3 = dctx->h.h[3]; 117 h3 = state->h[3];
125 h4 = dctx->h.h[4]; 118 h4 = state->h[4];
126
127 while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
128 119
120 do {
129 /* h += m[i] */ 121 /* h += m[i] */
130 h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; 122 h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff;
131 h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; 123 h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff;
@@ -154,16 +146,36 @@ static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
154 h1 += h0 >> 26; h0 = h0 & 0x3ffffff; 146 h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
155 147
156 src += POLY1305_BLOCK_SIZE; 148 src += POLY1305_BLOCK_SIZE;
157 srclen -= POLY1305_BLOCK_SIZE; 149 } while (--nblocks);
158 }
159 150
160 dctx->h.h[0] = h0; 151 state->h[0] = h0;
161 dctx->h.h[1] = h1; 152 state->h[1] = h1;
162 dctx->h.h[2] = h2; 153 state->h[2] = h2;
163 dctx->h.h[3] = h3; 154 state->h[3] = h3;
164 dctx->h.h[4] = h4; 155 state->h[4] = h4;
156}
165 157
166 return srclen; 158void poly1305_core_blocks(struct poly1305_state *state,
159 const struct poly1305_key *key,
160 const void *src, unsigned int nblocks)
161{
162 poly1305_blocks_internal(state, key, src, nblocks, 1 << 24);
163}
164EXPORT_SYMBOL_GPL(poly1305_core_blocks);
165
166static void poly1305_blocks(struct poly1305_desc_ctx *dctx,
167 const u8 *src, unsigned int srclen, u32 hibit)
168{
169 unsigned int datalen;
170
171 if (unlikely(!dctx->sset)) {
172 datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
173 src += srclen - datalen;
174 srclen = datalen;
175 }
176
177 poly1305_blocks_internal(&dctx->h, &dctx->r,
178 src, srclen / POLY1305_BLOCK_SIZE, hibit);
167} 179}
168 180
169int crypto_poly1305_update(struct shash_desc *desc, 181int crypto_poly1305_update(struct shash_desc *desc,
@@ -187,9 +199,9 @@ int crypto_poly1305_update(struct shash_desc *desc,
187 } 199 }
188 200
189 if (likely(srclen >= POLY1305_BLOCK_SIZE)) { 201 if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
190 bytes = poly1305_blocks(dctx, src, srclen, 1 << 24); 202 poly1305_blocks(dctx, src, srclen, 1 << 24);
191 src += srclen - bytes; 203 src += srclen - (srclen % POLY1305_BLOCK_SIZE);
192 srclen = bytes; 204 srclen %= POLY1305_BLOCK_SIZE;
193 } 205 }
194 206
195 if (unlikely(srclen)) { 207 if (unlikely(srclen)) {
@@ -201,30 +213,18 @@ int crypto_poly1305_update(struct shash_desc *desc,
201} 213}
202EXPORT_SYMBOL_GPL(crypto_poly1305_update); 214EXPORT_SYMBOL_GPL(crypto_poly1305_update);
203 215
204int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) 216void poly1305_core_emit(const struct poly1305_state *state, void *dst)
205{ 217{
206 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
207 u32 h0, h1, h2, h3, h4; 218 u32 h0, h1, h2, h3, h4;
208 u32 g0, g1, g2, g3, g4; 219 u32 g0, g1, g2, g3, g4;
209 u32 mask; 220 u32 mask;
210 u64 f = 0;
211
212 if (unlikely(!dctx->sset))
213 return -ENOKEY;
214
215 if (unlikely(dctx->buflen)) {
216 dctx->buf[dctx->buflen++] = 1;
217 memset(dctx->buf + dctx->buflen, 0,
218 POLY1305_BLOCK_SIZE - dctx->buflen);
219 poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
220 }
221 221
222 /* fully carry h */ 222 /* fully carry h */
223 h0 = dctx->h.h[0]; 223 h0 = state->h[0];
224 h1 = dctx->h.h[1]; 224 h1 = state->h[1];
225 h2 = dctx->h.h[2]; 225 h2 = state->h[2];
226 h3 = dctx->h.h[3]; 226 h3 = state->h[3];
227 h4 = dctx->h.h[4]; 227 h4 = state->h[4];
228 228
229 h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; 229 h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
230 h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; 230 h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
@@ -254,16 +254,40 @@ int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
254 h4 = (h4 & mask) | g4; 254 h4 = (h4 & mask) | g4;
255 255
256 /* h = h % (2^128) */ 256 /* h = h % (2^128) */
257 h0 = (h0 >> 0) | (h1 << 26); 257 put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0);
258 h1 = (h1 >> 6) | (h2 << 20); 258 put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4);
259 h2 = (h2 >> 12) | (h3 << 14); 259 put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8);
260 h3 = (h3 >> 18) | (h4 << 8); 260 put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12);
261}
262EXPORT_SYMBOL_GPL(poly1305_core_emit);
263
264int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
265{
266 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
267 __le32 digest[4];
268 u64 f = 0;
269
270 if (unlikely(!dctx->sset))
271 return -ENOKEY;
272
273 if (unlikely(dctx->buflen)) {
274 dctx->buf[dctx->buflen++] = 1;
275 memset(dctx->buf + dctx->buflen, 0,
276 POLY1305_BLOCK_SIZE - dctx->buflen);
277 poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
278 }
279
280 poly1305_core_emit(&dctx->h, digest);
261 281
262 /* mac = (h + s) % (2^128) */ 282 /* mac = (h + s) % (2^128) */
263 f = (f >> 32) + h0 + dctx->s[0]; put_unaligned_le32(f, dst + 0); 283 f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0];
264 f = (f >> 32) + h1 + dctx->s[1]; put_unaligned_le32(f, dst + 4); 284 put_unaligned_le32(f, dst + 0);
265 f = (f >> 32) + h2 + dctx->s[2]; put_unaligned_le32(f, dst + 8); 285 f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1];
266 f = (f >> 32) + h3 + dctx->s[3]; put_unaligned_le32(f, dst + 12); 286 put_unaligned_le32(f, dst + 4);
287 f = (f >> 32) + le32_to_cpu(digest[2]) + dctx->s[2];
288 put_unaligned_le32(f, dst + 8);
289 f = (f >> 32) + le32_to_cpu(digest[3]) + dctx->s[3];
290 put_unaligned_le32(f, dst + 12);
267 291
268 return 0; 292 return 0;
269} 293}