Skip to content

Commit 1b6fd3d

Browse files
ebiggersherbertx
authored andcommitted
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>
1 parent 878afc3 commit 1b6fd3d

File tree

2 files changed

+115
-75
lines changed

2 files changed

+115
-75
lines changed

crypto/poly1305_generic.c

+99-75
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ int crypto_poly1305_init(struct shash_desc *desc)
3838
{
3939
struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
4040

41-
memset(dctx->h.h, 0, sizeof(dctx->h.h));
41+
poly1305_core_init(&dctx->h);
4242
dctx->buflen = 0;
4343
dctx->rset = false;
4444
dctx->sset = false;
@@ -47,23 +47,16 @@ int crypto_poly1305_init(struct shash_desc *desc)
4747
}
4848
EXPORT_SYMBOL_GPL(crypto_poly1305_init);
4949

50-
static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
50+
void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
5151
{
5252
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
53-
dctx->r.r[0] = (get_unaligned_le32(key + 0) >> 0) & 0x3ffffff;
54-
dctx->r.r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03;
55-
dctx->r.r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff;
56-
dctx->r.r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff;
57-
dctx->r.r[4] = (get_unaligned_le32(key + 12) >> 8) & 0x00fffff;
58-
}
59-
60-
static 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);
53+
key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff;
54+
key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03;
55+
key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff;
56+
key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff;
57+
key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
6658
}
59+
EXPORT_SYMBOL_GPL(poly1305_core_setkey);
6760

6861
/*
6962
* 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,
7568
{
7669
if (!dctx->sset) {
7770
if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
78-
poly1305_setrkey(dctx, src);
71+
poly1305_core_setkey(&dctx->r, src);
7972
src += POLY1305_BLOCK_SIZE;
8073
srclen -= POLY1305_BLOCK_SIZE;
8174
dctx->rset = true;
8275
}
8376
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);
8581
src += POLY1305_BLOCK_SIZE;
8682
srclen -= POLY1305_BLOCK_SIZE;
8783
dctx->sset = true;
@@ -91,41 +87,37 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
9187
}
9288
EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey);
9389

94-
static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
95-
const u8 *src, unsigned int srclen,
96-
u32 hibit)
90+
static void poly1305_blocks_internal(struct poly1305_state *state,
91+
const struct poly1305_key *key,
92+
const void *src, unsigned int nblocks,
93+
u32 hibit)
9794
{
9895
u32 r0, r1, r2, r3, r4;
9996
u32 s1, s2, s3, s4;
10097
u32 h0, h1, h2, h3, h4;
10198
u64 d0, d1, d2, d3, d4;
102-
unsigned int datalen;
10399

104-
if (unlikely(!dctx->sset)) {
105-
datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
106-
src += srclen - datalen;
107-
srclen = datalen;
108-
}
100+
if (!nblocks)
101+
return;
109102

110-
r0 = dctx->r.r[0];
111-
r1 = dctx->r.r[1];
112-
r2 = dctx->r.r[2];
113-
r3 = dctx->r.r[3];
114-
r4 = dctx->r.r[4];
103+
r0 = key->r[0];
104+
r1 = key->r[1];
105+
r2 = key->r[2];
106+
r3 = key->r[3];
107+
r4 = key->r[4];
115108

116109
s1 = r1 * 5;
117110
s2 = r2 * 5;
118111
s3 = r3 * 5;
119112
s4 = r4 * 5;
120113

121-
h0 = dctx->h.h[0];
122-
h1 = dctx->h.h[1];
123-
h2 = dctx->h.h[2];
124-
h3 = dctx->h.h[3];
125-
h4 = dctx->h.h[4];
126-
127-
while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
114+
h0 = state->h[0];
115+
h1 = state->h[1];
116+
h2 = state->h[2];
117+
h3 = state->h[3];
118+
h4 = state->h[4];
128119

120+
do {
129121
/* h += m[i] */
130122
h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff;
131123
h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff;
@@ -154,16 +146,36 @@ static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
154146
h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
155147

156148
src += POLY1305_BLOCK_SIZE;
157-
srclen -= POLY1305_BLOCK_SIZE;
158-
}
149+
} while (--nblocks);
159150

