]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library
authorEric Biggers <ebiggers@kernel.org>
Wed, 18 Feb 2026 21:34:48 +0000 (13:34 -0800)
committerEric Biggers <ebiggers@kernel.org>
Mon, 9 Mar 2026 20:27:20 +0000 (13:27 -0700)
Update the "aes" module to implement "cmac(aes)", "xcbc(aes)", and
"cbcmac(aes)" algorithms using the corresponding library functions, and
register these with the crypto_shash API.  Each algorithm is included
only if the corresponding existing kconfig option is enabled.

This allows the architecture-optimized implementations of these
algorithms to continue to be accessible via the crypto_shash API once
they are migrated into the library.

For "xcbc(aes)", I also fixed the bug where AES key lengths other than
128 bits were allowed, so that this bug didn't have to be implemented in
the library.  The AES-XCBC-MAC specification (RFC 3566) is clear that
key lengths other than 128 bits MUST NOT be supported.  AES-XCBC-MAC
derives a 128-bit subkey internally, so the nonstandard support for
longer AES keys didn't really work: AES-128 was still used internally.

In the unlikely event that someone is actually relying on the broken and
nonstandard support for longer AES-XCBC-MAC keys, we can fairly easily
reintroduce it.  But it seems unnecessary: the only user of "xcbc(aes)"
seems to be IPsec, which uses 128-bit keys with it.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20260218213501.136844-3-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
crypto/Kconfig
crypto/aes.c
crypto/testmgr.c
drivers/crypto/starfive/jh7110-aes.c

index b4bb85e8e226120946a50c1a9d648090ded0db6c..c977d40f906d360017a84a16d2bb9ff51b0373c1 100644 (file)
@@ -361,6 +361,8 @@ config CRYPTO_AES
        tristate "AES (Advanced Encryption Standard)"
        select CRYPTO_ALGAPI
        select CRYPTO_LIB_AES
+       select CRYPTO_LIB_AES_CBC_MACS if CRYPTO_CMAC || CRYPTO_XCBC || CRYPTO_CCM
+       select CRYPTO_HASH if CRYPTO_CMAC || CRYPTO_XCBC || CRYPTO_CCM
        help
          AES cipher algorithms (Rijndael)(FIPS-197, ISO/IEC 18033-3)
 
index ae8385df0ce51c749b775be11d414bfeadf22365..6bf23eb0503f11d260dec5bca29db8664aa941d4 100644 (file)
@@ -5,8 +5,10 @@
  * Copyright 2026 Google LLC
  */
 
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/aes.h>
 #include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
 #include <linux/module.h>
 
 static_assert(__alignof__(struct aes_key) <= CRYPTO_MINALIGN);
@@ -33,6 +35,98 @@ static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
        aes_decrypt(key, out, in);
 }
 
