aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/aegis128-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/aegis128-core.c')
-rw-r--r--crypto/aegis128-core.c250
1 files changed, 165 insertions, 85 deletions
diff --git a/crypto/aegis128-core.c b/crypto/aegis128-core.c
index 44fb4956f0dd..c4f1bfa1d04f 100644
--- a/crypto/aegis128-core.c
+++ b/crypto/aegis128-core.c
@@ -58,19 +58,6 @@ static bool aegis128_do_simd(void)
return false;
}
-bool crypto_aegis128_have_simd(void);
-void crypto_aegis128_update_simd(struct aegis_state *state, const void *msg);
-void crypto_aegis128_init_simd(struct aegis_state *state,
- const union aegis_block *key,
- const u8 *iv);
-void crypto_aegis128_encrypt_chunk_simd(struct aegis_state *state, u8 *dst,
- const u8 *src, unsigned int size);
-void crypto_aegis128_decrypt_chunk_simd(struct aegis_state *state, u8 *dst,
- const u8 *src, unsigned int size);
-void crypto_aegis128_final_simd(struct aegis_state *state,
- union aegis_block *tag_xor,
- u64 assoclen, u64 cryptlen);
-
static void crypto_aegis128_update(struct aegis_state *state)
{
union aegis_block tmp;
@@ -84,9 +71,10 @@ static void crypto_aegis128_update(struct aegis_state *state)
}
static void crypto_aegis128_update_a(struct aegis_state *state,
- const union aegis_block *msg)
+ const union aegis_block *msg,
+ bool do_simd)
{
- if (aegis128_do_simd()) {
+ if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && do_simd) {
crypto_aegis128_update_simd(state, msg);
return;
}
@@ -95,9 +83,10 @@ static void crypto_aegis128_update_a(struct aegis_state *state,
crypto_aegis_block_xor(&state->blocks[0], msg);
}
-static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg)
+static void crypto_aegis128_update_u(struct aegis_state *state, const void *msg,
+ bool do_simd)
{
- if (aegis128_do_simd()) {
+ if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) && do_simd) {
crypto_aegis128_update_simd(state, msg);
return;
}
@@ -126,27 +115,28 @@ static void crypto_aegis128_init(struct aegis_state *state,
crypto_aegis_block_xor(&state->blocks[4], &crypto_aegis_const[1]);
for (i = 0; i < 5; i++) {
- crypto_aegis128_update_a(state, key);
- crypto_aegis128_update_a(state, &key_iv);
+ crypto_aegis128_update_a(state, key, false);
+ crypto_aegis128_update_a(state, &key_iv, false);
}
}
static void crypto_aegis128_ad(struct aegis_state *state,
- const u8 *src, unsigned int size)
+ const u8 *src, unsigned int size,
+ bool do_simd)
{
if (AEGIS_ALIGNED(src)) {
const union aegis_block *src_blk =
(const union aegis_block *)src;
while (size >= AEGIS_BLOCK_SIZE) {
- crypto_aegis128_update_a(state, src_blk);
+ crypto_aegis128_update_a(state, src_blk, do_simd);
size -= AEGIS_BLOCK_SIZE;
src_blk++;
}
} else {
while (size >= AEGIS_BLOCK_SIZE) {
- crypto_aegis128_update_u(state, src);
+ crypto_aegis128_update_u(state, src, do_simd);
size -= AEGIS_BLOCK_SIZE;
src += AEGIS_BLOCK_SIZE;
@@ -154,6 +144,12 @@ static void crypto_aegis128_ad(struct aegis_state *state,
}
}
+static void crypto_aegis128_wipe_chunk(struct aegis_state *state, u8 *dst,
+ const u8 *src, unsigned int size)
+{
+ memzero_explicit(dst, size);
+}
+
static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst,
const u8 *src, unsigned int size)
{
@@ -172,7 +168,7 @@ static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst,
crypto_aegis_block_xor(&tmp, &state->blocks[1]);
crypto_aegis_block_xor(&tmp, src_blk);
- crypto_aegis128_update_a(state, src_blk);
+ crypto_aegis128_update_a(state, src_blk, false);
*dst_blk = tmp;
@@ -188,7 +184,7 @@ static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst,
crypto_aegis_block_xor(&tmp, &state->blocks[1]);
crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE);
- crypto_aegis128_update_u(state, src);
+ crypto_aegis128_update_u(state, src, false);
memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE);
@@ -207,7 +203,7 @@ static void crypto_aegis128_encrypt_chunk(struct aegis_state *state, u8 *dst,
crypto_aegis_block_xor(&tmp, &state->blocks[4]);
crypto_aegis_block_xor(&tmp, &state->blocks[1]);
- crypto_aegis128_update_a(state, &msg);
+ crypto_aegis128_update_a(state, &msg, false);
crypto_aegis_block_xor(&msg, &tmp);
@@ -233,7 +229,7 @@ static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst,
crypto_aegis_block_xor(&tmp, &state->blocks[1]);
crypto_aegis_block_xor(&tmp, src_blk);
- crypto_aegis128_update_a(state, &tmp);
+ crypto_aegis128_update_a(state, &tmp, false);
*dst_blk = tmp;
@@ -249,7 +245,7 @@ static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst,
crypto_aegis_block_xor(&tmp, &state->blocks[1]);
crypto_xor(tmp.bytes, src, AEGIS_BLOCK_SIZE);
- crypto_aegis128_update_a(state, &tmp);
+ crypto_aegis128_update_a(state, &tmp, false);
memcpy(dst, tmp.bytes, AEGIS_BLOCK_SIZE);
@@ -271,7 +267,7 @@ static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst,
memset(msg.bytes + size, 0, AEGIS_BLOCK_SIZE - size);
- crypto_aegis128_update_a(state, &msg);
+ crypto_aegis128_update_a(state, &msg, false);
memcpy(dst, msg.bytes, size);
}
@@ -279,7 +275,8 @@ static void crypto_aegis128_decrypt_chunk(struct aegis_state *state, u8 *dst,
static void crypto_aegis128_process_ad(struct aegis_state *state,
struct scatterlist *sg_src,
- unsigned int assoclen)
+ unsigned int assoclen,
+ bool do_simd)
{
struct scatter_walk walk;
union aegis_block buf;
@@ -296,13 +293,13 @@ static void crypto_aegis128_process_ad(struct aegis_state *state,
if (pos > 0) {
unsigned int fill = AEGIS_BLOCK_SIZE - pos;
memcpy(buf.bytes + pos, src, fill);
- crypto_aegis128_update_a(state, &buf);
+ crypto_aegis128_update_a(state, &buf, do_simd);
pos = 0;
left -= fill;
src += fill;
}
- crypto_aegis128_ad(state, src, left);
+ crypto_aegis128_ad(state, src, left, do_simd);
src += left & ~(AEGIS_BLOCK_SIZE - 1);
left &= AEGIS_BLOCK_SIZE - 1;
}
@@ -318,13 +315,12 @@ static void crypto_aegis128_process_ad(struct aegis_state *state,
if (pos > 0) {
memset(buf.bytes + pos, 0, AEGIS_BLOCK_SIZE - pos);
- crypto_aegis128_update_a(state, &buf);
+ crypto_aegis128_update_a(state, &buf, do_simd);
}
}
static __always_inline
int crypto_aegis128_process_crypt(struct aegis_state *state,
- struct aead_request *req,
struct skcipher_walk *walk,
void (*crypt)(struct aegis_state *state,
u8 *dst, const u8 *src,
@@ -361,7 +357,7 @@ static void crypto_aegis128_final(struct aegis_state *state,
crypto_aegis_block_xor(&tmp, &state->blocks[3]);
for (i = 0; i < 7; i++)
- crypto_aegis128_update_a(state, &tmp);
+ crypto_aegis128_update_a(state, &tmp, false);
for (i = 0; i < AEGIS128_STATE_BLOCKS; i++)
crypto_aegis_block_xor(tag_xor, &state->blocks[i]);
@@ -389,7 +385,7 @@ static int crypto_aegis128_setauthsize(struct crypto_aead *tfm,
return 0;
}
-static int crypto_aegis128_encrypt(struct aead_request *req)
+static int crypto_aegis128_encrypt_generic(struct aead_request *req)
{
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
union aegis_block tag = {};
@@ -400,27 +396,18 @@ static int crypto_aegis128_encrypt(struct aead_request *req)
struct aegis_state state;
skcipher_walk_aead_encrypt(&walk, req, false);
- if (aegis128_do_simd()) {
- crypto_aegis128_init_simd(&state, &ctx->key, req->iv);
- crypto_aegis128_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_process_crypt(&state, req, &walk,
- crypto_aegis128_encrypt_chunk_simd);
- crypto_aegis128_final_simd(&state, &tag, req->assoclen,
- cryptlen);
- } else {
- crypto_aegis128_init(&state, &ctx->key, req->iv);
- crypto_aegis128_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_process_crypt(&state, req, &walk,
- crypto_aegis128_encrypt_chunk);
- crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen);
- }
+ crypto_aegis128_init(&state, &ctx->key, req->iv);
+ crypto_aegis128_process_ad(&state, req->src, req->assoclen, false);
+ crypto_aegis128_process_crypt(&state, &walk,
+ crypto_aegis128_encrypt_chunk);
+ crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen);
scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen,
authsize, 1);
return 0;
}
-static int crypto_aegis128_decrypt(struct aead_request *req)
+static int crypto_aegis128_decrypt_generic(struct aead_request *req)
{
static const u8 zeros[AEGIS128_MAX_AUTH_SIZE] = {};
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
@@ -435,60 +422,152 @@ static int crypto_aegis128_decrypt(struct aead_request *req)
authsize, 0);
skcipher_walk_aead_decrypt(&walk, req, false);
- if (aegis128_do_simd()) {
- crypto_aegis128_init_simd(&state, &ctx->key, req->iv);
- crypto_aegis128_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_process_crypt(&state, req, &walk,
- crypto_aegis128_decrypt_chunk_simd);
- crypto_aegis128_final_simd(&state, &tag, req->assoclen,
- cryptlen);
- } else {
- crypto_aegis128_init(&state, &ctx->key, req->iv);
- crypto_aegis128_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_process_crypt(&state, req, &walk,
- crypto_aegis128_decrypt_chunk);
- crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen);
+ crypto_aegis128_init(&state, &ctx->key, req->iv);
+ crypto_aegis128_process_ad(&state, req->src, req->assoclen, false);
+ crypto_aegis128_process_crypt(&state, &walk,
+ crypto_aegis128_decrypt_chunk);
+ crypto_aegis128_final(&state, &tag, req->assoclen, cryptlen);
+
+ if (unlikely(crypto_memneq(tag.bytes, zeros, authsize))) {
+ /*
+ * From Chapter 4. 'Security Analysis' of the AEGIS spec [0]
+ *
+ * "3. If verification fails, the decrypted plaintext and the
+ * wrong authentication tag should not be given as output."
+ *
+ * [0] https://competitions.cr.yp.to/round3/aegisv11.pdf
+ */
+ skcipher_walk_aead_decrypt(&walk, req, false);
+ crypto_aegis128_process_crypt(NULL, &walk,
+ crypto_aegis128_wipe_chunk);
+ memzero_explicit(&tag, sizeof(tag));
+ return -EBADMSG;
}
-
- return crypto_memneq(tag.bytes, zeros, authsize) ? -EBADMSG : 0;
+ return 0;
}
-static struct aead_alg crypto_aegis128_alg = {
- .setkey = crypto_aegis128_setkey,
- .setauthsize = crypto_aegis128_setauthsize,
- .encrypt = crypto_aegis128_encrypt,
- .decrypt = crypto_aegis128_decrypt,
+static int crypto_aegis128_encrypt_simd(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ union aegis_block tag = {};
+ unsigned int authsize = crypto_aead_authsize(tfm);
+ struct aegis_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned int cryptlen = req->cryptlen;
+ struct skcipher_walk walk;
+ struct aegis_state state;
+
+ if (!aegis128_do_simd())
+ return crypto_aegis128_encrypt_generic(req);
+
+ skcipher_walk_aead_encrypt(&walk, req, false);
+ crypto_aegis128_init_simd(&state, &ctx->key, req->iv);
+ crypto_aegis128_process_ad(&state, req->src, req->assoclen, true);
+ crypto_aegis128_process_crypt(&state, &walk,
+ crypto_aegis128_encrypt_chunk_simd);
+ crypto_aegis128_final_simd(&state, &tag, req->assoclen, cryptlen, 0);
- .ivsize = AEGIS128_NONCE_SIZE,
- .maxauthsize = AEGIS128_MAX_AUTH_SIZE,
- .chunksize = AEGIS_BLOCK_SIZE,
+ scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen,
+ authsize, 1);
+ return 0;
+}
- .base = {
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct aegis_ctx),
- .cra_alignmask = 0,
+static int crypto_aegis128_decrypt_simd(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ union aegis_block tag;
+ unsigned int authsize = crypto_aead_authsize(tfm);
+ unsigned int cryptlen = req->cryptlen - authsize;
+ struct aegis_ctx *ctx = crypto_aead_ctx(tfm);
+ struct skcipher_walk walk;
+ struct aegis_state state;
- .cra_priority = 100,
+ if (!aegis128_do_simd())
+ return crypto_aegis128_decrypt_generic(req);
- .cra_name = "aegis128",
- .cra_driver_name = "aegis128-generic",
+ scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen,
+ authsize, 0);
- .cra_module = THIS_MODULE,
+ skcipher_walk_aead_decrypt(&walk, req, false);
+ crypto_aegis128_init_simd(&state, &ctx->key, req->iv);
+ crypto_aegis128_process_ad(&state, req->src, req->assoclen, true);
+ crypto_aegis128_process_crypt(&state, &walk,
+ crypto_aegis128_decrypt_chunk_simd);
+
+ if (unlikely(crypto_aegis128_final_simd(&state, &tag, req->assoclen,
+ cryptlen, authsize))) {
+ skcipher_walk_aead_decrypt(&walk, req, false);
+ crypto_aegis128_process_crypt(NULL, &walk,
+ crypto_aegis128_wipe_chunk);
+ return -EBADMSG;
}
+ return 0;
+}
+
+static struct aead_alg crypto_aegis128_alg_generic = {
+ .setkey = crypto_aegis128_setkey,
+ .setauthsize = crypto_aegis128_setauthsize,
+ .encrypt = crypto_aegis128_encrypt_generic,
+ .decrypt = crypto_aegis128_decrypt_generic,
+
+ .ivsize = AEGIS128_NONCE_SIZE,
+ .maxauthsize = AEGIS128_MAX_AUTH_SIZE,
+ .chunksize = AEGIS_BLOCK_SIZE,
+
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aegis_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_priority = 100,
+ .base.cra_name = "aegis128",
+ .base.cra_driver_name = "aegis128-generic",
+ .base.cra_module = THIS_MODULE,
+};
+
+static struct aead_alg crypto_aegis128_alg_simd = {
+ .setkey = crypto_aegis128_setkey,
+ .setauthsize = crypto_aegis128_setauthsize,
+ .encrypt = crypto_aegis128_encrypt_simd,
+ .decrypt = crypto_aegis128_decrypt_simd,
+
+ .ivsize = AEGIS128_NONCE_SIZE,
+ .maxauthsize = AEGIS128_MAX_AUTH_SIZE,
+ .chunksize = AEGIS_BLOCK_SIZE,
+
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aegis_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_priority = 200,
+ .base.cra_name = "aegis128",
+ .base.cra_driver_name = "aegis128-simd",
+ .base.cra_module = THIS_MODULE,
};
static int __init crypto_aegis128_module_init(void)
{
+ int ret;
+
+ ret = crypto_register_aead(&crypto_aegis128_alg_generic);
+ if (ret)
+ return ret;
+
if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) &&
- crypto_aegis128_have_simd())
+ crypto_aegis128_have_simd()) {
+ ret = crypto_register_aead(&crypto_aegis128_alg_simd);
+ if (ret) {
+ crypto_unregister_aead(&crypto_aegis128_alg_generic);
+ return ret;
+ }
static_branch_enable(&have_simd);
-
- return crypto_register_aead(&crypto_aegis128_alg);
+ }
+ return 0;
}
static void __exit crypto_aegis128_module_exit(void)
{
- crypto_unregister_aead(&crypto_aegis128_alg);
+ if (IS_ENABLED(CONFIG_CRYPTO_AEGIS128_SIMD) &&
+ crypto_aegis128_have_simd())
+ crypto_unregister_aead(&crypto_aegis128_alg_simd);
+
+ crypto_unregister_aead(&crypto_aegis128_alg_generic);
}
subsys_initcall(crypto_aegis128_module_init);
@@ -499,3 +578,4 @@ MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm");
MODULE_ALIAS_CRYPTO("aegis128");
MODULE_ALIAS_CRYPTO("aegis128-generic");
+MODULE_ALIAS_CRYPTO("aegis128-simd");