1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * The AEGIS-128 Authenticated-Encryption Algorithm
4*4882a593Smuzhiyun * Glue for AES-NI + SSE2 implementation
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (c) 2017-2018 Ondrej Mosnacek <omosnacek@gmail.com>
7*4882a593Smuzhiyun * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <crypto/internal/aead.h>
11*4882a593Smuzhiyun #include <crypto/internal/simd.h>
12*4882a593Smuzhiyun #include <crypto/internal/skcipher.h>
13*4882a593Smuzhiyun #include <crypto/scatterwalk.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <asm/fpu/api.h>
16*4882a593Smuzhiyun #include <asm/cpu_device_id.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define AEGIS128_BLOCK_ALIGN 16
19*4882a593Smuzhiyun #define AEGIS128_BLOCK_SIZE 16
20*4882a593Smuzhiyun #define AEGIS128_NONCE_SIZE 16
21*4882a593Smuzhiyun #define AEGIS128_STATE_BLOCKS 5
22*4882a593Smuzhiyun #define AEGIS128_KEY_SIZE 16
23*4882a593Smuzhiyun #define AEGIS128_MIN_AUTH_SIZE 8
24*4882a593Smuzhiyun #define AEGIS128_MAX_AUTH_SIZE 16
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_init(void *state, void *key, void *iv);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_ad(
29*4882a593Smuzhiyun void *state, unsigned int length, const void *data);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_enc(
32*4882a593Smuzhiyun void *state, unsigned int length, const void *src, void *dst);
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_dec(
35*4882a593Smuzhiyun void *state, unsigned int length, const void *src, void *dst);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_enc_tail(
38*4882a593Smuzhiyun void *state, unsigned int length, const void *src, void *dst);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_dec_tail(
41*4882a593Smuzhiyun void *state, unsigned int length, const void *src, void *dst);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun asmlinkage void crypto_aegis128_aesni_final(
44*4882a593Smuzhiyun void *state, void *tag_xor, unsigned int cryptlen,
45*4882a593Smuzhiyun unsigned int assoclen);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct aegis_block {
48*4882a593Smuzhiyun u8 bytes[AEGIS128_BLOCK_SIZE] __aligned(AEGIS128_BLOCK_ALIGN);
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun struct aegis_state {
52*4882a593Smuzhiyun struct aegis_block blocks[AEGIS128_STATE_BLOCKS];
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct aegis_ctx {
56*4882a593Smuzhiyun struct aegis_block key;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun struct aegis_crypt_ops {
60*4882a593Smuzhiyun int (*skcipher_walk_init)(struct skcipher_walk *walk,
61*4882a593Smuzhiyun struct aead_request *req, bool atomic);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun void (*crypt_blocks)(void *state, unsigned int length, const void *src,
64*4882a593Smuzhiyun void *dst);
65*4882a593Smuzhiyun void (*crypt_tail)(void *state, unsigned int length, const void *src,
66*4882a593Smuzhiyun void *dst);
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
crypto_aegis128_aesni_process_ad(struct aegis_state * state,struct scatterlist * sg_src,unsigned int assoclen)69*4882a593Smuzhiyun static void crypto_aegis128_aesni_process_ad(
70*4882a593Smuzhiyun struct aegis_state *state, struct scatterlist *sg_src,
71*4882a593Smuzhiyun unsigned int assoclen)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun struct scatter_walk walk;
74*4882a593Smuzhiyun struct aegis_block buf;
75*4882a593Smuzhiyun unsigned int pos = 0;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun scatterwalk_start(&walk, sg_src);
78*4882a593Smuzhiyun while (assoclen != 0) {
79*4882a593Smuzhiyun unsigned int size = scatterwalk_clamp(&walk, assoclen);
80*4882a593Smuzhiyun unsigned int left = size;
81*4882a593Smuzhiyun void *mapped = scatterwalk_map(&walk);
82*4882a593Smuzhiyun const u8 *src = (const u8 *)mapped;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (pos + size >= AEGIS128_BLOCK_SIZE) {
85*4882a593Smuzhiyun if (pos > 0) {
86*4882a593Smuzhiyun unsigned int fill = AEGIS128_BLOCK_SIZE - pos;
87*4882a593Smuzhiyun memcpy(buf.bytes + pos, src, fill);
88*4882a593Smuzhiyun crypto_aegis128_aesni_ad(state,
89*4882a593Smuzhiyun AEGIS128_BLOCK_SIZE,
90*4882a593Smuzhiyun buf.bytes);
91*4882a593Smuzhiyun pos = 0;
92*4882a593Smuzhiyun left -= fill;
93*4882a593Smuzhiyun src += fill;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun crypto_aegis128_aesni_ad(state, left, src);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun src += left & ~(AEGIS128_BLOCK_SIZE - 1);
99*4882a593Smuzhiyun left &= AEGIS128_BLOCK_SIZE - 1;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun memcpy(buf.bytes + pos, src, left);
103*4882a593Smuzhiyun pos += left;
104*4882a593Smuzhiyun assoclen -= size;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun scatterwalk_unmap(mapped);
107*4882a593Smuzhiyun scatterwalk_advance(&walk, size);
108*4882a593Smuzhiyun scatterwalk_done(&walk, 0, assoclen);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (pos > 0) {
112*4882a593Smuzhiyun memset(buf.bytes + pos, 0, AEGIS128_BLOCK_SIZE - pos);
113*4882a593Smuzhiyun crypto_aegis128_aesni_ad(state, AEGIS128_BLOCK_SIZE, buf.bytes);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
crypto_aegis128_aesni_process_crypt(struct aegis_state * state,struct skcipher_walk * walk,const struct aegis_crypt_ops * ops)117*4882a593Smuzhiyun static void crypto_aegis128_aesni_process_crypt(
118*4882a593Smuzhiyun struct aegis_state *state, struct skcipher_walk *walk,
119*4882a593Smuzhiyun const struct aegis_crypt_ops *ops)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun while (walk->nbytes >= AEGIS128_BLOCK_SIZE) {
122*4882a593Smuzhiyun ops->crypt_blocks(state,
123*4882a593Smuzhiyun round_down(walk->nbytes, AEGIS128_BLOCK_SIZE),
124*4882a593Smuzhiyun walk->src.virt.addr, walk->dst.virt.addr);
125*4882a593Smuzhiyun skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (walk->nbytes) {
129*4882a593Smuzhiyun ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr,
130*4882a593Smuzhiyun walk->dst.virt.addr);
131*4882a593Smuzhiyun skcipher_walk_done(walk, 0);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
crypto_aegis128_aesni_ctx(struct crypto_aead * aead)135*4882a593Smuzhiyun static struct aegis_ctx *crypto_aegis128_aesni_ctx(struct crypto_aead *aead)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun u8 *ctx = crypto_aead_ctx(aead);
138*4882a593Smuzhiyun ctx = PTR_ALIGN(ctx, __alignof__(struct aegis_ctx));
139*4882a593Smuzhiyun return (void *)ctx;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
crypto_aegis128_aesni_setkey(struct crypto_aead * aead,const u8 * key,unsigned int keylen)142*4882a593Smuzhiyun static int crypto_aegis128_aesni_setkey(struct crypto_aead *aead, const u8 *key,
143*4882a593Smuzhiyun unsigned int keylen)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(aead);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (keylen != AEGIS128_KEY_SIZE)
148*4882a593Smuzhiyun return -EINVAL;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
crypto_aegis128_aesni_setauthsize(struct crypto_aead * tfm,unsigned int authsize)155*4882a593Smuzhiyun static int crypto_aegis128_aesni_setauthsize(struct crypto_aead *tfm,
156*4882a593Smuzhiyun unsigned int authsize)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun if (authsize > AEGIS128_MAX_AUTH_SIZE)
159*4882a593Smuzhiyun return -EINVAL;
160*4882a593Smuzhiyun if (authsize < AEGIS128_MIN_AUTH_SIZE)
161*4882a593Smuzhiyun return -EINVAL;
162*4882a593Smuzhiyun return 0;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
crypto_aegis128_aesni_crypt(struct aead_request * req,struct aegis_block * tag_xor,unsigned int cryptlen,const struct aegis_crypt_ops * ops)165*4882a593Smuzhiyun static void crypto_aegis128_aesni_crypt(struct aead_request *req,
166*4882a593Smuzhiyun struct aegis_block *tag_xor,
167*4882a593Smuzhiyun unsigned int cryptlen,
168*4882a593Smuzhiyun const struct aegis_crypt_ops *ops)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun struct crypto_aead *tfm = crypto_aead_reqtfm(req);
171*4882a593Smuzhiyun struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(tfm);
172*4882a593Smuzhiyun struct skcipher_walk walk;
173*4882a593Smuzhiyun struct aegis_state state;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun ops->skcipher_walk_init(&walk, req, true);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun kernel_fpu_begin();
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun crypto_aegis128_aesni_init(&state, ctx->key.bytes, req->iv);
180*4882a593Smuzhiyun crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen);
181*4882a593Smuzhiyun crypto_aegis128_aesni_process_crypt(&state, &walk, ops);
182*4882a593Smuzhiyun crypto_aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun kernel_fpu_end();
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
crypto_aegis128_aesni_encrypt(struct aead_request * req)187*4882a593Smuzhiyun static int crypto_aegis128_aesni_encrypt(struct aead_request *req)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun static const struct aegis_crypt_ops OPS = {
190*4882a593Smuzhiyun .skcipher_walk_init = skcipher_walk_aead_encrypt,
191*4882a593Smuzhiyun .crypt_blocks = crypto_aegis128_aesni_enc,
192*4882a593Smuzhiyun .crypt_tail = crypto_aegis128_aesni_enc_tail,
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun struct crypto_aead *tfm = crypto_aead_reqtfm(req);
196*4882a593Smuzhiyun struct aegis_block tag = {};
197*4882a593Smuzhiyun unsigned int authsize = crypto_aead_authsize(tfm);
198*4882a593Smuzhiyun unsigned int cryptlen = req->cryptlen;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun scatterwalk_map_and_copy(tag.bytes, req->dst,
203*4882a593Smuzhiyun req->assoclen + cryptlen, authsize, 1);
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
crypto_aegis128_aesni_decrypt(struct aead_request * req)207*4882a593Smuzhiyun static int crypto_aegis128_aesni_decrypt(struct aead_request *req)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun static const struct aegis_block zeros = {};
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun static const struct aegis_crypt_ops OPS = {
212*4882a593Smuzhiyun .skcipher_walk_init = skcipher_walk_aead_decrypt,
213*4882a593Smuzhiyun .crypt_blocks = crypto_aegis128_aesni_dec,
214*4882a593Smuzhiyun .crypt_tail = crypto_aegis128_aesni_dec_tail,
215*4882a593Smuzhiyun };
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun struct crypto_aead *tfm = crypto_aead_reqtfm(req);
218*4882a593Smuzhiyun struct aegis_block tag;
219*4882a593Smuzhiyun unsigned int authsize = crypto_aead_authsize(tfm);
220*4882a593Smuzhiyun unsigned int cryptlen = req->cryptlen - authsize;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun scatterwalk_map_and_copy(tag.bytes, req->src,
223*4882a593Smuzhiyun req->assoclen + cryptlen, authsize, 0);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
crypto_aegis128_aesni_init_tfm(struct crypto_aead * aead)230*4882a593Smuzhiyun static int crypto_aegis128_aesni_init_tfm(struct crypto_aead *aead)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
crypto_aegis128_aesni_exit_tfm(struct crypto_aead * aead)235*4882a593Smuzhiyun static void crypto_aegis128_aesni_exit_tfm(struct crypto_aead *aead)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun static struct aead_alg crypto_aegis128_aesni_alg = {
240*4882a593Smuzhiyun .setkey = crypto_aegis128_aesni_setkey,
241*4882a593Smuzhiyun .setauthsize = crypto_aegis128_aesni_setauthsize,
242*4882a593Smuzhiyun .encrypt = crypto_aegis128_aesni_encrypt,
243*4882a593Smuzhiyun .decrypt = crypto_aegis128_aesni_decrypt,
244*4882a593Smuzhiyun .init = crypto_aegis128_aesni_init_tfm,
245*4882a593Smuzhiyun .exit = crypto_aegis128_aesni_exit_tfm,
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun .ivsize = AEGIS128_NONCE_SIZE,
248*4882a593Smuzhiyun .maxauthsize = AEGIS128_MAX_AUTH_SIZE,
249*4882a593Smuzhiyun .chunksize = AEGIS128_BLOCK_SIZE,
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun .base = {
252*4882a593Smuzhiyun .cra_flags = CRYPTO_ALG_INTERNAL,
253*4882a593Smuzhiyun .cra_blocksize = 1,
254*4882a593Smuzhiyun .cra_ctxsize = sizeof(struct aegis_ctx) +
255*4882a593Smuzhiyun __alignof__(struct aegis_ctx),
256*4882a593Smuzhiyun .cra_alignmask = 0,
257*4882a593Smuzhiyun .cra_priority = 400,
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun .cra_name = "__aegis128",
260*4882a593Smuzhiyun .cra_driver_name = "__aegis128-aesni",
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun .cra_module = THIS_MODULE,
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun static struct simd_aead_alg *simd_alg;
267*4882a593Smuzhiyun
crypto_aegis128_aesni_module_init(void)268*4882a593Smuzhiyun static int __init crypto_aegis128_aesni_module_init(void)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun if (!boot_cpu_has(X86_FEATURE_XMM2) ||
271*4882a593Smuzhiyun !boot_cpu_has(X86_FEATURE_AES) ||
272*4882a593Smuzhiyun !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL))
273*4882a593Smuzhiyun return -ENODEV;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun return simd_register_aeads_compat(&crypto_aegis128_aesni_alg, 1,
276*4882a593Smuzhiyun &simd_alg);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
crypto_aegis128_aesni_module_exit(void)279*4882a593Smuzhiyun static void __exit crypto_aegis128_aesni_module_exit(void)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun simd_unregister_aeads(&crypto_aegis128_aesni_alg, 1, &simd_alg);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun module_init(crypto_aegis128_aesni_module_init);
285*4882a593Smuzhiyun module_exit(crypto_aegis128_aesni_module_exit);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun MODULE_LICENSE("GPL");
288*4882a593Smuzhiyun MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
289*4882a593Smuzhiyun MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE2 implementation");
290*4882a593Smuzhiyun MODULE_ALIAS_CRYPTO("aegis128");
291*4882a593Smuzhiyun MODULE_ALIAS_CRYPTO("aegis128-aesni");
292