2 * The MORUS-640 Authenticated-Encryption Algorithm
3 * Common x86 SIMD glue skeleton
5 * Copyright (c) 2016-2018 Ondrej Mosnacek <omosnacek@gmail.com>
6 * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
14 #include <crypto/cryptd.h>
15 #include <crypto/internal/aead.h>
16 #include <crypto/internal/skcipher.h>
17 #include <crypto/morus640_glue.h>
18 #include <crypto/scatterwalk.h>
19 #include <linux/err.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/scatterlist.h>
24 #include <asm/fpu/api.h>
26 struct morus640_state
{
27 struct morus640_block s
[MORUS_STATE_BLOCKS
];
31 int (*skcipher_walk_init
)(struct skcipher_walk
*walk
,
32 struct aead_request
*req
, bool atomic
);
34 void (*crypt_blocks
)(void *state
, const void *src
, void *dst
,
36 void (*crypt_tail
)(void *state
, const void *src
, void *dst
,
40 static void crypto_morus640_glue_process_ad(
41 struct morus640_state
*state
,
42 const struct morus640_glue_ops
*ops
,
43 struct scatterlist
*sg_src
, unsigned int assoclen
)
45 struct scatter_walk walk
;
46 struct morus640_block buf
;
49 scatterwalk_start(&walk
, sg_src
);
50 while (assoclen
!= 0) {
51 unsigned int size
= scatterwalk_clamp(&walk
, assoclen
);
52 unsigned int left
= size
;
53 void *mapped
= scatterwalk_map(&walk
);
54 const u8
*src
= (const u8
*)mapped
;
56 if (pos
+ size
>= MORUS640_BLOCK_SIZE
) {
58 unsigned int fill
= MORUS640_BLOCK_SIZE
- pos
;
59 memcpy(buf
.bytes
+ pos
, src
, fill
);
60 ops
->ad(state
, buf
.bytes
, MORUS640_BLOCK_SIZE
);
66 ops
->ad(state
, src
, left
);
67 src
+= left
& ~(MORUS640_BLOCK_SIZE
- 1);
68 left
&= MORUS640_BLOCK_SIZE
- 1;
71 memcpy(buf
.bytes
+ pos
, src
, left
);
75 scatterwalk_unmap(mapped
);
76 scatterwalk_advance(&walk
, size
);
77 scatterwalk_done(&walk
, 0, assoclen
);
81 memset(buf
.bytes
+ pos
, 0, MORUS640_BLOCK_SIZE
- pos
);
82 ops
->ad(state
, buf
.bytes
, MORUS640_BLOCK_SIZE
);
86 static void crypto_morus640_glue_process_crypt(struct morus640_state
*state
,
87 struct morus640_ops ops
,
88 struct skcipher_walk
*walk
)
90 while (walk
->nbytes
>= MORUS640_BLOCK_SIZE
) {
91 ops
.crypt_blocks(state
, walk
->src
.virt
.addr
,
93 round_down(walk
->nbytes
, MORUS640_BLOCK_SIZE
));
94 skcipher_walk_done(walk
, walk
->nbytes
% MORUS640_BLOCK_SIZE
);
98 ops
.crypt_tail(state
, walk
->src
.virt
.addr
, walk
->dst
.virt
.addr
,
100 skcipher_walk_done(walk
, 0);
104 int crypto_morus640_glue_setkey(struct crypto_aead
*aead
, const u8
*key
,
107 struct morus640_ctx
*ctx
= crypto_aead_ctx(aead
);
109 if (keylen
!= MORUS640_BLOCK_SIZE
) {
110 crypto_aead_set_flags(aead
, CRYPTO_TFM_RES_BAD_KEY_LEN
);
114 memcpy(ctx
->key
.bytes
, key
, MORUS640_BLOCK_SIZE
);
117 EXPORT_SYMBOL_GPL(crypto_morus640_glue_setkey
);
119 int crypto_morus640_glue_setauthsize(struct crypto_aead
*tfm
,
120 unsigned int authsize
)
122 return (authsize
<= MORUS_MAX_AUTH_SIZE
) ? 0 : -EINVAL
;
124 EXPORT_SYMBOL_GPL(crypto_morus640_glue_setauthsize
);
126 static void crypto_morus640_glue_crypt(struct aead_request
*req
,
127 struct morus640_ops ops
,
128 unsigned int cryptlen
,
129 struct morus640_block
*tag_xor
)
131 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
132 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
133 struct morus640_state state
;
134 struct skcipher_walk walk
;
136 ops
.skcipher_walk_init(&walk
, req
, true);
140 ctx
->ops
->init(&state
, &ctx
->key
, req
->iv
);
141 crypto_morus640_glue_process_ad(&state
, ctx
->ops
, req
->src
, req
->assoclen
);
142 crypto_morus640_glue_process_crypt(&state
, ops
, &walk
);
143 ctx
->ops
->final(&state
, tag_xor
, req
->assoclen
, cryptlen
);
148 int crypto_morus640_glue_encrypt(struct aead_request
*req
)
150 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
151 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
152 struct morus640_ops OPS
= {
153 .skcipher_walk_init
= skcipher_walk_aead_encrypt
,
154 .crypt_blocks
= ctx
->ops
->enc
,
155 .crypt_tail
= ctx
->ops
->enc_tail
,
158 struct morus640_block tag
= {};
159 unsigned int authsize
= crypto_aead_authsize(tfm
);
160 unsigned int cryptlen
= req
->cryptlen
;
162 crypto_morus640_glue_crypt(req
, OPS
, cryptlen
, &tag
);
164 scatterwalk_map_and_copy(tag
.bytes
, req
->dst
,
165 req
->assoclen
+ cryptlen
, authsize
, 1);
168 EXPORT_SYMBOL_GPL(crypto_morus640_glue_encrypt
);
170 int crypto_morus640_glue_decrypt(struct aead_request
*req
)
172 static const u8 zeros
[MORUS640_BLOCK_SIZE
] = {};
174 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
175 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
176 struct morus640_ops OPS
= {
177 .skcipher_walk_init
= skcipher_walk_aead_decrypt
,
178 .crypt_blocks
= ctx
->ops
->dec
,
179 .crypt_tail
= ctx
->ops
->dec_tail
,
182 struct morus640_block tag
;
183 unsigned int authsize
= crypto_aead_authsize(tfm
);
184 unsigned int cryptlen
= req
->cryptlen
- authsize
;
186 scatterwalk_map_and_copy(tag
.bytes
, req
->src
,
187 req
->assoclen
+ cryptlen
, authsize
, 0);
189 crypto_morus640_glue_crypt(req
, OPS
, cryptlen
, &tag
);
191 return crypto_memneq(tag
.bytes
, zeros
, authsize
) ? -EBADMSG
: 0;
193 EXPORT_SYMBOL_GPL(crypto_morus640_glue_decrypt
);
195 void crypto_morus640_glue_init_ops(struct crypto_aead
*aead
,
196 const struct morus640_glue_ops
*ops
)
198 struct morus640_ctx
*ctx
= crypto_aead_ctx(aead
);
201 EXPORT_SYMBOL_GPL(crypto_morus640_glue_init_ops
);
203 int cryptd_morus640_glue_setkey(struct crypto_aead
*aead
, const u8
*key
,
206 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
207 struct cryptd_aead
*cryptd_tfm
= *ctx
;
209 return crypto_aead_setkey(&cryptd_tfm
->base
, key
, keylen
);
211 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_setkey
);
213 int cryptd_morus640_glue_setauthsize(struct crypto_aead
*aead
,
214 unsigned int authsize
)
216 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
217 struct cryptd_aead
*cryptd_tfm
= *ctx
;
219 return crypto_aead_setauthsize(&cryptd_tfm
->base
, authsize
);
221 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_setauthsize
);
223 int cryptd_morus640_glue_encrypt(struct aead_request
*req
)
225 struct crypto_aead
*aead
= crypto_aead_reqtfm(req
);
226 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
227 struct cryptd_aead
*cryptd_tfm
= *ctx
;
229 aead
= &cryptd_tfm
->base
;
230 if (irq_fpu_usable() && (!in_atomic() ||
231 !cryptd_aead_queued(cryptd_tfm
)))
232 aead
= cryptd_aead_child(cryptd_tfm
);
234 aead_request_set_tfm(req
, aead
);
236 return crypto_aead_encrypt(req
);
238 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_encrypt
);
240 int cryptd_morus640_glue_decrypt(struct aead_request
*req
)
242 struct crypto_aead
*aead
= crypto_aead_reqtfm(req
);
243 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
244 struct cryptd_aead
*cryptd_tfm
= *ctx
;
246 aead
= &cryptd_tfm
->base
;
247 if (irq_fpu_usable() && (!in_atomic() ||
248 !cryptd_aead_queued(cryptd_tfm
)))
249 aead
= cryptd_aead_child(cryptd_tfm
);
251 aead_request_set_tfm(req
, aead
);
253 return crypto_aead_decrypt(req
);
255 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_decrypt
);
257 int cryptd_morus640_glue_init_tfm(struct crypto_aead
*aead
)
259 struct cryptd_aead
*cryptd_tfm
;
260 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
261 const char *name
= crypto_aead_alg(aead
)->base
.cra_driver_name
;
262 char internal_name
[CRYPTO_MAX_ALG_NAME
];
264 if (snprintf(internal_name
, CRYPTO_MAX_ALG_NAME
, "__%s", name
)
265 >= CRYPTO_MAX_ALG_NAME
)
266 return -ENAMETOOLONG
;
268 cryptd_tfm
= cryptd_alloc_aead(internal_name
, CRYPTO_ALG_INTERNAL
,
269 CRYPTO_ALG_INTERNAL
);
270 if (IS_ERR(cryptd_tfm
))
271 return PTR_ERR(cryptd_tfm
);
274 crypto_aead_set_reqsize(aead
, crypto_aead_reqsize(&cryptd_tfm
->base
));
277 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_init_tfm
);
279 void cryptd_morus640_glue_exit_tfm(struct crypto_aead
*aead
)
281 struct cryptd_aead
**ctx
= crypto_aead_ctx(aead
);
283 cryptd_free_aead(*ctx
);
285 EXPORT_SYMBOL_GPL(cryptd_morus640_glue_exit_tfm
);
287 MODULE_LICENSE("GPL");
288 MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
289 MODULE_DESCRIPTION("MORUS-640 AEAD mode -- glue for x86 optimizations");