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/internal/aead.h>
15 #include <crypto/internal/skcipher.h>
16 #include <crypto/morus640_glue.h>
17 #include <crypto/scatterwalk.h>
18 #include <linux/err.h>
19 #include <linux/init.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/scatterlist.h>
23 #include <asm/fpu/api.h>
25 struct morus640_state
{
26 struct morus640_block s
[MORUS_STATE_BLOCKS
];
30 int (*skcipher_walk_init
)(struct skcipher_walk
*walk
,
31 struct aead_request
*req
, bool atomic
);
33 void (*crypt_blocks
)(void *state
, const void *src
, void *dst
,
35 void (*crypt_tail
)(void *state
, const void *src
, void *dst
,
39 static void crypto_morus640_glue_process_ad(
40 struct morus640_state
*state
,
41 const struct morus640_glue_ops
*ops
,
42 struct scatterlist
*sg_src
, unsigned int assoclen
)
44 struct scatter_walk walk
;
45 struct morus640_block buf
;
48 scatterwalk_start(&walk
, sg_src
);
49 while (assoclen
!= 0) {
50 unsigned int size
= scatterwalk_clamp(&walk
, assoclen
);
51 unsigned int left
= size
;
52 void *mapped
= scatterwalk_map(&walk
);
53 const u8
*src
= (const u8
*)mapped
;
55 if (pos
+ size
>= MORUS640_BLOCK_SIZE
) {
57 unsigned int fill
= MORUS640_BLOCK_SIZE
- pos
;
58 memcpy(buf
.bytes
+ pos
, src
, fill
);
59 ops
->ad(state
, buf
.bytes
, MORUS640_BLOCK_SIZE
);
65 ops
->ad(state
, src
, left
);
66 src
+= left
& ~(MORUS640_BLOCK_SIZE
- 1);
67 left
&= MORUS640_BLOCK_SIZE
- 1;
70 memcpy(buf
.bytes
+ pos
, src
, left
);
74 scatterwalk_unmap(mapped
);
75 scatterwalk_advance(&walk
, size
);
76 scatterwalk_done(&walk
, 0, assoclen
);
80 memset(buf
.bytes
+ pos
, 0, MORUS640_BLOCK_SIZE
- pos
);
81 ops
->ad(state
, buf
.bytes
, MORUS640_BLOCK_SIZE
);
85 static void crypto_morus640_glue_process_crypt(struct morus640_state
*state
,
86 struct morus640_ops ops
,
87 struct skcipher_walk
*walk
)
89 while (walk
->nbytes
>= MORUS640_BLOCK_SIZE
) {
90 ops
.crypt_blocks(state
, walk
->src
.virt
.addr
,
92 round_down(walk
->nbytes
, MORUS640_BLOCK_SIZE
));
93 skcipher_walk_done(walk
, walk
->nbytes
% MORUS640_BLOCK_SIZE
);
97 ops
.crypt_tail(state
, walk
->src
.virt
.addr
, walk
->dst
.virt
.addr
,
99 skcipher_walk_done(walk
, 0);
103 int crypto_morus640_glue_setkey(struct crypto_aead
*aead
, const u8
*key
,
106 struct morus640_ctx
*ctx
= crypto_aead_ctx(aead
);
108 if (keylen
!= MORUS640_BLOCK_SIZE
) {
109 crypto_aead_set_flags(aead
, CRYPTO_TFM_RES_BAD_KEY_LEN
);
113 memcpy(ctx
->key
.bytes
, key
, MORUS640_BLOCK_SIZE
);
116 EXPORT_SYMBOL_GPL(crypto_morus640_glue_setkey
);
118 int crypto_morus640_glue_setauthsize(struct crypto_aead
*tfm
,
119 unsigned int authsize
)
121 return (authsize
<= MORUS_MAX_AUTH_SIZE
) ? 0 : -EINVAL
;
123 EXPORT_SYMBOL_GPL(crypto_morus640_glue_setauthsize
);
125 static void crypto_morus640_glue_crypt(struct aead_request
*req
,
126 struct morus640_ops ops
,
127 unsigned int cryptlen
,
128 struct morus640_block
*tag_xor
)
130 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
131 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
132 struct morus640_state state
;
133 struct skcipher_walk walk
;
135 ops
.skcipher_walk_init(&walk
, req
, true);
139 ctx
->ops
->init(&state
, &ctx
->key
, req
->iv
);
140 crypto_morus640_glue_process_ad(&state
, ctx
->ops
, req
->src
, req
->assoclen
);
141 crypto_morus640_glue_process_crypt(&state
, ops
, &walk
);
142 ctx
->ops
->final(&state
, tag_xor
, req
->assoclen
, cryptlen
);
147 int crypto_morus640_glue_encrypt(struct aead_request
*req
)
149 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
150 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
151 struct morus640_ops OPS
= {
152 .skcipher_walk_init
= skcipher_walk_aead_encrypt
,
153 .crypt_blocks
= ctx
->ops
->enc
,
154 .crypt_tail
= ctx
->ops
->enc_tail
,
157 struct morus640_block tag
= {};
158 unsigned int authsize
= crypto_aead_authsize(tfm
);
159 unsigned int cryptlen
= req
->cryptlen
;
161 crypto_morus640_glue_crypt(req
, OPS
, cryptlen
, &tag
);
163 scatterwalk_map_and_copy(tag
.bytes
, req
->dst
,
164 req
->assoclen
+ cryptlen
, authsize
, 1);
167 EXPORT_SYMBOL_GPL(crypto_morus640_glue_encrypt
);
169 int crypto_morus640_glue_decrypt(struct aead_request
*req
)
171 static const u8 zeros
[MORUS640_BLOCK_SIZE
] = {};
173 struct crypto_aead
*tfm
= crypto_aead_reqtfm(req
);
174 struct morus640_ctx
*ctx
= crypto_aead_ctx(tfm
);
175 struct morus640_ops OPS
= {
176 .skcipher_walk_init
= skcipher_walk_aead_decrypt
,
177 .crypt_blocks
= ctx
->ops
->dec
,
178 .crypt_tail
= ctx
->ops
->dec_tail
,
181 struct morus640_block tag
;
182 unsigned int authsize
= crypto_aead_authsize(tfm
);
183 unsigned int cryptlen
= req
->cryptlen
- authsize
;
185 scatterwalk_map_and_copy(tag
.bytes
, req
->src
,
186 req
->assoclen
+ cryptlen
, authsize
, 0);
188 crypto_morus640_glue_crypt(req
, OPS
, cryptlen
, &tag
);
190 return crypto_memneq(tag
.bytes
, zeros
, authsize
) ? -EBADMSG
: 0;
192 EXPORT_SYMBOL_GPL(crypto_morus640_glue_decrypt
);
194 void crypto_morus640_glue_init_ops(struct crypto_aead
*aead
,
195 const struct morus640_glue_ops
*ops
)
197 struct morus640_ctx
*ctx
= crypto_aead_ctx(aead
);
200 EXPORT_SYMBOL_GPL(crypto_morus640_glue_init_ops
);
202 MODULE_LICENSE("GPL");
203 MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
204 MODULE_DESCRIPTION("MORUS-640 AEAD mode -- glue for x86 optimizations");