aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2015-06-01 07:43:58 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2015-06-04 03:04:50 -0400
commitf979e014c50ce3f7467f133898dbea2243247a91 (patch)
treeb9b3bb455c76a9a94e3fcbe7fa9726890e083942 /crypto
parent3590ebf2b4c40aa4b663c4f2b9dfeb0a1e0b8f32 (diff)
crypto: poly1305 - Add a generic Poly1305 authenticator implementation
Poly1305 is a fast message authenticator designed by Daniel J. Bernstein. It is further defined in RFC7539 as a building block for the ChaCha20-Poly1305 AEAD for use in IETF protocols. This is a portable C implementation of the algorithm without architecture specific optimizations, based on public domain code by Daniel J. Bernstein and Andrew Moon. Signed-off-by: Martin Willi <martin@strongswan.org> Acked-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/Kconfig9
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/poly1305_generic.c300
3 files changed, 310 insertions, 0 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index bf657becbb71..9c00454ed024 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -426,6 +426,15 @@ config CRYPTO_GHASH
426 help 426 help
427 GHASH is message digest algorithm for GCM (Galois/Counter Mode). 427 GHASH is message digest algorithm for GCM (Galois/Counter Mode).
428 428
429config CRYPTO_POLY1305
430 tristate "Poly1305 authenticator algorithm"
431 help
432 Poly1305 authenticator algorithm, RFC7539.
433
434 Poly1305 is an authenticator algorithm designed by Daniel J. Bernstein.
435 It is used for the ChaCha20-Poly1305 AEAD, specified in RFC7539 for use
436 in IETF protocols. This is the portable C implementation of Poly1305.
437
429config CRYPTO_MD4 438config CRYPTO_MD4
430 tristate "MD4 digest algorithm" 439 tristate "MD4 digest algorithm"
431 select CRYPTO_HASH 440 select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index be87ec1a62eb..2424c81d69bc 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
81obj-$(CONFIG_CRYPTO_SEED) += seed.o 81obj-$(CONFIG_CRYPTO_SEED) += seed.o
82obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o 82obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
83obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o 83obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
84obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
84obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o 85obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
85obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o 86obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
86obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o 87obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
new file mode 100644
index 000000000000..9c1159b991f4
--- /dev/null
+++ b/crypto/poly1305_generic.c
@@ -0,0 +1,300 @@
1/*
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");