+static_assert(__alignof__(struct aes_cmac_key) <= CRYPTO_MINALIGN);
+#define AES_CMAC_KEY(tfm) ((struct aes_cmac_key *)crypto_shash_ctx(tfm))
+#define AES_CMAC_CTX(desc) ((struct aes_cmac_ctx *)shash_desc_ctx(desc))
+
+static int __maybe_unused crypto_aes_cmac_setkey(struct crypto_shash *tfm,
+                                                const u8 *in_key,
+                                                unsigned int key_len)
+{
+       return aes_cmac_preparekey(AES_CMAC_KEY(tfm), in_key, key_len);
+}
+
+static int __maybe_unused crypto_aes_xcbc_setkey(struct crypto_shash *tfm,
+                                                const u8 *in_key,
+                                                unsigned int key_len)
+{
+       if (key_len != AES_KEYSIZE_128)
+               return -EINVAL;
+       aes_xcbcmac_preparekey(AES_CMAC_KEY(tfm), in_key);
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_init(struct shash_desc *desc)
+{
+       aes_cmac_init(AES_CMAC_CTX(desc), AES_CMAC_KEY(desc->tfm));
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_update(struct shash_desc *desc,
+                                                const u8 *data,
+                                                unsigned int len)
+{
+       aes_cmac_update(AES_CMAC_CTX(desc), data, len);
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_final(struct shash_desc *desc,
+                                               u8 *out)
+{
+       aes_cmac_final(AES_CMAC_CTX(desc), out);
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_digest(struct shash_desc *desc,
+                                                const u8 *data,
+                                                unsigned int len, u8 *out)
+{
+       aes_cmac(AES_CMAC_KEY(desc->tfm), data, len, out);
+       return 0;
+}
+
+static_assert(__alignof__(struct aes_enckey) <= CRYPTO_MINALIGN);
+#define AES_CBCMAC_KEY(tfm) ((struct aes_enckey *)crypto_shash_ctx(tfm))
+#define AES_CBCMAC_CTX(desc) ((struct aes_cbcmac_ctx *)shash_desc_ctx(desc))
+
+static int __maybe_unused crypto_aes_cbcmac_setkey(struct crypto_shash *tfm,
+                                                  const u8 *in_key,
+                                                  unsigned int key_len)
+{
+       return aes_prepareenckey(AES_CBCMAC_KEY(tfm), in_key, key_len);
+}
+
+static int __maybe_unused crypto_aes_cbcmac_init(struct shash_desc *desc)
+{
+       aes_cbcmac_init(AES_CBCMAC_CTX(desc), AES_CBCMAC_KEY(desc->tfm));
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_update(struct shash_desc *desc,
+                                                  const u8 *data,
+                                                  unsigned int len)
+{
+       aes_cbcmac_update(AES_CBCMAC_CTX(desc), data, len);
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_final(struct shash_desc *desc,
+                                                 u8 *out)
+{
+       aes_cbcmac_final(AES_CBCMAC_CTX(desc), out);
+       return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_digest(struct shash_desc *desc,
+                                                  const u8 *data,
+                                                  unsigned int len, u8 *out)
+{
+       aes_cbcmac_init(AES_CBCMAC_CTX(desc), AES_CBCMAC_KEY(desc->tfm));
+       aes_cbcmac_update(AES_CBCMAC_CTX(desc), data, len);
+       aes_cbcmac_final(AES_CBCMAC_CTX(desc), out);
+       return 0;
+}
+
 static struct crypto_alg alg = {
        .cra_name = "aes",
        .cra_driver_name = "aes-lib",
@@ -48,19 +142,106 @@ static struct crypto_alg alg = {
                               .cia_decrypt = crypto_aes_decrypt } }
 };
 
+static struct shash_alg mac_algs[] = {
+#if IS_ENABLED(CONFIG_CRYPTO_CMAC)
+       {
+               .base.cra_name = "cmac(aes)",
+               .base.cra_driver_name = "cmac-aes-lib",
+               .base.cra_priority = 300,
+               .base.cra_blocksize = AES_BLOCK_SIZE,
+               .base.cra_ctxsize = sizeof(struct aes_cmac_key),
+               .base.cra_module = THIS_MODULE,
+               .digestsize = AES_BLOCK_SIZE,
+               .setkey = crypto_aes_cmac_setkey,
+               .init = crypto_aes_cmac_init,
+               .update = crypto_aes_cmac_update,
+               .final = crypto_aes_cmac_final,
+               .digest = crypto_aes_cmac_digest,
+               .descsize = sizeof(struct aes_cmac_ctx),
+       },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCBC)
+       {
+               /*
+                * Note that the only difference between xcbc(aes) and cmac(aes)
+                * is the preparekey function.
+                */
+               .base.cra_name = "xcbc(aes)",
+               .base.cra_driver_name = "xcbc-aes-lib",
+               .base.cra_priority = 300,
+               .base.cra_blocksize = AES_BLOCK_SIZE,
+               .base.cra_ctxsize = sizeof(struct aes_cmac_key),
+               .base.cra_module = THIS_MODULE,
+               .digestsize = AES_BLOCK_SIZE,
+               .setkey = crypto_aes_xcbc_setkey,
+               .init = crypto_aes_cmac_init,
+               .update = crypto_aes_cmac_update,
+               .final = crypto_aes_cmac_final,
+               .digest = crypto_aes_cmac_digest,
+               .descsize = sizeof(struct aes_cmac_ctx),
+       },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+       {
+               .base.cra_name = "cbcmac(aes)",
+               .base.cra_driver_name = "cbcmac-aes-lib",
+               .base.cra_priority = 300,
+               .base.cra_blocksize = AES_BLOCK_SIZE,
+               .base.cra_ctxsize = sizeof(struct aes_enckey),
+               .base.cra_module = THIS_MODULE,
+               .digestsize = AES_BLOCK_SIZE,
+               .setkey = crypto_aes_cbcmac_setkey,
+               .init = crypto_aes_cbcmac_init,
+               .update = crypto_aes_cbcmac_update,
+               .final = crypto_aes_cbcmac_final,
+               .digest = crypto_aes_cbcmac_digest,
+               .descsize = sizeof(struct aes_cbcmac_ctx),
+       },
+#endif
+};
+
 static int __init crypto_aes_mod_init(void)
 {
-       return crypto_register_alg(&alg);
+       int err = crypto_register_alg(&alg);
+
+       if (err)
+               return err;
+
+       if (ARRAY_SIZE(mac_algs) > 0) {
+               err = crypto_register_shashes(mac_algs, ARRAY_SIZE(mac_algs));
+               if (err)
+                       goto err_unregister_alg;
+       } /* Else, CONFIG_CRYPTO_HASH might not be enabled. */
+       return 0;
+
+err_unregister_alg:
+       crypto_unregister_alg(&alg);
+       return err;
 }
 module_init(crypto_aes_mod_init);
 
 static void __exit crypto_aes_mod_exit(void)
 {
+       if (ARRAY_SIZE(mac_algs) > 0)
+               crypto_unregister_shashes(mac_algs, ARRAY_SIZE(mac_algs));
        crypto_unregister_alg(&alg);
 }
 module_exit(crypto_aes_mod_exit);
 
 MODULE_DESCRIPTION("Crypto API support for AES block cipher");
+MODULE_IMPORT_NS("CRYPTO_INTERNAL");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("aes");
 MODULE_ALIAS_CRYPTO("aes-lib");
+#if IS_ENABLED(CONFIG_CRYPTO_CMAC)
+MODULE_ALIAS_CRYPTO("cmac(aes)");
+MODULE_ALIAS_CRYPTO("cmac-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCBC)
+MODULE_ALIAS_CRYPTO("xcbc(aes)");
+MODULE_ALIAS_CRYPTO("xcbc-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+MODULE_ALIAS_CRYPTO("cbcmac(aes)");
+MODULE_ALIAS_CRYPTO("cbcmac-aes-lib");
+#endif
index 4985411dedaec6dd8f804428f36fae53a2550b9c..fec950f1628b588f2e95a34b888a0a217199b953 100644 (file)
@@ -4388,7 +4388,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
 #endif
                .alg = "cbcmac(aes)",
-               .generic_driver = "cbcmac(aes-lib)",
+               .generic_driver = "cbcmac-aes-lib",
                .test = alg_test_hash,
                .suite = {
                        .hash = __VECS(aes_cbcmac_tv_template)
@@ -4401,7 +4401,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "ccm(aes)",
-               .generic_driver = "ccm_base(ctr(aes-lib),cbcmac(aes-lib))",
+               .generic_driver = "ccm_base(ctr(aes-lib),cbcmac-aes-lib)",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -4429,7 +4429,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                },
        }, {
                .alg = "cmac(aes)",
-               .generic_driver = "cmac(aes-lib)",
+               .generic_driver = "cmac-aes-lib",
                .fips_allowed = 1,
                .test = alg_test_hash,
                .suite = {
@@ -5326,7 +5326,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "rfc4309(ccm(aes))",
-               .generic_driver = "rfc4309(ccm_base(ctr(aes-lib),cbcmac(aes-lib)))",
+               .generic_driver = "rfc4309(ccm_base(ctr(aes-lib),cbcmac-aes-lib))",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -5515,7 +5515,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "xcbc(aes)",
-               .generic_driver = "xcbc(aes-lib)",
+               .generic_driver = "xcbc-aes-lib",
                .test = alg_test_hash,
                .suite = {
                        .hash = __VECS(aes_xcbc128_tv_template)
index c1dc1e43e117e93e4d59d0b152f4f69fed983313..2e2d97d17e6c3897388ddf615fdc48887cb66fde 100644 (file)
@@ -1003,7 +1003,7 @@ static int starfive_aes_ctr_init_tfm(struct crypto_skcipher *tfm)
 
 static int starfive_aes_ccm_init_tfm(struct crypto_aead *tfm)
 {
-       return starfive_aes_aead_init_tfm(tfm, "ccm_base(ctr(aes-lib),cbcmac(aes-lib))");
+       return starfive_aes_aead_init_tfm(tfm, "ccm_base(ctr(aes-lib),cbcmac-aes-lib)");
 }
 
 static int starfive_aes_gcm_init_tfm(struct crypto_aead *tfm)