Merge branch 'pm-cpufreq'
[linux-2.6-microblaze.git] / crypto / aegis128-core.c
index 44fb495..89dc1c5 100644 (file)
@@ -67,9 +67,11 @@ 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);
+int crypto_aegis128_final_simd(struct aegis_state *state,
+                              union aegis_block *tag_xor,
+                              unsigned int assoclen,
+                              unsigned int cryptlen,
+                              unsigned int authsize);
 
 static void crypto_aegis128_update(struct aegis_state *state)
 {
@@ -84,9 +86,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 +98,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 +130,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 +159,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 +183,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 +199,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 +218,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 +244,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 +260,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 +282,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 +290,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 +308,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 +330,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 +372,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 +400,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 +411,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 +437,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;
 
-       .ivsize = AEGIS128_NONCE_SIZE,
-       .maxauthsize = AEGIS128_MAX_AUTH_SIZE,
-       .chunksize = AEGIS_BLOCK_SIZE,
+       if (!aegis128_do_simd())
+               return crypto_aegis128_encrypt_generic(req);
 
-       .base = {
-               .cra_blocksize = 1,
-               .cra_ctxsize = sizeof(struct aegis_ctx),
-               .cra_alignmask = 0,
+       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);
 
-               .cra_priority = 100,
+       scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen,
+                                authsize, 1);
+       return 0;
+}
 
-               .cra_name = "aegis128",
-               .cra_driver_name = "aegis128-generic",
+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;
+
+       if (!aegis128_do_simd())
+               return crypto_aegis128_decrypt_generic(req);
+
+       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 +593,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");