xref: /openbmc/linux/arch/mips/crypto/poly1305-glue.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
1a11d055eSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0
2a11d055eSArd Biesheuvel /*
3a11d055eSArd Biesheuvel  * OpenSSL/Cryptogams accelerated Poly1305 transform for MIPS
4a11d055eSArd Biesheuvel  *
5a11d055eSArd Biesheuvel  * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
6a11d055eSArd Biesheuvel  */
7a11d055eSArd Biesheuvel 
8a11d055eSArd Biesheuvel #include <asm/unaligned.h>
9a11d055eSArd Biesheuvel #include <crypto/algapi.h>
10a11d055eSArd Biesheuvel #include <crypto/internal/hash.h>
11a11d055eSArd Biesheuvel #include <crypto/internal/poly1305.h>
12a11d055eSArd Biesheuvel #include <linux/cpufeature.h>
13a11d055eSArd Biesheuvel #include <linux/crypto.h>
14a11d055eSArd Biesheuvel #include <linux/module.h>
15a11d055eSArd Biesheuvel 
16a11d055eSArd Biesheuvel asmlinkage void poly1305_init_mips(void *state, const u8 *key);
17a11d055eSArd Biesheuvel asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
1831899908SJason A. Donenfeld asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce);
19a11d055eSArd Biesheuvel 
poly1305_init_arch(struct poly1305_desc_ctx * dctx,const u8 key[POLY1305_KEY_SIZE])20*8d195e7aSArnd Bergmann void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
21a11d055eSArd Biesheuvel {
22a11d055eSArd Biesheuvel 	poly1305_init_mips(&dctx->h, key);
23a11d055eSArd Biesheuvel 	dctx->s[0] = get_unaligned_le32(key + 16);
24a11d055eSArd Biesheuvel 	dctx->s[1] = get_unaligned_le32(key + 20);
25a11d055eSArd Biesheuvel 	dctx->s[2] = get_unaligned_le32(key + 24);
26a11d055eSArd Biesheuvel 	dctx->s[3] = get_unaligned_le32(key + 28);
27a11d055eSArd Biesheuvel 	dctx->buflen = 0;
28a11d055eSArd Biesheuvel }
29a11d055eSArd Biesheuvel EXPORT_SYMBOL(poly1305_init_arch);
30a11d055eSArd Biesheuvel 
mips_poly1305_init(struct shash_desc * desc)31a11d055eSArd Biesheuvel static int mips_poly1305_init(struct shash_desc *desc)
32a11d055eSArd Biesheuvel {
33a11d055eSArd Biesheuvel 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
34a11d055eSArd Biesheuvel 
35a11d055eSArd Biesheuvel 	dctx->buflen = 0;
36a11d055eSArd Biesheuvel 	dctx->rset = 0;
37a11d055eSArd Biesheuvel 	dctx->sset = false;
38a11d055eSArd Biesheuvel 
39a11d055eSArd Biesheuvel 	return 0;
40a11d055eSArd Biesheuvel }
41a11d055eSArd Biesheuvel 
mips_poly1305_blocks(struct poly1305_desc_ctx * dctx,const u8 * src,u32 len,u32 hibit)42a11d055eSArd Biesheuvel static void mips_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
43a11d055eSArd Biesheuvel 				 u32 len, u32 hibit)
44a11d055eSArd Biesheuvel {
45a11d055eSArd Biesheuvel 	if (unlikely(!dctx->sset)) {
46a11d055eSArd Biesheuvel 		if (!dctx->rset) {
47a11d055eSArd Biesheuvel 			poly1305_init_mips(&dctx->h, src);
48a11d055eSArd Biesheuvel 			src += POLY1305_BLOCK_SIZE;
49a11d055eSArd Biesheuvel 			len -= POLY1305_BLOCK_SIZE;
50a11d055eSArd Biesheuvel 			dctx->rset = 1;
51a11d055eSArd Biesheuvel 		}
52a11d055eSArd Biesheuvel 		if (len >= POLY1305_BLOCK_SIZE) {
53a11d055eSArd Biesheuvel 			dctx->s[0] = get_unaligned_le32(src +  0);
54a11d055eSArd Biesheuvel 			dctx->s[1] = get_unaligned_le32(src +  4);
55a11d055eSArd Biesheuvel 			dctx->s[2] = get_unaligned_le32(src +  8);
56a11d055eSArd Biesheuvel 			dctx->s[3] = get_unaligned_le32(src + 12);
57a11d055eSArd Biesheuvel 			src += POLY1305_BLOCK_SIZE;
58a11d055eSArd Biesheuvel 			len -= POLY1305_BLOCK_SIZE;
59a11d055eSArd Biesheuvel 			dctx->sset = true;
60a11d055eSArd Biesheuvel 		}
61a11d055eSArd Biesheuvel 		if (len < POLY1305_BLOCK_SIZE)
62a11d055eSArd Biesheuvel 			return;
63a11d055eSArd Biesheuvel 	}
64a11d055eSArd Biesheuvel 
65a11d055eSArd Biesheuvel 	len &= ~(POLY1305_BLOCK_SIZE - 1);
66a11d055eSArd Biesheuvel 
67a11d055eSArd Biesheuvel 	poly1305_blocks_mips(&dctx->h, src, len, hibit);
68a11d055eSArd Biesheuvel }
69a11d055eSArd Biesheuvel 
mips_poly1305_update(struct shash_desc * desc,const u8 * src,unsigned int len)70a11d055eSArd Biesheuvel static int mips_poly1305_update(struct shash_desc *desc, const u8 *src,
71a11d055eSArd Biesheuvel 				unsigned int len)
72a11d055eSArd Biesheuvel {
73a11d055eSArd Biesheuvel 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
74a11d055eSArd Biesheuvel 
75a11d055eSArd Biesheuvel 	if (unlikely(dctx->buflen)) {
76a11d055eSArd Biesheuvel 		u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen);
77a11d055eSArd Biesheuvel 
78a11d055eSArd Biesheuvel 		memcpy(dctx->buf + dctx->buflen, src, bytes);
79a11d055eSArd Biesheuvel 		src += bytes;
80a11d055eSArd Biesheuvel 		len -= bytes;
81a11d055eSArd Biesheuvel 		dctx->buflen += bytes;
82a11d055eSArd Biesheuvel 
83a11d055eSArd Biesheuvel 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
84a11d055eSArd Biesheuvel 			mips_poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 1);
85a11d055eSArd Biesheuvel 			dctx->buflen = 0;
86a11d055eSArd Biesheuvel 		}
87a11d055eSArd Biesheuvel 	}
88a11d055eSArd Biesheuvel 
89a11d055eSArd Biesheuvel 	if (likely(len >= POLY1305_BLOCK_SIZE)) {
90a11d055eSArd Biesheuvel 		mips_poly1305_blocks(dctx, src, len, 1);
91a11d055eSArd Biesheuvel 		src += round_down(len, POLY1305_BLOCK_SIZE);
92a11d055eSArd Biesheuvel 		len %= POLY1305_BLOCK_SIZE;
93a11d055eSArd Biesheuvel 	}
94a11d055eSArd Biesheuvel 
95a11d055eSArd Biesheuvel 	if (unlikely(len)) {
96a11d055eSArd Biesheuvel 		dctx->buflen = len;
97a11d055eSArd Biesheuvel 		memcpy(dctx->buf, src, len);
98a11d055eSArd Biesheuvel 	}
99a11d055eSArd Biesheuvel 	return 0;
100a11d055eSArd Biesheuvel }
101a11d055eSArd Biesheuvel 
poly1305_update_arch(struct poly1305_desc_ctx * dctx,const u8 * src,unsigned int nbytes)102a11d055eSArd Biesheuvel void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
103a11d055eSArd Biesheuvel 			  unsigned int nbytes)
104a11d055eSArd Biesheuvel {
105a11d055eSArd Biesheuvel 	if (unlikely(dctx->buflen)) {
106a11d055eSArd Biesheuvel 		u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen);
107a11d055eSArd Biesheuvel 
108a11d055eSArd Biesheuvel 		memcpy(dctx->buf + dctx->buflen, src, bytes);
109a11d055eSArd Biesheuvel 		src += bytes;
110a11d055eSArd Biesheuvel 		nbytes -= bytes;
111a11d055eSArd Biesheuvel 		dctx->buflen += bytes;
112a11d055eSArd Biesheuvel 
113a11d055eSArd Biesheuvel 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
114a11d055eSArd Biesheuvel 			poly1305_blocks_mips(&dctx->h, dctx->buf,
115a11d055eSArd Biesheuvel 					     POLY1305_BLOCK_SIZE, 1);
116a11d055eSArd Biesheuvel 			dctx->buflen = 0;
117a11d055eSArd Biesheuvel 		}
118a11d055eSArd Biesheuvel 	}
119a11d055eSArd Biesheuvel 
120a11d055eSArd Biesheuvel 	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
121a11d055eSArd Biesheuvel 		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
122a11d055eSArd Biesheuvel 
123a11d055eSArd Biesheuvel 		poly1305_blocks_mips(&dctx->h, src, len, 1);
124a11d055eSArd Biesheuvel 		src += len;
125a11d055eSArd Biesheuvel 		nbytes %= POLY1305_BLOCK_SIZE;
126a11d055eSArd Biesheuvel 	}
127a11d055eSArd Biesheuvel 
128a11d055eSArd Biesheuvel 	if (unlikely(nbytes)) {
129a11d055eSArd Biesheuvel 		dctx->buflen = nbytes;
130a11d055eSArd Biesheuvel 		memcpy(dctx->buf, src, nbytes);
131a11d055eSArd Biesheuvel 	}
132a11d055eSArd Biesheuvel }
133a11d055eSArd Biesheuvel EXPORT_SYMBOL(poly1305_update_arch);
134a11d055eSArd Biesheuvel 
poly1305_final_arch(struct poly1305_desc_ctx * dctx,u8 * dst)135a11d055eSArd Biesheuvel void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
136a11d055eSArd Biesheuvel {
137a11d055eSArd Biesheuvel 	if (unlikely(dctx->buflen)) {
138a11d055eSArd Biesheuvel 		dctx->buf[dctx->buflen++] = 1;
139a11d055eSArd Biesheuvel 		memset(dctx->buf + dctx->buflen, 0,
140a11d055eSArd Biesheuvel 		       POLY1305_BLOCK_SIZE - dctx->buflen);
141a11d055eSArd Biesheuvel 		poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
142a11d055eSArd Biesheuvel 	}
143a11d055eSArd Biesheuvel 
14431899908SJason A. Donenfeld 	poly1305_emit_mips(&dctx->h, dst, dctx->s);
145a11d055eSArd Biesheuvel 	*dctx = (struct poly1305_desc_ctx){};
146a11d055eSArd Biesheuvel }
147a11d055eSArd Biesheuvel EXPORT_SYMBOL(poly1305_final_arch);
148a11d055eSArd Biesheuvel 
mips_poly1305_final(struct shash_desc * desc,u8 * dst)149a11d055eSArd Biesheuvel static int mips_poly1305_final(struct shash_desc *desc, u8 *dst)
150a11d055eSArd Biesheuvel {
151a11d055eSArd Biesheuvel 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
152a11d055eSArd Biesheuvel 
153a11d055eSArd Biesheuvel 	if (unlikely(!dctx->sset))
154a11d055eSArd Biesheuvel 		return -ENOKEY;
155a11d055eSArd Biesheuvel 
156a11d055eSArd Biesheuvel 	poly1305_final_arch(dctx, dst);
157a11d055eSArd Biesheuvel 	return 0;
158a11d055eSArd Biesheuvel }
159a11d055eSArd Biesheuvel 
160a11d055eSArd Biesheuvel static struct shash_alg mips_poly1305_alg = {
161a11d055eSArd Biesheuvel 	.init			= mips_poly1305_init,
162a11d055eSArd Biesheuvel 	.update			= mips_poly1305_update,
163a11d055eSArd Biesheuvel 	.final			= mips_poly1305_final,
164a11d055eSArd Biesheuvel 	.digestsize		= POLY1305_DIGEST_SIZE,
165a11d055eSArd Biesheuvel 	.descsize		= sizeof(struct poly1305_desc_ctx),
166a11d055eSArd Biesheuvel 
167a11d055eSArd Biesheuvel 	.base.cra_name		= "poly1305",
168a11d055eSArd Biesheuvel 	.base.cra_driver_name	= "poly1305-mips",
169a11d055eSArd Biesheuvel 	.base.cra_priority	= 200,
170a11d055eSArd Biesheuvel 	.base.cra_blocksize	= POLY1305_BLOCK_SIZE,
171a11d055eSArd Biesheuvel 	.base.cra_module	= THIS_MODULE,
172a11d055eSArd Biesheuvel };
173a11d055eSArd Biesheuvel 
mips_poly1305_mod_init(void)174a11d055eSArd Biesheuvel static int __init mips_poly1305_mod_init(void)
175a11d055eSArd Biesheuvel {
1768394bfecSJason A. Donenfeld 	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
1778394bfecSJason A. Donenfeld 		crypto_register_shash(&mips_poly1305_alg) : 0;
178a11d055eSArd Biesheuvel }
179a11d055eSArd Biesheuvel 
mips_poly1305_mod_exit(void)180a11d055eSArd Biesheuvel static void __exit mips_poly1305_mod_exit(void)
181a11d055eSArd Biesheuvel {
1828394bfecSJason A. Donenfeld 	if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
183a11d055eSArd Biesheuvel 		crypto_unregister_shash(&mips_poly1305_alg);
184a11d055eSArd Biesheuvel }
185a11d055eSArd Biesheuvel 
186a11d055eSArd Biesheuvel module_init(mips_poly1305_mod_init);
187a11d055eSArd Biesheuvel module_exit(mips_poly1305_mod_exit);
188a11d055eSArd Biesheuvel 
189a11d055eSArd Biesheuvel MODULE_LICENSE("GPL v2");
190a11d055eSArd Biesheuvel MODULE_ALIAS_CRYPTO("poly1305");
191a11d055eSArd Biesheuvel MODULE_ALIAS_CRYPTO("poly1305-mips");
192