blob: 9c1159b991f401f609d713018558a3f9b68ebdb3 [file] [log] [blame]
Martin Willif979e012015-06-01 13:43:58 +02001/*
2 * Poly1305 authenticator algorithm, RFC7539
3 *
4 * Copyright (C) 2015 Martin Willi
5 *
6 * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <crypto/algapi.h>
15#include <crypto/internal/hash.h>
16#include <linux/crypto.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19
20#define POLY1305_BLOCK_SIZE 16
21#define POLY1305_KEY_SIZE 32
22#define POLY1305_DIGEST_SIZE 16
23
24struct poly1305_ctx {
25 /* key */
26 u32 r[5];
27 /* finalize key */
28 u32 s[4];
29};
30
31struct poly1305_desc_ctx {
32 /* accumulator */
33 u32 h[5];
34 /* partial buffer */
35 u8 buf[POLY1305_BLOCK_SIZE];
36 /* bytes used in partial buffer */
37 unsigned int buflen;
38};
39
40static inline u64 mlt(u64 a, u64 b)
41{
42 return a * b;
43}
44
45static inline u32 sr(u64 v, u_char n)
46{
47 return v >> n;
48}
49
50static inline u32 and(u32 v, u32 mask)
51{
52 return v & mask;
53}
54
55static inline u32 le32_to_cpuvp(const void *p)
56{
57 return le32_to_cpup(p);
58}
59
60static int poly1305_init(struct shash_desc *desc)
61{
62 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
63
64 memset(dctx->h, 0, sizeof(dctx->h));
65 dctx->buflen = 0;
66
67 return 0;
68}
69
70static int poly1305_setkey(struct crypto_shash *tfm,
71 const u8 *key, unsigned int keylen)
72{
73 struct poly1305_ctx *ctx = crypto_shash_ctx(tfm);
74
75 if (keylen != POLY1305_KEY_SIZE) {
76 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
77 return -EINVAL;
78 }
79
80 /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
81 ctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff;
82 ctx->r[1] = (le32_to_cpuvp(key + 3) >> 2) & 0x3ffff03;
83 ctx->r[2] = (le32_to_cpuvp(key + 6) >> 4) & 0x3ffc0ff;
84 ctx->r[3] = (le32_to_cpuvp(key + 9) >> 6) & 0x3f03fff;
85 ctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff;
86
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 return 0;
93}
94
95static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
96 struct poly1305_ctx *ctx, const u8 *src,
97 unsigned int srclen, u32 hibit)
98{
99 u32 r0, r1, r2, r3, r4;
100 u32 s1, s2, s3, s4;
101 u32 h0, h1, h2, h3, h4;
102 u64 d0, d1, d2, d3, d4;
103
104 r0 = ctx->r[0];
105 r1 = ctx->r[1];
106 r2 = ctx->r[2];
107 r3 = ctx->r[3];
108 r4 = ctx->r[4];
109
110 s1 = r1 * 5;
111 s2 = r2 * 5;
112 s3 = r3 * 5;
113 s4 = r4 * 5;
114
115 h0 = dctx->h[0];
116 h1 = dctx->h[1];
117 h2 = dctx->h[2];
118 h3 = dctx->h[3];
119 h4 = dctx->h[4];
120
121 while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
122
123 /* h += m[i] */
124 h0 += (le32_to_cpuvp(src + 0) >> 0) & 0x3ffffff;
125 h1 += (le32_to_cpuvp(src + 3) >> 2) & 0x3ffffff;
126 h2 += (le32_to_cpuvp(src + 6) >> 4) & 0x3ffffff;
127 h3 += (le32_to_cpuvp(src + 9) >> 6) & 0x3ffffff;
128 h4 += (le32_to_cpuvp(src + 12) >> 8) | hibit;
129
130 /* h *= r */
131 d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
132 mlt(h3, s2) + mlt(h4, s1);
133 d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
134 mlt(h3, s3) + mlt(h4, s2);
135 d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
136 mlt(h3, s4) + mlt(h4, s3);
137 d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
138 mlt(h3, r0) + mlt(h4, s4);
139 d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
140 mlt(h3, r1) + mlt(h4, r0);
141
142 /* (partial) h %= p */
143 d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
144 d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
145 d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
146 d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
147 h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
148 h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
149
150 src += POLY1305_BLOCK_SIZE;
151 srclen -= POLY1305_BLOCK_SIZE;
152 }
153
154 dctx->h[0] = h0;
155 dctx->h[1] = h1;
156 dctx->h[2] = h2;
157 dctx->h[3] = h3;
158 dctx->h[4] = h4;
159
160 return srclen;
161}
162
163static int poly1305_update(struct shash_desc *desc,
164 const u8 *src, unsigned int srclen)
165{
166 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
167 struct poly1305_ctx *ctx = crypto_shash_ctx(desc->tfm);
168 unsigned int bytes;
169
170 if (unlikely(dctx->buflen)) {
171 bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
172 memcpy(dctx->buf + dctx->buflen, src, bytes);
173 src += bytes;
174 srclen -= bytes;
175 dctx->buflen += bytes;
176
177 if (dctx->buflen == POLY1305_BLOCK_SIZE) {
178 poly1305_blocks(dctx, ctx, dctx->buf,
179 POLY1305_BLOCK_SIZE, 1 << 24);
180 dctx->buflen = 0;
181 }
182 }
183
184 if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
185 bytes = poly1305_blocks(dctx, ctx, src, srclen, 1 << 24);
186 src += srclen - bytes;
187 srclen = bytes;
188 }
189
190 if (unlikely(srclen)) {
191 dctx->buflen = srclen;
192 memcpy(dctx->buf, src, srclen);
193 }
194
195 return 0;
196}
197
198static int poly1305_final(struct shash_desc *desc, u8 *dst)
199{
200 struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
201 struct poly1305_ctx *ctx = crypto_shash_ctx(desc->tfm);
202 __le32 *mac = (__le32 *)dst;
203 u32 h0, h1, h2, h3, h4;
204 u32 g0, g1, g2, g3, g4;
205 u32 mask;
206 u64 f = 0;
207
208 if (unlikely(dctx->buflen)) {
209 dctx->buf[dctx->buflen++] = 1;
210 memset(dctx->buf + dctx->buflen, 0,
211 POLY1305_BLOCK_SIZE - dctx->buflen);
212 poly1305_blocks(dctx, ctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
213 }
214
215 /* fully carry h */
216 h0 = dctx->h[0];
217 h1 = dctx->h[1];
218 h2 = dctx->h[2];
219 h3 = dctx->h[3];
220 h4 = dctx->h[4];
221
222 h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
223 h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
224 h4 += (h3 >> 26); h3 = h3 & 0x3ffffff;
225 h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
226 h1 += (h0 >> 26); h0 = h0 & 0x3ffffff;
227
228 /* compute h + -p */
229 g0 = h0 + 5;
230 g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff;
231 g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff;
232 g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff;
233 g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
234
235 /* select h if h < p, or h + -p if h >= p */
236 mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
237 g0 &= mask;
238 g1 &= mask;
239 g2 &= mask;
240 g3 &= mask;
241 g4 &= mask;
242 mask = ~mask;
243 h0 = (h0 & mask) | g0;
244 h1 = (h1 & mask) | g1;
245 h2 = (h2 & mask) | g2;
246 h3 = (h3 & mask) | g3;
247 h4 = (h4 & mask) | g4;
248
249 /* h = h % (2^128) */
250 h0 = (h0 >> 0) | (h1 << 26);
251 h1 = (h1 >> 6) | (h2 << 20);
252 h2 = (h2 >> 12) | (h3 << 14);
253 h3 = (h3 >> 18) | (h4 << 8);
254
255 /* mac = (h + s) % (2^128) */
256 f = (f >> 32) + h0 + ctx->s[0]; mac[0] = cpu_to_le32(f);
257 f = (f >> 32) + h1 + ctx->s[1]; mac[1] = cpu_to_le32(f);
258 f = (f >> 32) + h2 + ctx->s[2]; mac[2] = cpu_to_le32(f);
259 f = (f >> 32) + h3 + ctx->s[3]; mac[3] = cpu_to_le32(f);
260
261 return 0;
262}
263
264static struct shash_alg poly1305_alg = {
265 .digestsize = POLY1305_DIGEST_SIZE,
266 .init = poly1305_init,
267 .update = poly1305_update,
268 .final = poly1305_final,
269 .setkey = poly1305_setkey,
270 .descsize = sizeof(struct poly1305_desc_ctx),
271 .base = {
272 .cra_name = "poly1305",
273 .cra_driver_name = "poly1305-generic",
274 .cra_priority = 100,
275 .cra_flags = CRYPTO_ALG_TYPE_SHASH,
276 .cra_alignmask = sizeof(u32) - 1,
277 .cra_blocksize = POLY1305_BLOCK_SIZE,
278 .cra_ctxsize = sizeof(struct poly1305_ctx),
279 .cra_module = THIS_MODULE,
280 },
281};
282
283static int __init poly1305_mod_init(void)
284{
285 return crypto_register_shash(&poly1305_alg);
286}
287
288static void __exit poly1305_mod_exit(void)
289{
290 crypto_unregister_shash(&poly1305_alg);
291}
292
293module_init(poly1305_mod_init);
294module_exit(poly1305_mod_exit);
295
296MODULE_LICENSE("GPL");
297MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
298MODULE_DESCRIPTION("Poly1305 authenticator");
299MODULE_ALIAS_CRYPTO("poly1305");
300MODULE_ALIAS_CRYPTO("poly1305-generic");