160-
dctx->h.h[0] = h0;
161-
dctx->h.h[1] = h1;
162-
dctx->h.h[2] = h2;
163-
dctx->h.h[3] = h3;
164-
dctx->h.h[4] = h4;
151+
state->h[0] = h0;
152+
state->h[1] = h1;
153+
state->h[2] = h2;
154+
state->h[3] = h3;
155+
state->h[4] = h4;
156+
}
165157

166-
return srclen;
158+
void 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+
}
164+
EXPORT_SYMBOL_GPL(poly1305_core_blocks);
165+
166+
static 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);
167179
}
168180

169181
int crypto_poly1305_update(struct shash_desc *desc,
@@ -187,9 +199,9 @@ int crypto_poly1305_update(struct shash_desc *desc,
187199
}
188200

189201
if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
190-
bytes = poly1305_blocks(dctx, src, srclen, 1 << 24);
191-
src += srclen - bytes;
192-
srclen = bytes;
202+
poly1305_blocks(dctx, src, srclen, 1 << 24);
203+
src += srclen - (srclen % POLY1305_BLOCK_SIZE);
204+
srclen %= POLY1305_BLOCK_SIZE;
193205
}
194206

195207
if (unlikely(srclen)) {
@@ -201,30 +213,18 @@ int crypto_poly1305_update(struct shash_desc *desc,
201213
}
202214
EXPORT_SYMBOL_GPL(crypto_poly1305_update);
203215

204-
int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
216+
void poly1305_core_emit(const struct poly1305_state *state, void *dst)
205217
{
206-
struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
207218
u32 h0, h1, h2, h3, h4;
208219
u32 g0, g1, g2, g3, g4;
209220
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-
}
221221

222222
/* fully carry h */
223-
h0 = dctx->h.h[0];
224-
h1 = dctx->h.h[1];
225-
h2 = dctx->h.h[2];
226-
h3 = dctx->h.h[3];
227-
h4 = dctx->h.h[4];
223+
h0 = state->h[0];
224+
h1 = state->h[1];
225+
h2 = state->h[2];
226+
h3 = state->h[3];
227+
h4 = state->h[4];
228228

229229
h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
230230
h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
@@ -254,16 +254,40 @@ int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
254254
h4 = (h4 & mask) | g4;
255255

256256
/* h = h % (2^128) */
257-
h0 = (h0 >> 0) | (h1 << 26);
258-
h1 = (h1 >> 6) | (h2 << 20);
259-
h2 = (h2 >> 12) | (h3 << 14);
260-
h3 = (h3 >> 18) | (h4 << 8);
257+
put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0);
258+
put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4);
259+
put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8);
260+
put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12);
261+
}
262+
EXPORT_SYMBOL_GPL(poly1305_core_emit);
263+
264+
int 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);
261281

262282
/* mac = (h + s) % (2^128) */
263-
f = (f >> 32) + h0 + dctx->s[0]; put_unaligned_le32(f, dst + 0);
264-
f = (f >> 32) + h1 + dctx->s[1]; put_unaligned_le32(f, dst + 4);
265-
f = (f >> 32) + h2 + dctx->s[2]; put_unaligned_le32(f, dst + 8);
266-
f = (f >> 32) + h3 + dctx->s[3]; put_unaligned_le32(f, dst + 12);
283+
f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0];
284+
put_unaligned_le32(f, dst + 0);
285+
f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1];
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);
267291

268292
return 0;
269293
}

include/crypto/poly1305.h

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ struct poly1305_desc_ctx {
3838
bool sset;
3939
};
4040

41+
/*
42+
* Poly1305 core functions. These implement the ε-almost-∆-universal hash
43+
* function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce
44+
* ("s key") at the end. They also only support block-aligned inputs.
45+
*/
46+
void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key);
47+
static inline void poly1305_core_init(struct poly1305_state *state)
48+
{
49+
memset(state->h, 0, sizeof(state->h));
50+
}
51+
void poly1305_core_blocks(struct poly1305_state *state,
52+
const struct poly1305_key *key,
53+
const void *src, unsigned int nblocks);
54+
void poly1305_core_emit(const struct poly1305_state *state, void *dst);
55+
56+
/* Crypto API helper functions for the Poly1305 MAC */
4157
int crypto_poly1305_init(struct shash_desc *desc);
4258
unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
4359
const u8 *src, unsigned int srclen);

0 commit comments

Comments
 (0)