crypto: xcbc - Use API partial block handling
authorHerbert Xu <herbert@gondor.apana.org.au>
Fri, 18 Apr 2025 03:01:04 +0000 (11:01 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 23 Apr 2025 07:52:47 +0000 (15:52 +0800)
Use the Crypto API partial block handling.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/xcbc.c

index fc785667b134d954f7bc5a579772574ec6152209..970ff581dc5894702684014c6710ac8cb04bdcf6 100644 (file)
@@ -8,9 +8,12 @@
 
 #include <crypto/internal/cipher.h>
 #include <crypto/internal/hash.h>
+#include <crypto/utils.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
 
 static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
                           0x02020202, 0x02020202, 0x02020202, 0x02020202,
@@ -30,22 +33,6 @@ struct xcbc_tfm_ctx {
        u8 consts[];
 };
 
-/*
- * +------------------------
- * | <shash desc>
- * +------------------------
- * | xcbc_desc_ctx
- * +------------------------
- * | odds (block size)
- * +------------------------
- * | prev (block size)
- * +------------------------
- */
-struct xcbc_desc_ctx {
-       unsigned int len;
-       u8 odds[];
-};
-
 #define XCBC_BLOCKSIZE 16
 
 static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
@@ -70,13 +57,10 @@ static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
 
 static int crypto_xcbc_digest_init(struct shash_desc *pdesc)
 {
-       struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
        int bs = crypto_shash_blocksize(pdesc->tfm);
-       u8 *prev = &ctx->odds[bs];
+       u8 *prev = shash_desc_ctx(pdesc);
 
-       ctx->len = 0;
        memset(prev, 0, bs);
-
        return 0;
 }
 
@@ -85,77 +69,36 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
 {
        struct crypto_shash *parent = pdesc->tfm;
        struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
-       struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
        struct crypto_cipher *tfm = tctx->child;
        int bs = crypto_shash_blocksize(parent);
-       u8 *odds = ctx->odds;
-       u8 *prev = odds + bs;
-
-       /* checking the data can fill the block */
-       if ((ctx->len + len) <= bs) {
-               memcpy(odds + ctx->len, p, len);
-               ctx->len += len;
-               return 0;
-       }
-
-       /* filling odds with new data and encrypting it */
-       memcpy(odds + ctx->len, p, bs - ctx->len);
-       len -= bs - ctx->len;
-       p += bs - ctx->len;
-
-       crypto_xor(prev, odds, bs);
-       crypto_cipher_encrypt_one(tfm, prev, prev);
+       u8 *prev = shash_desc_ctx(pdesc);
 
-       /* clearing the length */
-       ctx->len = 0;
-
-       /* encrypting the rest of data */
-       while (len > bs) {
+       do {
                crypto_xor(prev, p, bs);
                crypto_cipher_encrypt_one(tfm, prev, prev);
                p += bs;
                len -= bs;
-       }
-
-       /* keeping the surplus of blocksize */
-       if (len) {
-               memcpy(odds, p, len);
-               ctx->len = len;
-       }
-
-       return 0;
+       } while (len >= bs);
+       return len;
 }
 
-static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out)
+static int crypto_xcbc_digest_finup(struct shash_desc *pdesc, const u8 *src,
+                                   unsigned int len, u8 *out)
 {
        struct crypto_shash *parent = pdesc->tfm;
        struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
-       struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
        struct crypto_cipher *tfm = tctx->child;
        int bs = crypto_shash_blocksize(parent);
-       u8 *odds = ctx->odds;
-       u8 *prev = odds + bs;
+       u8 *prev = shash_desc_ctx(pdesc);
        unsigned int offset = 0;
 
-       if (ctx->len != bs) {
-               unsigned int rlen;
-               u8 *p = odds + ctx->len;
-
-               *p = 0x80;
-               p++;
-
-               rlen = bs - ctx->len -1;
-               if (rlen)
-                       memset(p, 0, rlen);
-
+       crypto_xor(prev, src, len);
+       if (len != bs) {
+               prev[len] ^= 0x80;
                offset += bs;
        }
-
-       crypto_xor(prev, odds, bs);
        crypto_xor(prev, &tctx->consts[offset], bs);
-
        crypto_cipher_encrypt_one(tfm, out, prev);
-
        return 0;
 }
 
@@ -216,17 +159,18 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
        inst->alg.base.cra_blocksize = alg->cra_blocksize;
        inst->alg.base.cra_ctxsize = sizeof(struct xcbc_tfm_ctx) +
                                     alg->cra_blocksize * 2;
+       inst->alg.base.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY |
+                                  CRYPTO_AHASH_ALG_FINAL_NONZERO;
 
        inst->alg.digestsize = alg->cra_blocksize;
-       inst->alg.descsize = sizeof(struct xcbc_desc_ctx) +
-                            alg->cra_blocksize * 2;
+       inst->alg.descsize = alg->cra_blocksize;
 
        inst->alg.base.cra_init = xcbc_init_tfm;
        inst->alg.base.cra_exit = xcbc_exit_tfm;
 
        inst->alg.init = crypto_xcbc_digest_init;
        inst->alg.update = crypto_xcbc_digest_update;
-       inst->alg.final = crypto_xcbc_digest_final;
+       inst->alg.finup = crypto_xcbc_digest_finup;
        inst->alg.setkey = crypto_xcbc_digest_setkey;
 
        inst->free = shash_free_singlespawn_instance;