1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Poly1305 authenticator algorithm, RFC7539
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2015 Martin Willi
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <crypto/internal/poly1305.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <asm/unaligned.h>
14*4882a593Smuzhiyun
poly1305_init_generic(struct poly1305_desc_ctx * desc,const u8 key[POLY1305_KEY_SIZE])15*4882a593Smuzhiyun void poly1305_init_generic(struct poly1305_desc_ctx *desc,
16*4882a593Smuzhiyun const u8 key[POLY1305_KEY_SIZE])
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun poly1305_core_setkey(&desc->core_r, key);
19*4882a593Smuzhiyun desc->s[0] = get_unaligned_le32(key + 16);
20*4882a593Smuzhiyun desc->s[1] = get_unaligned_le32(key + 20);
21*4882a593Smuzhiyun desc->s[2] = get_unaligned_le32(key + 24);
22*4882a593Smuzhiyun desc->s[3] = get_unaligned_le32(key + 28);
23*4882a593Smuzhiyun poly1305_core_init(&desc->h);
24*4882a593Smuzhiyun desc->buflen = 0;
25*4882a593Smuzhiyun desc->sset = true;
26*4882a593Smuzhiyun desc->rset = 2;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(poly1305_init_generic);
29*4882a593Smuzhiyun
poly1305_update_generic(struct poly1305_desc_ctx * desc,const u8 * src,unsigned int nbytes)30*4882a593Smuzhiyun void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
31*4882a593Smuzhiyun unsigned int nbytes)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun unsigned int bytes;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (unlikely(desc->buflen)) {
36*4882a593Smuzhiyun bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen);
37*4882a593Smuzhiyun memcpy(desc->buf + desc->buflen, src, bytes);
38*4882a593Smuzhiyun src += bytes;
39*4882a593Smuzhiyun nbytes -= bytes;
40*4882a593Smuzhiyun desc->buflen += bytes;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (desc->buflen == POLY1305_BLOCK_SIZE) {
43*4882a593Smuzhiyun poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf,
44*4882a593Smuzhiyun 1, 1);
45*4882a593Smuzhiyun desc->buflen = 0;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
50*4882a593Smuzhiyun poly1305_core_blocks(&desc->h, &desc->core_r, src,
51*4882a593Smuzhiyun nbytes / POLY1305_BLOCK_SIZE, 1);
52*4882a593Smuzhiyun src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
53*4882a593Smuzhiyun nbytes %= POLY1305_BLOCK_SIZE;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun if (unlikely(nbytes)) {
57*4882a593Smuzhiyun desc->buflen = nbytes;
58*4882a593Smuzhiyun memcpy(desc->buf, src, nbytes);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(poly1305_update_generic);
62*4882a593Smuzhiyun
poly1305_final_generic(struct poly1305_desc_ctx * desc,u8 * dst)63*4882a593Smuzhiyun void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun if (unlikely(desc->buflen)) {
66*4882a593Smuzhiyun desc->buf[desc->buflen++] = 1;
67*4882a593Smuzhiyun memset(desc->buf + desc->buflen, 0,
68*4882a593Smuzhiyun POLY1305_BLOCK_SIZE - desc->buflen);
69*4882a593Smuzhiyun poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun poly1305_core_emit(&desc->h, desc->s, dst);
73*4882a593Smuzhiyun *desc = (struct poly1305_desc_ctx){};
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(poly1305_final_generic);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun MODULE_LICENSE("GPL");
78*4882a593Smuzhiyun MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
79