148ea8c6eSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0-or-later
248ea8c6eSArd Biesheuvel /*
348ea8c6eSArd Biesheuvel * Poly1305 authenticator algorithm, RFC7539
448ea8c6eSArd Biesheuvel *
548ea8c6eSArd Biesheuvel * Copyright (C) 2015 Martin Willi
648ea8c6eSArd Biesheuvel *
748ea8c6eSArd Biesheuvel * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
848ea8c6eSArd Biesheuvel */
948ea8c6eSArd Biesheuvel
1048ea8c6eSArd Biesheuvel #include <crypto/internal/poly1305.h>
1148ea8c6eSArd Biesheuvel #include <linux/kernel.h>
1248ea8c6eSArd Biesheuvel #include <linux/module.h>
1348ea8c6eSArd Biesheuvel #include <asm/unaligned.h>
1448ea8c6eSArd Biesheuvel
poly1305_init_generic(struct poly1305_desc_ctx * desc,const u8 key[POLY1305_KEY_SIZE])15*8d195e7aSArnd Bergmann void poly1305_init_generic(struct poly1305_desc_ctx *desc,
16*8d195e7aSArnd Bergmann const u8 key[POLY1305_KEY_SIZE])
17a1d93064SArd Biesheuvel {
181c08a104SJason A. Donenfeld poly1305_core_setkey(&desc->core_r, key);
19a1d93064SArd Biesheuvel desc->s[0] = get_unaligned_le32(key + 16);
20a1d93064SArd Biesheuvel desc->s[1] = get_unaligned_le32(key + 20);
21a1d93064SArd Biesheuvel desc->s[2] = get_unaligned_le32(key + 24);
22a1d93064SArd Biesheuvel desc->s[3] = get_unaligned_le32(key + 28);
23a1d93064SArd Biesheuvel poly1305_core_init(&desc->h);
24a1d93064SArd Biesheuvel desc->buflen = 0;
25a1d93064SArd Biesheuvel desc->sset = true;
261c08a104SJason A. Donenfeld desc->rset = 2;
27a1d93064SArd Biesheuvel }
28a1d93064SArd Biesheuvel EXPORT_SYMBOL_GPL(poly1305_init_generic);
29a1d93064SArd Biesheuvel
poly1305_update_generic(struct poly1305_desc_ctx * desc,const u8 * src,unsigned int nbytes)30a1d93064SArd Biesheuvel void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
31a1d93064SArd Biesheuvel unsigned int nbytes)
32a1d93064SArd Biesheuvel {
33a1d93064SArd Biesheuvel unsigned int bytes;
34a1d93064SArd Biesheuvel
35a1d93064SArd Biesheuvel if (unlikely(desc->buflen)) {
36a1d93064SArd Biesheuvel bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen);
37a1d93064SArd Biesheuvel memcpy(desc->buf + desc->buflen, src, bytes);
38a1d93064SArd Biesheuvel src += bytes;
39a1d93064SArd Biesheuvel nbytes -= bytes;
40a1d93064SArd Biesheuvel desc->buflen += bytes;
41a1d93064SArd Biesheuvel
42a1d93064SArd Biesheuvel if (desc->buflen == POLY1305_BLOCK_SIZE) {
431c08a104SJason A. Donenfeld poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf,
441c08a104SJason A. Donenfeld 1, 1);
45a1d93064SArd Biesheuvel desc->buflen = 0;
46a1d93064SArd Biesheuvel }
47a1d93064SArd Biesheuvel }
48a1d93064SArd Biesheuvel
49a1d93064SArd Biesheuvel if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
501c08a104SJason A. Donenfeld poly1305_core_blocks(&desc->h, &desc->core_r, src,
51a1d93064SArd Biesheuvel nbytes / POLY1305_BLOCK_SIZE, 1);
52a1d93064SArd Biesheuvel src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
53a1d93064SArd Biesheuvel nbytes %= POLY1305_BLOCK_SIZE;
54a1d93064SArd Biesheuvel }
55a1d93064SArd Biesheuvel
56a1d93064SArd Biesheuvel if (unlikely(nbytes)) {
57a1d93064SArd Biesheuvel desc->buflen = nbytes;
58a1d93064SArd Biesheuvel memcpy(desc->buf, src, nbytes);
59a1d93064SArd Biesheuvel }
60a1d93064SArd Biesheuvel }
61a1d93064SArd Biesheuvel EXPORT_SYMBOL_GPL(poly1305_update_generic);
62a1d93064SArd Biesheuvel
poly1305_final_generic(struct poly1305_desc_ctx * desc,u8 * dst)63a1d93064SArd Biesheuvel void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
64a1d93064SArd Biesheuvel {
65a1d93064SArd Biesheuvel if (unlikely(desc->buflen)) {
66a1d93064SArd Biesheuvel desc->buf[desc->buflen++] = 1;
67a1d93064SArd Biesheuvel memset(desc->buf + desc->buflen, 0,
68a1d93064SArd Biesheuvel POLY1305_BLOCK_SIZE - desc->buflen);
691c08a104SJason A. Donenfeld poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0);
70a1d93064SArd Biesheuvel }
71a1d93064SArd Biesheuvel
721c08a104SJason A. Donenfeld poly1305_core_emit(&desc->h, desc->s, dst);
73a1d93064SArd Biesheuvel *desc = (struct poly1305_desc_ctx){};
74a1d93064SArd Biesheuvel }
75a1d93064SArd Biesheuvel EXPORT_SYMBOL_GPL(poly1305_final_generic);
76a1d93064SArd Biesheuvel
7748ea8c6eSArd Biesheuvel MODULE_LICENSE("GPL");
7848ea8c6eSArd Biesheuvel MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
79