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