xref: /openbmc/linux/lib/crypto/poly1305.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
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