summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-17 19:16:42 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-17 19:16:42 -0700
commitd47db9bf50d28647689e6743ee93c45cb755ffc3 (patch)
tree16d422e07b769f6e720102489021f55b09567c41
parent1d7443e4dca1e8637930f3baf64e2fe82033e669 (diff)
parentff6ac629076fb3f369c6ad35d6ead1c666469b95 (diff)
Merge tag 'libcrypto-updates-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux
Pull crypto library updates from Eric Biggers: "Add library APIs for most AES encryption modes that are used in the kernel (ECB, CBC, CBC-CTS, CTR, XCTR, XTS, GCM, CCM). These AES modes have many in-kernel users that are currently using the crypto_skcipher or crypto_aead APIs. These existing APIs are difficult to use and inefficient. Until now, the lack of proper library support for these has been the main gap in the crypto library. This set of changes is the next stage of addressing it: - Implement the new APIs on top of the existing support for single-block AES in the library. - Fully document the new APIs. - Migrate the only user of the old AES-GCM library API to the new, more flexible API; then remove the old API and its implementation. - Wire up the new APIs to the traditional crypto API by adding crypto_skcipher and crypto_aead algorithms. This makes the new APIs be covered by the traditional crypto API's self-tests. It also makes them be already used for real on systems that don't have architecture-optimized code for these modes. But most importantly, this is a prerequisite for migrating the architecture-optimized code for these AES modes (i.e. arch/*/crypto/aes*) into the library, which as usual will eliminate a lot of redundant "glue" code. Note that unlike some of the other algorithms that have been migrated to the library, e.g. SHA-512, for these AES modes there was too much to get done in one cycle. Nor did it make sense to handle these modes one at a time, because they tend to be coupled together or depend on each other, especially in the architecture-optimized AES code. Thus, most of the benefits (reductions in lines of code, performance improvements, etc.) will follow in later cycles when architecture-optimized code is migrated into the library and users of crypto_skcipher and crypto_aead are updated to use the new APIs. The design of the new APIs was informed by writing proof-of-concept patches for many kernel subsystems currently accessing these same algorithms via crypto_skcipher or crypto_aead (patches 18-33 of https://lore.kernel.org/r/20260707053503.209874-1-ebiggers@kernel.org/). While those patches will be resent for real later, the total diffstat for them was negative 1905 lines. So clearly the new APIs are quite a bit easier to use and align better with what users actually need. Besides the new AES encryption APIs, there are also a few changes for improved AES-CMAC key and context zeroization" * tag 'libcrypto-updates-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux: mac80211: fils_aead: Use __cleanup() instead of memzero_explicit() Bluetooth: SMP: clear the aes_cmac_key when done smb: clear the aes_cmac_key and aes_cmac_ctx when done lib/crypto: aes-cmac: Add zeroization functions lib/crypto: aesgcm: Remove old AES-GCM library x86/sev: Remove obsolete virtual address check x86/sev: Use new AES-GCM library crypto: aes - Add CCM support using library crypto: aes - Add GCM support using library crypto: aes - Add XTS support using library crypto: aes - Add CTR and XCTR support using library crypto: aes - Add CBC and CBC-CTS support using library crypto: aes - Add ECB support using library lib/crypto: aes: Add CCM support lib/crypto: aes: Add GCM support lib/crypto: aes: Add XTS support lib/crypto: aes: Add CTR and XCTR support lib/crypto: aes: Add CBC and CBC-CTS support lib/crypto: aes: Add ECB support crypto: xts - Split out __xts_verify_key() helper
-rw-r--r--Documentation/crypto/libcrypto-auth-encryption.rst20
-rw-r--r--Documentation/crypto/libcrypto-unauth-encryption.rst49
-rw-r--r--Documentation/crypto/libcrypto.rst2
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/coco/sev/core.c53
-rw-r--r--arch/x86/include/asm/sev.h2
-rw-r--r--crypto/Kconfig11
-rw-r--r--crypto/aes.c892
-rw-r--r--drivers/virt/coco/sev-guest/sev-guest.c7
-rw-r--r--fs/smb/client/smb2transport.c4
-rw-r--r--fs/smb/server/auth.c2
-rw-r--r--include/crypto/aes-cbc-macs.h34
-rw-r--r--include/crypto/aes-cbc.h77
-rw-r--r--include/crypto/aes-ccm.h266
-rw-r--r--include/crypto/aes-ctr.h65
-rw-r--r--include/crypto/aes-ecb.h49
-rw-r--r--include/crypto/aes-gcm.h260
-rw-r--r--include/crypto/aes-xts.h94
-rw-r--r--include/crypto/gcm.h25
-rw-r--r--include/crypto/xts.h18
-rw-r--r--lib/crypto/Kconfig41
-rw-r--r--lib/crypto/Makefile3
-rw-r--r--lib/crypto/aes.c1163
-rw-r--r--lib/crypto/aesgcm.c721
-rw-r--r--lib/crypto/tests/Kconfig6
-rw-r--r--net/bluetooth/smp.c3
-rw-r--r--net/mac80211/fils_aead.c3
27 files changed, 3073 insertions, 799 deletions
diff --git a/Documentation/crypto/libcrypto-auth-encryption.rst b/Documentation/crypto/libcrypto-auth-encryption.rst
new file mode 100644
index 000000000000..1e527685a42f
--- /dev/null
+++ b/Documentation/crypto/libcrypto-auth-encryption.rst
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Authenticated encryption
+========================
+
+These APIs provide support for authenticated encryption and decryption.
+
+AES-CCM
+-------
+
+This API provides support for AES in the CCM mode of operation.
+
+.. kernel-doc:: include/crypto/aes-ccm.h
+
+AES-GCM
+-------
+
+This API provides support for AES in the GCM mode of operation.
+
+.. kernel-doc:: include/crypto/aes-gcm.h
diff --git a/Documentation/crypto/libcrypto-unauth-encryption.rst b/Documentation/crypto/libcrypto-unauth-encryption.rst
new file mode 100644
index 000000000000..b4639b8927c6
--- /dev/null
+++ b/Documentation/crypto/libcrypto-unauth-encryption.rst
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Unauthenticated encryption
+==========================
+
+These APIs provide support for unauthenticated encryption and decryption,
+including bare stream ciphers and other length-preserving algorithms such as
+block ciphers in XTS mode. The legitimate use cases for these algorithms are:
+
+- Support for legacy protocols that really should have chosen an authenticated
+ mode (or even another primitive entirely) but didn't.
+
+- Internal components of authenticated modes. For example, AES-CTR is used by
+ AES-GCM and AES-CCM internally.
+
+- Storage encryption that cannot accommodate ciphertext expansion. Usually
+ AES-XTS is used for this.
+
+- Stream ciphers for key derivation and random number generation.
+
+Besides the above, these shouldn't be used.
+
+AES-CBC and AES-CBC-CTS
+-----------------------
+
+This API provides support for AES in the CBC and CBC-CTS modes of operation.
+
+.. kernel-doc:: include/crypto/aes-cbc.h
+
+AES-CTR and AES-XCTR
+--------------------
+
+This API provides support for AES in the CTR and XCTR modes of operation.
+
+.. kernel-doc:: include/crypto/aes-ctr.h
+
+AES-ECB
+-------
+
+This API provides support for AES in the ECB mode of operation.
+
+.. kernel-doc:: include/crypto/aes-ecb.h
+
+AES-XTS
+-------
+
+This API provides support for AES in the XTS mode of operation.
+
+.. kernel-doc:: include/crypto/aes-xts.h
diff --git a/Documentation/crypto/libcrypto.rst b/Documentation/crypto/libcrypto.rst
index 0733e603d229..e911e0521597 100644
--- a/Documentation/crypto/libcrypto.rst
+++ b/Documentation/crypto/libcrypto.rst
@@ -159,8 +159,10 @@ API documentation
.. toctree::
:maxdepth: 2
+ libcrypto-auth-encryption
libcrypto-blockcipher
libcrypto-hash
libcrypto-signature
+ libcrypto-unauth-encryption
libcrypto-utils
sha3
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bdad90f210e4..0b89641cac16 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1495,7 +1495,7 @@ config AMD_MEM_ENCRYPT
select ARCH_HAS_CC_PLATFORM
select X86_MEM_ENCRYPT
select UNACCEPTED_MEMORY
- select CRYPTO_LIB_AESGCM
+ select CRYPTO_LIB_AES_GCM
help
Say yes to enable support for the encryption of system memory.
This requires an AMD processor that supports Secure Memory
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index ecd77d3217f3..cc292d7c6fd1 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -25,7 +25,7 @@
#include <linux/psp-sev.h>
#include <linux/dmi.h>
#include <uapi/linux/sev-guest.h>
-#include <crypto/gcm.h>
+#include <crypto/aes-gcm.h>
#include <asm/init.h>
#include <asm/cpu_entry_area.h>
@@ -1535,21 +1535,21 @@ static u8 *get_vmpck(int id, struct snp_secrets_page *secrets, u32 **seqno)
return key;
}
-static struct aesgcm_ctx *snp_init_crypto(u8 *key, size_t keylen)
+static struct aes_gcm_key *snp_init_crypto(const u8 *key, size_t keylen)
{
- struct aesgcm_ctx *ctx;
+ struct aes_gcm_key *gcm_key;
- ctx = kzalloc_obj(*ctx);
- if (!ctx)
+ gcm_key = kzalloc_obj(*gcm_key);
+ if (!gcm_key)
return NULL;
- if (aesgcm_expandkey(ctx, key, keylen, AUTHTAG_LEN)) {
- pr_err("Crypto context initialization failed\n");
- kfree(ctx);
+ if (aes_gcm_preparekey(gcm_key, key, keylen, AUTHTAG_LEN)) {
+ pr_err("AES-GCM key preparation failed\n");
+ kfree_sensitive(gcm_key);
return NULL;
}
- return ctx;
+ return gcm_key;
}
int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id)
@@ -1572,8 +1572,8 @@ int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id)
mdesc->vmpck_id = vmpck_id;
- mdesc->ctx = snp_init_crypto(mdesc->vmpck, VMPCK_KEY_LEN);
- if (!mdesc->ctx)
+ mdesc->gcm_key = snp_init_crypto(mdesc->vmpck, VMPCK_KEY_LEN);
+ if (!mdesc->gcm_key)
return -ENOMEM;
return 0;
@@ -1624,7 +1624,7 @@ void snp_msg_free(struct snp_msg_desc *mdesc)
if (!mdesc)
return;
- kfree(mdesc->ctx);
+ kfree_sensitive(mdesc->gcm_key);
free_shared_pages(mdesc->response, sizeof(struct snp_guest_msg));
free_shared_pages(mdesc->request, sizeof(struct snp_guest_msg));
iounmap((__force void __iomem *)mdesc->secrets);
@@ -1709,7 +1709,7 @@ static int verify_and_dec_payload(struct snp_msg_desc *mdesc, struct snp_guest_r
struct snp_guest_msg *req_msg = &mdesc->secret_request;
struct snp_guest_msg_hdr *req_msg_hdr = &req_msg->hdr;
struct snp_guest_msg_hdr *resp_msg_hdr = &resp_msg->hdr;
- struct aesgcm_ctx *ctx = mdesc->ctx;
+ struct aes_gcm_key *gcm_key = mdesc->gcm_key;
u8 iv[GCM_AES_IV_SIZE] = {};
pr_debug("response [seqno %lld type %d version %d sz %d]\n",
@@ -1732,23 +1732,21 @@ static int verify_and_dec_payload(struct snp_msg_desc *mdesc, struct snp_guest_r
* If the message size is greater than our buffer length then return
* an error.
*/
- if (unlikely((resp_msg_hdr->msg_sz + ctx->authsize) > req->resp_sz))
+ if (unlikely(resp_msg_hdr->msg_sz + AUTHTAG_LEN > req->resp_sz))
return -EBADMSG;
/* Decrypt the payload */
memcpy(iv, &resp_msg_hdr->msg_seqno, min(sizeof(iv), sizeof(resp_msg_hdr->msg_seqno)));
- if (!aesgcm_decrypt(ctx, req->resp_buf, resp_msg->payload, resp_msg_hdr->msg_sz,
- &resp_msg_hdr->algo, AAD_LEN, iv, resp_msg_hdr->authtag))
- return -EBADMSG;
-
- return 0;
+ return aes_gcm_decrypt(req->resp_buf, resp_msg->payload,
+ resp_msg_hdr->msg_sz, resp_msg_hdr->authtag,
+ &resp_msg_hdr->algo, AAD_LEN, iv, gcm_key);
}
static int enc_payload(struct snp_msg_desc *mdesc, u64 seqno, struct snp_guest_req *req)
{
struct snp_guest_msg *msg = &mdesc->secret_request;
struct snp_guest_msg_hdr *hdr = &msg->hdr;
- struct aesgcm_ctx *ctx = mdesc->ctx;
+ struct aes_gcm_key *gcm_key = mdesc->gcm_key;
u8 iv[GCM_AES_IV_SIZE] = {};
memset(msg, 0, sizeof(*msg));
@@ -1769,12 +1767,12 @@ static int enc_payload(struct snp_msg_desc *mdesc, u64 seqno, struct snp_guest_r
pr_debug("request [seqno %lld type %d version %d sz %d]\n",
hdr->msg_seqno, hdr->msg_type, hdr->msg_version, hdr->msg_sz);
- if (WARN_ON((req->req_sz + ctx->authsize) > sizeof(msg->payload)))
+ if (WARN_ON(req->req_sz + AUTHTAG_LEN > sizeof(msg->payload)))
return -EBADMSG;
memcpy(iv, &hdr->msg_seqno, min(sizeof(iv), sizeof(hdr->msg_seqno)));
- aesgcm_encrypt(ctx, msg->payload, req->req_buf, req->req_sz, &hdr->algo,
- AAD_LEN, iv, hdr->authtag);
+ aes_gcm_encrypt(msg->payload, req->req_buf, req->req_sz, hdr->authtag,
+ &hdr->algo, AAD_LEN, iv, gcm_key);
return 0;
}
@@ -1869,15 +1867,6 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req
u64 seqno;
int rc;
- /*
- * enc_payload() calls aesgcm_encrypt(), which can potentially offload to HW.
- * The offload's DMA SG list of data to encrypt has to be in linear mapping.
- */
- if (!virt_addr_valid(req->req_buf) || !virt_addr_valid(req->resp_buf)) {
- pr_warn("AES-GSM buffers must be in linear mapping");
- return -EINVAL;
- }
-
guard(mutex)(&snp_cmd_mutex);
/* Check if the VMPCK is not empty */
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 594cfa19cbd4..9e7a077c445d 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -314,7 +314,7 @@ struct snp_msg_desc {
struct snp_secrets_page *secrets;
- struct aesgcm_ctx *ctx;
+ struct aes_gcm_key *gcm_key;
u32 *os_area_msg_seqno;
u8 *vmpck;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b61401bd3ef6..981d5dc422d4 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -358,8 +358,19 @@ config CRYPTO_AES
tristate "AES (Advanced Encryption Standard)"
select CRYPTO_ALGAPI
select CRYPTO_LIB_AES
+ select CRYPTO_LIB_AES_CBC if CRYPTO_CBC != n || CRYPTO_CTS != n
select CRYPTO_LIB_AES_CBC_MACS if CRYPTO_CMAC != n || CRYPTO_XCBC != n || CRYPTO_CCM != n
+ select CRYPTO_LIB_AES_CCM if CRYPTO_CCM != n
+ select CRYPTO_LIB_AES_CTR if CRYPTO_CTR != n || CRYPTO_XCTR != n
+ select CRYPTO_LIB_AES_ECB if CRYPTO_ECB != n
+ select CRYPTO_LIB_AES_GCM if CRYPTO_GCM != n
+ select CRYPTO_LIB_AES_XTS if CRYPTO_XTS != n
+ select CRYPTO_AEAD if CRYPTO_GCM != n || CRYPTO_CCM != n
select CRYPTO_HASH if CRYPTO_CMAC != n || CRYPTO_XCBC != n || CRYPTO_CCM != n
+ # CRYPTO_SKCIPHER should be selected only if a mode that needs it is
+ # enabled, but that doesn't work due to a recursive dependency caused by
+ # CRYPTO_SKCIPHER selecting CRYPTO_ECB. So just always select it.
+ select CRYPTO_SKCIPHER
help
AES cipher algorithms (Rijndael)(FIPS-197, ISO/IEC 18033-3)
diff --git a/crypto/aes.c b/crypto/aes.c
index 6bf23eb0503f..94791f481e98 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -6,12 +6,22 @@
*/
#include <crypto/aes-cbc-macs.h>
+#include <crypto/aes-cbc.h>
+#include <crypto/aes-ccm.h>
+#include <crypto/aes-ctr.h>
+#include <crypto/aes-ecb.h>
+#include <crypto/aes-gcm.h>
+#include <crypto/aes-xts.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
+#include <crypto/internal/aead.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
#include <linux/module.h>
static_assert(__alignof__(struct aes_key) <= CRYPTO_MINALIGN);
+static_assert(__alignof__(struct aes_enckey) <= CRYPTO_MINALIGN);
static int crypto_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
unsigned int key_len)
@@ -85,7 +95,6 @@ static int __maybe_unused crypto_aes_cmac_digest(struct shash_desc *desc,
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))
@@ -200,6 +209,828 @@ static struct shash_alg mac_algs[] = {
#endif
};
+static __maybe_unused int
+crypto_aes_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_key *key = crypto_skcipher_ctx(tfm);
+
+ return aes_preparekey(key, in_key, key_len);
+}
+
+static __maybe_unused int
+crypto_aes_skcipher_setenckey(struct crypto_skcipher *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_enckey *key = crypto_skcipher_ctx(tfm);
+
+ return aes_prepareenckey(key, in_key, key_len);
+}
+
+/*
+ * Return true if the request uses only a single scatterlist element and high
+ * memory isn't enabled. This assumes that both scatterlists are non-NULL, i.e.
+ * the caller must have handled the cryptlen == 0 case already.
+ */
+static inline bool
+skcipher_request_is_linear_lowmem(const struct skcipher_request *req)
+{
+ return !IS_ENABLED(CONFIG_HIGHMEM) &&
+ req->dst->length >= req->cryptlen &&
+ req->src->length >= req->cryptlen;
+}
+
+/*
+ * Call crypt_func() (a function that operates on simple virtual addresses) zero
+ * or more times to en/decrypt 'cryptlen' bytes of data from the source
+ * scatterlist 'src' and write it into the destination scatterlist 'dst',
+ * starting at 'start_pos' bytes into both.
+ *
+ * This always calls crypt_func() with a length that's a multiple of
+ * AES_BLOCK_SIZE, except the last call which includes any remainder. This is
+ * implemented by using an on-stack bounce buffer when necessary. The current
+ * implementation also tries to prefer passing at least 4 blocks, so e.g.
+ * scatterlist entries [16,16,16,16] result in a single 64-byte call.
+ *
+ * The scatterlists must describe either entirely different memory
+ * (out-of-place) or entirely the same memory (in-place). In the latter case,
+ * crypt_func() is always called with the source and dest pointers the same.
+ */
+#define AES_CRYPT_SG(crypt_func, dst, src, cryptlen, start_pos, ...) \
+ ({ \
+ unsigned int remaining = (cryptlen); \
+ unsigned int spos = (start_pos); \
+ \
+ if (remaining != 0) { \
+ struct scatter_walk dst_walk, src_walk; \
+ u8 tmp[4 * AES_BLOCK_SIZE] __aligned( \
+ __alignof__(long)); \
+ \
+ scatterwalk_start_at_pos(&dst_walk, (dst), spos); \
+ scatterwalk_start_at_pos(&src_walk, (src), spos); \
+ do { \
+ unsigned int dst_avail = scatterwalk_clamp( \
+ &dst_walk, remaining); \
+ unsigned int src_avail = scatterwalk_clamp( \
+ &src_walk, remaining); \
+ unsigned int n = min(dst_avail, src_avail); \
+ u8 *dst_virt; \
+ const u8 *src_virt; \
+ \
+ if (n < remaining) { \
+ if (n < sizeof(tmp)) { \
+ n = min(remaining, \
+ sizeof(tmp)); \
+ memcpy_from_scatterwalk( \
+ tmp, &src_walk, n); \
+ crypt_func(tmp, tmp, n, \
+ ##__VA_ARGS__); \
+ memcpy_to_scatterwalk( \
+ &dst_walk, tmp, n); \
+ remaining -= n; \
+ continue; \
+ } \
+ n = round_down(n, AES_BLOCK_SIZE); \
+ } \
+ \
+ scatterwalk_map(&dst_walk); \
+ dst_virt = dst_walk.addr; \
+ if (IS_ENABLED(CONFIG_HIGHMEM) && \
+ offset_in_page(src_walk.offset) == \
+ offset_in_page(dst_walk.offset) && \
+ sg_page(src_walk.sg) + (src_walk.offset / \
+ PAGE_SIZE) == \
+ sg_page(dst_walk.sg) + \
+ (dst_walk.offset / \
+ PAGE_SIZE)) { \
+ src_virt = dst_virt; \
+ } else { \
+ scatterwalk_map(&src_walk); \
+ src_virt = src_walk.addr; \
+ } \
+ crypt_func(dst_virt, src_virt, n, \
+ ##__VA_ARGS__); \
+ if (src_virt != dst_virt) \
+ scatterwalk_unmap(&src_walk); \
+ scatterwalk_advance(&src_walk, n); \
+ scatterwalk_done_dst(&dst_walk, n); \
+ remaining -= n; \
+ } while (remaining); \
+ memzero_explicit(tmp, sizeof(tmp)); \
+ } \
+ })
+
+/*
+ * Call ad_func() as needed to process the associated data in the first
+ * 'assoclen' bytes of the scatterlist 'src'.
+ */
+#define AES_PROCESS_ASSOC_DATA(ad_func, src, assoclen, ctx) \
+ ({ \
+ unsigned int remaining = (assoclen); \
+ \
+ if (remaining != 0) { \
+ struct scatter_walk walk; \
+ \
+ scatterwalk_start(&walk, (src)); \
+ do { \
+ unsigned int n = \
+ scatterwalk_next(&walk, remaining); \
+ \
+ ad_func((ctx), walk.addr, n); \
+ scatterwalk_done_src(&walk, n); \
+ remaining -= n; \
+ } while (remaining); \
+ } \
+ })
+
+/* AES-ECB */
+
+static __maybe_unused int crypto_aes_ecb_encrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen % AES_BLOCK_SIZE))
+ return -EINVAL;
+ AES_CRYPT_SG(aes_ecb_encrypt, req->dst, req->src, req->cryptlen, 0,
+ key);
+ return 0;
+}
+
+static __maybe_unused int crypto_aes_ecb_decrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen % AES_BLOCK_SIZE))
+ return -EINVAL;
+ AES_CRYPT_SG(aes_ecb_decrypt, req->dst, req->src, req->cryptlen, 0,
+ key);
+ return 0;
+}
+
+/* AES-CBC */
+
+static void crypto_aes_cbc_encrypt_sg(struct skcipher_request *req,
+ unsigned int cryptlen,
+ const struct aes_key *key)
+{
+ AES_CRYPT_SG(aes_cbc_encrypt, req->dst, req->src, cryptlen, 0, req->iv,
+ key);
+}
+
+static void crypto_aes_cbc_decrypt_sg(struct skcipher_request *req,
+ unsigned int cryptlen,
+ const struct aes_key *key)
+{
+ AES_CRYPT_SG(aes_cbc_decrypt, req->dst, req->src, cryptlen, 0, req->iv,
+ key);
+}
+
+static __maybe_unused int crypto_aes_cbc_encrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen % AES_BLOCK_SIZE))
+ return -EINVAL;
+ crypto_aes_cbc_encrypt_sg(req, req->cryptlen, key);
+ return 0;
+}
+
+static __maybe_unused int crypto_aes_cbc_decrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen % AES_BLOCK_SIZE))
+ return -EINVAL;
+ crypto_aes_cbc_decrypt_sg(req, req->cryptlen, key);
+ return 0;
+}
+
+/* AES-CBC-CTS */
+
+/*
+ * This handles AES-CBC-CTS en/decryption requests that use a nonlinear
+ * scatterlist layout or where HIGHMEM is enabled. It is explicitly 'noinline'
+ * to keep the temporary buffer out of the stack frame of the fast path.
+ */
+static noinline int
+crypto_aes_cbc_cts_crypt_nonlinear(struct skcipher_request *req, bool enc)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+ unsigned int main_len = req->cryptlen;
+ unsigned int tail_len;
+ u8 tmp[2 * AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ if (main_len == AES_BLOCK_SIZE) {
+ /* Single block is a special case that just does CBC. */
+ if (enc)
+ crypto_aes_cbc_encrypt_sg(req, main_len, key);
+ else
+ crypto_aes_cbc_decrypt_sg(req, main_len, key);
+ return 0;
+ }
+ /* Just do the last two blocks separately. */
+ tail_len = AES_BLOCK_SIZE + ((main_len - 1) % AES_BLOCK_SIZE) + 1;
+ main_len -= tail_len;
+ if (enc)
+ crypto_aes_cbc_encrypt_sg(req, main_len, key);
+ else
+ crypto_aes_cbc_decrypt_sg(req, main_len, key);
+ memcpy_from_sglist(tmp, req->src, main_len, tail_len);
+ if (enc)
+ aes_cbc_cts_encrypt(tmp, tmp, tail_len, req->iv, key);
+ else
+ aes_cbc_cts_decrypt(tmp, tmp, tail_len, req->iv, key);
+ memcpy_to_sglist(req->dst, main_len, tmp, tail_len);
+ memzero_explicit(tmp, sizeof(tmp));
+ return 0;
+}
+
+static __maybe_unused int
+crypto_aes_cbc_cts_encrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen < AES_BLOCK_SIZE))
+ return -EINVAL;
+ if (likely(skcipher_request_is_linear_lowmem(req))) {
+ /* Fast path */
+ aes_cbc_cts_encrypt(sg_virt(req->dst), sg_virt(req->src),
+ req->cryptlen, req->iv, key);
+ return 0;
+ }
+ return crypto_aes_cbc_cts_crypt_nonlinear(req, /* enc= */ true);
+}
+
+static __maybe_unused int
+crypto_aes_cbc_cts_decrypt(struct skcipher_request *req)
+{
+ const struct aes_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen < AES_BLOCK_SIZE))
+ return -EINVAL;
+ if (likely(skcipher_request_is_linear_lowmem(req))) {
+ /* Fast path */
+ aes_cbc_cts_decrypt(sg_virt(req->dst), sg_virt(req->src),
+ req->cryptlen, req->iv, key);
+ return 0;
+ }
+ return crypto_aes_cbc_cts_crypt_nonlinear(req, /* enc= */ false);
+}
+
+/* AES-CTR */
+
+static __maybe_unused int crypto_aes_ctr_crypt(struct skcipher_request *req)
+{
+ const struct aes_enckey *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ AES_CRYPT_SG(aes_ctr, req->dst, req->src, req->cryptlen, 0, req->iv,
+ key);
+ return 0;
+}
+
+/* AES-XCTR */
+
+static __maybe_unused int crypto_aes_xctr_crypt(struct skcipher_request *req)
+{
+ const struct aes_enckey *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+ u64 ctr = 1;
+
+ AES_CRYPT_SG(aes_xctr, req->dst, req->src, req->cryptlen, 0, &ctr,
+ req->iv, key);
+ return 0;
+}
+
+/* AES-XTS */
+
+static __maybe_unused int crypto_aes_xts_setkey(struct crypto_skcipher *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_xts_key *key = crypto_skcipher_ctx(tfm);
+ int flags = (crypto_skcipher_get_flags(tfm) &
+ CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) ?
+ XTS_FORBID_WEAK_KEYS :
+ 0;
+
+ return aes_xts_preparekey(key, in_key, key_len, flags);
+}
+
+static void aes_xts_crypt_wrapper(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool enc,
+ bool *cont)
+{
+ if (enc)
+ aes_xts_encrypt(dst, src, len, iv, key, *cont);
+ else
+ aes_xts_decrypt(dst, src, len, iv, key, *cont);
+ *cont = true;
+}
+
+/*
+ * This handles AES-XTS en/decryption requests that use a nonlinear scatterlist
+ * layout or where HIGHMEM is enabled. It is explicitly 'noinline' to keep the
+ * temporary buffer out of the stack frame of the fast path.
+ */
+static noinline int crypto_aes_xts_crypt_nonlinear(struct skcipher_request *req,
+ bool enc)
+{
+ const struct aes_xts_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+ u8 tmp[2 * AES_BLOCK_SIZE] __aligned(__alignof__(long));
+ unsigned int main_len = req->cryptlen;
+ unsigned int tail_len = main_len % AES_BLOCK_SIZE;
+ bool cont = false;
+
+ if (unlikely(tail_len)) {
+ /*
+ * Ciphertext stealing is needed.
+ * Just do the last two blocks separately.
+ */
+ tail_len += AES_BLOCK_SIZE;
+ main_len -= tail_len;
+ }
+
+ AES_CRYPT_SG(aes_xts_crypt_wrapper, req->dst, req->src, main_len, 0,
+ req->iv, key, enc, &cont);
+
+ if (unlikely(tail_len)) {
+ memcpy_from_sglist(tmp, req->src, main_len, tail_len);
+ aes_xts_crypt_wrapper(tmp, tmp, tail_len, req->iv, key, enc,
+ &cont);
+ memcpy_to_sglist(req->dst, main_len, tmp, tail_len);
+ memzero_explicit(tmp, sizeof(tmp));
+ }
+ return 0;
+}
+
+static __maybe_unused int crypto_aes_xts_encrypt(struct skcipher_request *req)
+{
+ const struct aes_xts_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen < AES_BLOCK_SIZE))
+ return -EINVAL;
+ if (likely(skcipher_request_is_linear_lowmem(req))) {
+ /* Fast path */
+ aes_xts_encrypt(sg_virt(req->dst), sg_virt(req->src),
+ req->cryptlen, req->iv, key, /* cont= */ false);
+ return 0;
+ }
+ return crypto_aes_xts_crypt_nonlinear(req, /* enc= */ true);
+}
+
+static __maybe_unused int crypto_aes_xts_decrypt(struct skcipher_request *req)
+{
+ const struct aes_xts_key *key =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (unlikely(req->cryptlen < AES_BLOCK_SIZE))
+ return -EINVAL;
+ if (likely(skcipher_request_is_linear_lowmem(req))) {
+ /* Fast path */
+ aes_xts_decrypt(sg_virt(req->dst), sg_virt(req->src),
+ req->cryptlen, req->iv, key, /* cont= */ false);
+ return 0;
+ }
+ return crypto_aes_xts_crypt_nonlinear(req, /* enc= */ false);
+}
+
+static struct skcipher_alg skcipher_algs[] = {
+#if IS_ENABLED(CONFIG_CRYPTO_ECB)
+ {
+ .base.cra_name = "ecb(aes)",
+ .base.cra_driver_name = "ecb-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct aes_key),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = crypto_aes_skcipher_setkey,
+ .encrypt = crypto_aes_ecb_encrypt,
+ .decrypt = crypto_aes_ecb_decrypt,
+ },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CBC)
+ {
+ .base.cra_name = "cbc(aes)",
+ .base.cra_driver_name = "cbc-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct aes_key),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = crypto_aes_skcipher_setkey,
+ .encrypt = crypto_aes_cbc_encrypt,
+ .decrypt = crypto_aes_cbc_decrypt,
+ },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CTS)
+ {
+ .base.cra_name = "cts(cbc(aes))",
+ .base.cra_driver_name = "cts-cbc-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct aes_key),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = crypto_aes_skcipher_setkey,
+ .encrypt = crypto_aes_cbc_cts_encrypt,
+ .decrypt = crypto_aes_cbc_cts_decrypt,
+ },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CTR)
+ {
+ .base.cra_name = "ctr(aes)",
+ .base.cra_driver_name = "ctr-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aes_enckey),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ .setkey = crypto_aes_skcipher_setenckey,
+ .encrypt = crypto_aes_ctr_crypt,
+ .decrypt = crypto_aes_ctr_crypt,
+ },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCTR)
+ {
+ .base.cra_name = "xctr(aes)",
+ .base.cra_driver_name = "xctr-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aes_enckey),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ .setkey = crypto_aes_skcipher_setenckey,
+ .encrypt = crypto_aes_xctr_crypt,
+ .decrypt = crypto_aes_xctr_crypt,
+ },
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XTS)
+ {
+ .base.cra_name = "xts(aes)",
+ .base.cra_driver_name = "xts-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct aes_xts_key),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = crypto_aes_xts_setkey,
+ .encrypt = crypto_aes_xts_encrypt,
+ .decrypt = crypto_aes_xts_decrypt,
+ },
+#endif
+};
+
+/* AES-GCM */
+
+static __maybe_unused int crypto_aes_gcm_setkey(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_gcm_key *key = crypto_aead_ctx(tfm);
+
+ return aes_gcm_preparekey(key, in_key, key_len,
+ crypto_aead_authsize(tfm));
+}
+
+static __maybe_unused int crypto_aes_gcm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ struct aes_gcm_key *key = crypto_aead_ctx(tfm);
+
+ if (crypto_gcm_check_authsize(authsize) != 0)
+ return -EINVAL;
+ /* Synchronize the tag length to the struct aes_gcm_key. */
+ key->authtag_len = authsize;
+ return 0;
+}
+
+static void crypto_aes_gcm_auth_update(struct aes_gcm_ctx *ctx,
+ struct scatterlist *src,
+ unsigned int assoclen)
+{
+ AES_PROCESS_ASSOC_DATA(aes_gcm_auth_update, src, assoclen, ctx);
+}
+
+static void aes_gcm_encrypt_update_helper(u8 *dst, const u8 *src,
+ unsigned int len,
+ struct aes_gcm_ctx *ctx)
+{
+ aes_gcm_encrypt_update(ctx, dst, src, len);
+}
+
+static void aes_gcm_decrypt_update_helper(u8 *dst, const u8 *src,
+ unsigned int len,
+ struct aes_gcm_ctx *ctx)
+{
+ aes_gcm_decrypt_update(ctx, dst, src, len);
+}
+
+static int crypto_aes_gcm_encrypt_common(struct aead_request *req,
+ const struct aes_gcm_key *key,
+ u8 iv[12], unsigned int assoclen)
+{
+ struct aes_gcm_ctx ctx;
+ u8 authtag[16];
+
+ aes_gcm_init(&ctx, iv, key);
+ crypto_aes_gcm_auth_update(&ctx, req->src, assoclen);
+ AES_CRYPT_SG(aes_gcm_encrypt_update_helper, req->dst, req->src,
+ req->cryptlen, req->assoclen, &ctx);
+ aes_gcm_encrypt_final(&ctx, authtag);
+ memcpy_to_sglist(req->dst, req->assoclen + req->cryptlen, authtag,
+ key->authtag_len);
+ memzero_explicit(authtag, sizeof(authtag));
+ return 0;
+}
+
+static int crypto_aes_gcm_decrypt_common(struct aead_request *req,
+ const struct aes_gcm_key *key,
+ u8 iv[12], unsigned int assoclen)
+{
+ struct aes_gcm_ctx ctx;
+ unsigned int data_len;
+ u8 authtag[16];
+ int err;
+
+ aes_gcm_init(&ctx, iv, key);
+ crypto_aes_gcm_auth_update(&ctx, req->src, assoclen);
+
+ /* crypto_aead_decrypt() already checked cryptlen >= authtag_len. */
+ data_len = req->cryptlen - key->authtag_len;
+ AES_CRYPT_SG(aes_gcm_decrypt_update_helper, req->dst, req->src,
+ data_len, req->assoclen, &ctx);
+
+ memcpy_from_sglist(authtag, req->src, req->assoclen + data_len,
+ key->authtag_len);
+ err = aes_gcm_decrypt_final(&ctx, authtag);
+ memzero_explicit(authtag, sizeof(authtag));
+ return err;
+}
+
+static __maybe_unused int crypto_aes_gcm_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_gcm_key *key = crypto_aead_ctx(tfm);
+
+ return crypto_aes_gcm_encrypt_common(req, key, req->iv, req->assoclen);
+}
+
+static __maybe_unused int crypto_aes_gcm_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_gcm_key *key = crypto_aead_ctx(tfm);
+
+ return crypto_aes_gcm_decrypt_common(req, key, req->iv, req->assoclen);
+}
+
+struct aes_rfc4106_key {
+ struct aes_gcm_key gcm;
+ u8 nonce[4];
+};
+
+static __maybe_unused int crypto_aes_rfc4106_setkey(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_rfc4106_key *key = crypto_aead_ctx(tfm);
+
+ if (key_len < 4)
+ return -EINVAL;
+
+ key_len -= 4;
+ memcpy(key->nonce, in_key + key_len, 4);
+
+ return aes_gcm_preparekey(&key->gcm, in_key, key_len,
+ crypto_aead_authsize(tfm));
+}
+
+static __maybe_unused int
+crypto_aes_rfc4106_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+ struct aes_rfc4106_key *key = crypto_aead_ctx(tfm);
+
+ if (crypto_rfc4106_check_authsize(authsize) != 0)
+ return -EINVAL;
+
+ /* Synchronize the tag length to the struct aes_gcm_key. */
+ key->gcm.authtag_len = authsize;
+ return 0;
+}
+
+static __maybe_unused int crypto_aes_rfc4106_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_rfc4106_key *key = crypto_aead_ctx(tfm);
+ u8 iv[12];
+
+ if (crypto_ipsec_check_assoclen(req->assoclen) != 0)
+ return -EINVAL;
+ memcpy(iv, key->nonce, 4);
+ memcpy(&iv[4], req->iv, 8);
+
+ return crypto_aes_gcm_encrypt_common(req, &key->gcm, iv,
+ req->assoclen - 8);
+}
+
+static __maybe_unused int crypto_aes_rfc4106_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_rfc4106_key *key = crypto_aead_ctx(tfm);
+ u8 iv[12];
+
+ if (crypto_ipsec_check_assoclen(req->assoclen) != 0)
+ return -EINVAL;
+ memcpy(iv, key->nonce, 4);
+ memcpy(&iv[4], req->iv, 8);
+
+ return crypto_aes_gcm_decrypt_common(req, &key->gcm, iv,
+ req->assoclen - 8);
+}
+
+/* AES-CCM */
+
+static __maybe_unused int crypto_aes_ccm_setkey(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_ccm_key *key = crypto_aead_ctx(tfm);
+
+ return aes_ccm_preparekey(key, in_key, key_len,
+ crypto_aead_authsize(tfm));
+}
+
+static __maybe_unused int crypto_aes_ccm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ struct aes_ccm_key *key = crypto_aead_ctx(tfm);
+
+ if (authsize < 4 || authsize > 16 || authsize % 2)
+ return -EINVAL;
+ /* Synchronize the tag length to the struct aes_ccm_key. */
+ key->authtag_len = authsize;
+ return 0;
+}
+
+static int crypto_aes_ccm_init(struct aes_ccm_ctx *ctx,
+ struct aead_request *req, unsigned int data_len,
+ const struct aes_ccm_key *key)
+{
+ int nonce_len;
+ const u8 *nonce;
+ int err;
+
+ /*
+ * CCM accepts a variable-length nonce between 7 and 13 bytes
+ * inclusively, while crypto_aead assumes a fixed-length IV. This is
+ * worked around by requiring that iv[0] contain '14 - nonce_len' and
+ * iv[1..] contain the actual nonce. Extra bytes at the end are unused.
+ */
+ nonce_len = 14 - (int)req->iv[0];
+ if (unlikely(nonce_len < 7 || nonce_len > 13))
+ return -EINVAL;
+ nonce = &req->iv[1];
+ err = aes_ccm_init(ctx, data_len, req->assoclen, nonce, nonce_len, key);
+ if (unlikely(err))
+ return err;
+ AES_PROCESS_ASSOC_DATA(aes_ccm_auth_update, req->src, req->assoclen,
+ ctx);
+ return 0;
+}
+
+static void aes_ccm_encrypt_update_helper(u8 *dst, const u8 *src,
+ unsigned int len,
+ struct aes_ccm_ctx *ctx)
+{
+ aes_ccm_encrypt_update(ctx, dst, src, len);
+}
+
+static void aes_ccm_decrypt_update_helper(u8 *dst, const u8 *src,
+ unsigned int len,
+ struct aes_ccm_ctx *ctx)
+{
+ aes_ccm_decrypt_update(ctx, dst, src, len);
+}
+
+static __maybe_unused int crypto_aes_ccm_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_ccm_key *key = crypto_aead_ctx(tfm);
+ struct aes_ccm_ctx ctx;
+ u8 authtag[16];
+ int err;
+
+ err = crypto_aes_ccm_init(&ctx, req, req->cryptlen, key);
+ if (unlikely(err))
+ return err;
+ AES_CRYPT_SG(aes_ccm_encrypt_update_helper, req->dst, req->src,
+ req->cryptlen, req->assoclen, &ctx);
+ aes_ccm_encrypt_final(&ctx, authtag);
+ memcpy_to_sglist(req->dst, req->assoclen + req->cryptlen, authtag,
+ key->authtag_len);
+ memzero_explicit(authtag, sizeof(authtag));
+ return 0;
+}
+
+static __maybe_unused int crypto_aes_ccm_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ const struct aes_ccm_key *key = crypto_aead_ctx(tfm);
+ unsigned int data_len;
+ struct aes_ccm_ctx ctx;
+ u8 authtag[16];
+ int err;
+
+ /* crypto_aead_decrypt() already checked cryptlen >= authtag_len. */
+ data_len = req->cryptlen - key->authtag_len;
+ err = crypto_aes_ccm_init(&ctx, req, data_len, key);
+ if (unlikely(err))
+ return err;
+ AES_CRYPT_SG(aes_ccm_decrypt_update_helper, req->dst, req->src,
+ data_len, req->assoclen, &ctx);
+ memcpy_from_sglist(authtag, req->src, req->assoclen + data_len,
+ key->authtag_len);
+ err = aes_ccm_decrypt_final(&ctx, authtag);
+ memzero_explicit(authtag, sizeof(authtag));
+ return err;
+}
+
+static struct aead_alg aead_algs[] = {
+#if IS_ENABLED(CONFIG_CRYPTO_GCM)
+ {
+ .base.cra_name = "gcm(aes)",
+ .base.cra_driver_name = "gcm-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aes_gcm_key),
+ .base.cra_module = THIS_MODULE,
+ .setkey = crypto_aes_gcm_setkey,
+ .setauthsize = crypto_aes_gcm_setauthsize,
+ .encrypt = crypto_aes_gcm_encrypt,
+ .decrypt = crypto_aes_gcm_decrypt,
+ .ivsize = GCM_AES_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ {
+ .base.cra_name = "rfc4106(gcm(aes))",
+ .base.cra_driver_name = "rfc4106-gcm-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aes_rfc4106_key),
+ .base.cra_module = THIS_MODULE,
+ .setkey = crypto_aes_rfc4106_setkey,
+ .setauthsize = crypto_aes_rfc4106_setauthsize,
+ .encrypt = crypto_aes_rfc4106_encrypt,
+ .decrypt = crypto_aes_rfc4106_decrypt,
+ .ivsize = GCM_RFC4106_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+#endif /* CONFIG_CRYPTO_GCM */
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+ {
+ .base.cra_name = "ccm(aes)",
+ .base.cra_driver_name = "ccm-aes-lib",
+ .base.cra_priority = 110,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct aes_ccm_key),
+ .base.cra_module = THIS_MODULE,
+ .setkey = crypto_aes_ccm_setkey,
+ .setauthsize = crypto_aes_ccm_setauthsize,
+ .encrypt = crypto_aes_ccm_encrypt,
+ .decrypt = crypto_aes_ccm_decrypt,
+ .ivsize = 16,
+ .maxauthsize = 16,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+#endif /* CONFIG_CRYPTO_CCM */
+};
+
static int __init crypto_aes_mod_init(void)
{
int err = crypto_register_alg(&alg);
@@ -212,8 +1043,28 @@ static int __init crypto_aes_mod_init(void)
if (err)
goto err_unregister_alg;
} /* Else, CONFIG_CRYPTO_HASH might not be enabled. */
+
+ if (ARRAY_SIZE(skcipher_algs) > 0) {
+ err = crypto_register_skciphers(skcipher_algs,
+ ARRAY_SIZE(skcipher_algs));
+ if (err)
+ goto err_unregister_macs;
+ }
+
+ if (ARRAY_SIZE(aead_algs) > 0) {
+ err = crypto_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ if (err)
+ goto err_unregister_skciphers;
+ } /* Else, CONFIG_CRYPTO_AEAD might not be enabled. */
return 0;
+err_unregister_skciphers:
+ if (ARRAY_SIZE(skcipher_algs) > 0)
+ crypto_unregister_skciphers(skcipher_algs,
+ ARRAY_SIZE(skcipher_algs));
+err_unregister_macs:
+ if (ARRAY_SIZE(mac_algs) > 0)
+ crypto_unregister_shashes(mac_algs, ARRAY_SIZE(mac_algs));
err_unregister_alg:
crypto_unregister_alg(&alg);
return err;
@@ -222,6 +1073,11 @@ module_init(crypto_aes_mod_init);
static void __exit crypto_aes_mod_exit(void)
{
+ if (ARRAY_SIZE(aead_algs) > 0)
+ crypto_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ if (ARRAY_SIZE(skcipher_algs) > 0)
+ crypto_unregister_skciphers(skcipher_algs,
+ ARRAY_SIZE(skcipher_algs));
if (ARRAY_SIZE(mac_algs) > 0)
crypto_unregister_shashes(mac_algs, ARRAY_SIZE(mac_algs));
crypto_unregister_alg(&alg);
@@ -245,3 +1101,37 @@ MODULE_ALIAS_CRYPTO("xcbc-aes-lib");
MODULE_ALIAS_CRYPTO("cbcmac(aes)");
MODULE_ALIAS_CRYPTO("cbcmac-aes-lib");
#endif
+#if IS_ENABLED(CONFIG_CRYPTO_ECB)
+MODULE_ALIAS_CRYPTO("ecb(aes)");
+MODULE_ALIAS_CRYPTO("ecb-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CBC)
+MODULE_ALIAS_CRYPTO("cbc(aes)");
+MODULE_ALIAS_CRYPTO("cbc-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CTS)
+MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
+MODULE_ALIAS_CRYPTO("cts-cbc-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CTR)
+MODULE_ALIAS_CRYPTO("ctr(aes)");
+MODULE_ALIAS_CRYPTO("ctr-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCTR)
+MODULE_ALIAS_CRYPTO("xctr(aes)");
+MODULE_ALIAS_CRYPTO("xctr-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XTS)
+MODULE_ALIAS_CRYPTO("xts(aes)");
+MODULE_ALIAS_CRYPTO("xts-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_GCM)
+MODULE_ALIAS_CRYPTO("gcm(aes)");
+MODULE_ALIAS_CRYPTO("gcm-aes-lib");
+MODULE_ALIAS_CRYPTO("rfc4106(gcm(aes))");
+MODULE_ALIAS_CRYPTO("rfc4106-gcm-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+MODULE_ALIAS_CRYPTO("ccm(aes)");
+MODULE_ALIAS_CRYPTO("ccm-aes-lib");
+#endif
diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c
index d186ae55cf63..935537a41469 100644
--- a/drivers/virt/coco/sev-guest/sev-guest.c
+++ b/drivers/virt/coco/sev-guest/sev-guest.c
@@ -17,7 +17,6 @@
#include <linux/set_memory.h>
#include <linux/fs.h>
#include <linux/tsm.h>
-#include <crypto/gcm.h>
#include <linux/psp-sev.h>
#include <linux/sockptr.h>
#include <linux/cleanup.h>
@@ -87,7 +86,7 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(report_resp->data) + mdesc->ctx->authsize;
+ resp_len = sizeof(report_resp->data) + AUTHTAG_LEN;
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
if (!report_resp)
return -ENOMEM;
@@ -130,7 +129,7 @@ static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_reque
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(derived_key_resp->data) + mdesc->ctx->authsize;
+ resp_len = sizeof(derived_key_resp->data) + AUTHTAG_LEN;
derived_key_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
if (!derived_key_resp)
return -ENOMEM;
@@ -230,7 +229,7 @@ cmd:
* response payload. Make sure that it has enough space to cover the
* authtag.
*/
- resp_len = sizeof(report_resp->data) + mdesc->ctx->authsize;
+ resp_len = sizeof(report_resp->data) + AUTHTAG_LEN;
report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
if (!report_resp) {
ret = -ENOMEM;
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 1143ee52470a..d23566da2ac8 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -464,8 +464,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb3_signature[SMB2_CMACAES_SIZE];
struct kvec *iov = rqst->rq_iov;
struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
- struct aes_cmac_key cmac_key;
- struct aes_cmac_ctx cmac_ctx;
+ struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
+ struct aes_cmac_ctx cmac_ctx __cleanup(aes_cmac_zeroize_ctx);
struct smb_rqst drqst;
u8 key[SMB3_SIGN_KEY_SIZE];
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 4e7b6f0e6b8c..e8d1c068a43e 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -509,7 +509,7 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig)
{
- struct aes_cmac_key cmac_key;
+ struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
struct aes_cmac_ctx cmac_ctx;
int i;
diff --git a/include/crypto/aes-cbc-macs.h b/include/crypto/aes-cbc-macs.h
index e61df108b926..06e8a22f8a0a 100644
--- a/include/crypto/aes-cbc-macs.h
+++ b/include/crypto/aes-cbc-macs.h
@@ -8,6 +8,7 @@
#define _CRYPTO_AES_CBC_MACS_H
#include <crypto/aes.h>
+#include <linux/string.h>
/**
* struct aes_cmac_key - Prepared key for AES-CMAC or AES-XCBC-MAC
@@ -25,6 +26,19 @@ struct aes_cmac_key {
};
/**
+ * aes_cmac_zeroize_key() - Zeroize an aes_cmac_key structure
+ * @key: The location of the key structure that should be zeroized
+ *
+ * Explicitly fills the aes_cmac_key with zeroes. This should be done once
+ * the key is not required anymore to avoid that its contents are leaked
+ * on the stack or heap (if not using kfree_sensitive()).
+ */
+static inline void aes_cmac_zeroize_key(struct aes_cmac_key *key)
+{
+ memzero_explicit(key, sizeof(*key));
+}
+
+/**
* struct aes_cmac_ctx - Context for computing an AES-CMAC or AES-XCBC-MAC value
* @key: Pointer to the key struct. A pointer is used rather than a copy of the
* struct, since the key struct size may be large. It is assumed that the
@@ -41,12 +55,29 @@ struct aes_cmac_ctx {
};
/**
+ * aes_cmac_zeroize_ctx() - Zeroize an aes_cmac_ctx structure
+ * @ctx: The location of the context that should be zeroized
+ *
+ * Explicitly fills the aes_cmac_ctx with zeroes. This should be done once
+ * the context is not required anymore to avoid that its contents are
+ * leaked on the stack or heap. Only required if not using aes_cmac_final().
+ */
+static inline void aes_cmac_zeroize_ctx(struct aes_cmac_ctx *ctx)
+{
+ memzero_explicit(ctx, sizeof(*ctx));
+}
+
+/**
* aes_cmac_preparekey() - Prepare a key for AES-CMAC
* @key: (output) The key struct to initialize
* @in_key: The raw AES key
* @key_len: Length of the raw key in bytes. The supported values are
* AES_KEYSIZE_128, AES_KEYSIZE_192, and AES_KEYSIZE_256.
*
+ * On success, the caller should ensure that the prepared key is zeroized
+ * at the end of its lifetime, e.g. by calling aes_cmac_zeroize_key() or
+ * kfree_sensitive().
+ *
* Context: Any context.
* Return: 0 on success or -EINVAL if the given key length is invalid. No other
* errors are possible, so callers that always pass a valid key length
@@ -79,6 +110,9 @@ void aes_xcbcmac_preparekey(struct aes_cmac_key *key,
*
* This supports both AES-CMAC and AES-XCBC-MAC. Which one is done depends on
* whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
+ *
+ * The caller should ensure that the context is zeroized at the end of its
+ * lifetime, e.g. by calling aes_cmac_final() or aes_cmac_zeroize_ctx().
*/
static inline void aes_cmac_init(struct aes_cmac_ctx *ctx,
const struct aes_cmac_key *key)
diff --git a/include/crypto/aes-cbc.h b/include/crypto/aes-cbc.h
new file mode 100644
index 000000000000..7bae340935f9
--- /dev/null
+++ b/include/crypto/aes-cbc.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-CBC and AES-CBC-CTS unauthenticated encryption and decryption
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_CBC_H
+#define _CRYPTO_AES_CBC_H
+
+#include <crypto/aes.h>
+
+/**
+ * aes_cbc_encrypt() - Encrypt data using AES-CBC
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to encrypt. Must be a multiple of AES_BLOCK_SIZE.
+ * @iv: The initialization vector. It is updated with the next value, i.e. the
+ * last ciphertext block (or left unchanged if @len == 0).
+ * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()
+ *
+ * This supports incremental encryption. The length of each chunk must be a
+ * multiple of AES_BLOCK_SIZE, and the updated @iv must be passed in each time.
+ *
+ * Context: Any context.
+ */
+void aes_cbc_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[at_least AES_BLOCK_SIZE], aes_encrypt_arg key);
+
+/**
+ * aes_cbc_decrypt() - Decrypt data using AES-CBC
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to decrypt. Must be a multiple of AES_BLOCK_SIZE.
+ * @iv: The initialization vector. It is updated with the next value, i.e. the
+ * last ciphertext block (or left unchanged if @len == 0).
+ * @key: The key, already prepared using aes_preparekey()
+ *
+ * This supports incremental decryption. The length of each chunk must be a
+ * multiple of AES_BLOCK_SIZE, and the updated @iv must be passed in each time.
+ *
+ * Context: Any context.
+ */
+void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[at_least AES_BLOCK_SIZE], const struct aes_key *key);
+
+/**
+ * aes_cbc_cts_encrypt() - Encrypt data using AES-CBC-CTS (CS3 variant)
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to encrypt, at least AES_BLOCK_SIZE
+ * @iv: The initialization vector, clobbered by this function
+ * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()
+ *
+ * Context: Any context.
+ */
+void aes_cbc_cts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[at_least AES_BLOCK_SIZE], aes_encrypt_arg key);
+
+/**
+ * aes_cbc_cts_decrypt() - Decrypt data using AES-CBC-CTS (CS3 variant)
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to decrypt, at least AES_BLOCK_SIZE
+ * @iv: The initialization vector, clobbered by this function
+ * @key: The key, already prepared using aes_preparekey()
+ *
+ * Context: Any context.
+ */
+void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[at_least AES_BLOCK_SIZE],
+ const struct aes_key *key);
+
+#endif /* _CRYPTO_AES_CBC_H */
diff --git a/include/crypto/aes-ccm.h b/include/crypto/aes-ccm.h
new file mode 100644
index 000000000000..8b00859ac4d6
--- /dev/null
+++ b/include/crypto/aes-ccm.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-CCM authenticated encryption and decryption
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_CCM_H
+#define _CRYPTO_AES_CCM_H
+
+#include <crypto/aes.h>
+
+/**
+ * struct aes_ccm_key - A key prepared for AES-CCM encryption and decryption
+ */
+struct aes_ccm_key {
+ /* private: */
+ struct aes_enckey aes;
+ size_t authtag_len; /* Length of authentication tags in bytes */
+};
+
+/**
+ * struct aes_ccm_ctx - Context for incrementally en/decrypting a message
+ */
+struct aes_ccm_ctx {
+ /* private: */
+ /*
+ * Pointer to the key, which is assumed to live at least as long as this
+ * struct.
+ */
+ const struct aes_ccm_key *key;
+ /*
+ * The current CBC-MAC chaining value. When not on a block boundary,
+ * the partial block has been XOR'ed into this. The number of partial
+ * bytes is 'partial_len'.
+ */
+ u8 mac[AES_BLOCK_SIZE] __aligned(__alignof__(__be64));
+ /* The current counter, a 128-bit big endian value */
+ u8 ctr[AES_BLOCK_SIZE] __aligned(__alignof__(__be64));
+ /* Buffered keystream for partial block updates */
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(__be64));
+ /* Encrypted counter of 0. This gets XOR'ed with the tag at the end. */
+ u8 s0[AES_BLOCK_SIZE] __aligned(__alignof__(__be64));
+ /* Number of associated data bytes remaining to be provided */
+ u64 ad_remaining;
+ /* Number of en/decrypted data bytes remaining to be provided */
+ u64 data_remaining;
+ /* Current partial block length, 0 <= partial_len < AES_BLOCK_SIZE */
+ u32 partial_len;
+ /* True if associated data padding has been done */
+ bool ad_padded;
+};
+
+/**
+ * aes_ccm_preparekey() - Prepare a key for AES-CCM encryption and decryption
+ * @key: (output) The key structure to initialize
+ * @in_key: The raw AES-CCM key
+ * @key_len: Length of the raw key in bytes: 16, 24, or 32
+ * @authtag_len: Length of the authentication tag in bytes:
+ * 4, 6, 8, 10, 12, 14, or 16. 16 is recommended.
+ *
+ * Users should use memzero_explicit() to zeroize the key struct at the end of
+ * its lifetime. (But if this function fails, zeroization is unnecessary.)
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success
+ * * -EINVAL if either of the lengths is invalid
+ */
+int __must_check aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len);
+
+/**
+ * aes_ccm_encrypt() - Encrypt a message with AES-CCM
+ * @dst: The destination ciphertext data. Can be in-place or out-of-place.
+ * For other overlaps the behavior is unspecified.
+ * @src: The source plaintext data
+ * @data_len: Length of plaintext in bytes (and ciphertext excluding the tag):
+ * at most 2^(120 - (8 * @nonce_len)) - 1
+ * @authtag: The output authentication tag. Length is the authtag_len that was
+ * passed to aes_ccm_preparekey(). Usually protocols using AES-CCM
+ * put the tag at the end of the ciphertext, in which case this should
+ * be set to @dst + @data_len and @dst must have room for the tag.
+ * @ad: The associated data
+ * @ad_len: Length of associated data in bytes
+ * @nonce: The nonce. All (key, nonce) pairs used MUST be distinct.
+ * @nonce_len: Length of the nonce in bytes: between 7 and 13 inclusive
+ * @key: The key, already prepared using aes_ccm_preparekey()
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success
+ * * -EINVAL if @nonce_len is invalid
+ * * -EOVERFLOW if @data_len is too large for the selected @nonce_len
+ */
+int __must_check aes_ccm_encrypt(u8 *dst, const u8 *src, size_t data_len,
+ u8 *authtag, const u8 *ad, size_t ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_ccm_key *key);
+
+/**
+ * aes_ccm_decrypt() - Decrypt a message with AES-CCM
+ * @dst: The destination plaintext data. Can be in-place or out-of-place.
+ * For other overlaps the behavior is unspecified.
+ * @src: The source ciphertext data
+ * @data_len: Length of plaintext in bytes (and ciphertext excluding the tag):
+ * at most 2^(120 - (8 * @nonce_len)) - 1
+ * @authtag: The stored authentication tag. Length is the authtag_len that was
+ * passed to aes_ccm_preparekey(). Usually protocols using AES-CCM
+ * put the tag at the end of the ciphertext, in which case this should
+ * be set to @src + @data_len and @src must have room for the tag.
+ * @ad: The associated data
+ * @ad_len: Length of associated data in bytes
+ * @nonce: The nonce
+ * @nonce_len: Length of the nonce in bytes: between 7 and 13 inclusive
+ * @key: The key, already prepared using aes_ccm_preparekey()
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success. This is the only case where any decrypted or associated data
+ * can be used.
+ * * -EBADMSG if the message is inauthentic
+ * * -EINVAL if @nonce_len is invalid
+ * * -EOVERFLOW if @data_len is too large for the selected @nonce_len
+ */
+int __must_check aes_ccm_decrypt(u8 *dst, const u8 *src, size_t data_len,
+ const u8 *authtag, const u8 *ad, size_t ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_ccm_key *key);
+
+/**
+ * aes_ccm_init() - Initialize context for incremental AES-CCM encryption or
+ * decryption
+ * @ctx: The context to initialize
+ * @data_len: Length of the en/decrypted data that will be provided in bytes:
+ * at most 2^(120 - (8 * @nonce_len)) - 1
+ * @ad_len: Length of the associated data that will be provided in bytes
+ * @nonce: The nonce. All (key, nonce) pairs used for encryption MUST be
+ * distinct.
+ * @nonce_len: Length of the nonce in bytes: between 7 and 13 inclusive
+ * @key: The key, already prepared using aes_ccm_preparekey(). Note that a
+ * pointer to the key is saved in the context, so the key must live at
+ * least as long as the context.
+ *
+ * Unlike AES-GCM, AES-CCM requires the total lengths of the associated data and
+ * the en/decrypted data to be known during initialization. Callers MUST ensure
+ * that these lengths are correct.
+ *
+ * If this function returns success, the context should be zeroized at the end
+ * of its lifetime. Normally that happens in aes_ccm_encrypt_final() or
+ * aes_ccm_decrypt_final(), but callers that abandon a context without
+ * finalizing it should explicitly zeroize it.
+ *
+ * IMPORTANT: Callers that are decrypting MUST NOT assume that any decrypted or
+ * associated data is authentic until the authentication tag has been verified.
+ * This incremental API is provided solely to support callers that can't
+ * efficiently use the one-shot functions due to using a nonlinear data layout.
+ *
+ * For incremental AES-CCM encryption, use:
+ *
+ * 1. aes_ccm_init()
+ * 2. aes_ccm_auth_update() (any number of times)
+ * 3. aes_ccm_encrypt_update() (any number of times)
+ * 4. aes_ccm_encrypt_final()
+ *
+ * For incremental AES-CCM decryption, use:
+ *
+ * 1. aes_ccm_init()
+ * 2. aes_ccm_auth_update() (any number of times)
+ * 3. aes_ccm_decrypt_update() (any number of times)
+ * 4. aes_ccm_decrypt_final()
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success
+ * * -EINVAL if @nonce_len is invalid
+ * * -EOVERFLOW if @data_len is too large for the selected @nonce_len
+ */
+int __must_check aes_ccm_init(struct aes_ccm_ctx *ctx, u64 data_len, u64 ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_ccm_key *key);
+
+/**
+ * aes_ccm_auth_update() - Incrementally process AES-CCM associated data
+ * @ctx: An AES-CCM context
+ * @ad: The associated data
+ * @len: Length of the associated data in bytes
+ *
+ * IMPORTANT: Callers MUST NOT assume that any decrypted or associated data is
+ * authentic until the authentication tag has been verified.
+ *
+ * The total length of the associated data (over all calls to this function)
+ * MUST match the ad_len that was passed to aes_ccm_init().
+ *
+ * Context: Any context.
+ */
+void aes_ccm_auth_update(struct aes_ccm_ctx *ctx, const u8 *ad, size_t len);
+
+/**
+ * aes_ccm_encrypt_update() - Incrementally encrypt data with AES-CCM
+ * @ctx: An AES-CCM context
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source plaintext data
+ * @len: Number of bytes to encrypt
+ *
+ * This can be called only after all associated data has been processed.
+ *
+ * The total length of the encrypted data (over all calls to this function) MUST
+ * match the data_len that was passed to aes_ccm_init().
+ *
+ * Context: Any context.
+ */
+void aes_ccm_encrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len);
+
+/**
+ * aes_ccm_decrypt_update() - Incrementally decrypt data with AES-CCM
+ * @ctx: An AES-CCM context
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source ciphertext data (not including auth tag)
+ * @len: Number of bytes to decrypt
+ *
+ * This can be called only after all associated data has been processed.
+ *
+ * The total length of the decrypted data (over all calls to this function) MUST
+ * match the data_len that was passed to aes_ccm_init().
+ *
+ * IMPORTANT: Callers MUST NOT assume that any decrypted or associated data is
+ * authentic until the authentication tag has been verified.
+ *
+ * Context: Any context.
+ */
+void aes_ccm_decrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len);
+
+/**
+ * aes_ccm_encrypt_final() - Finish encrypting a message with AES-CCM
+ * @ctx: An AES-CCM context
+ * @authtag: The output authentication tag. Length is the authtag_len that was
+ * passed to aes_ccm_preparekey().
+ *
+ * This also zeroizes @ctx, so the caller doesn't need to do it.
+ *
+ * Context: Any context.
+ */
+void aes_ccm_encrypt_final(struct aes_ccm_ctx *ctx, u8 *authtag);
+
+/**
+ * aes_ccm_decrypt_final() - Finish decrypting a message with AES-CCM
+ * @ctx: An AES-CCM context
+ * @authtag: The stored authentication tag. Length is the authtag_len that was
+ * passed to aes_ccm_preparekey().
+ *
+ * This also zeroizes @ctx, so the caller doesn't need to do it.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success. This is the only case where any decrypted or associated data
+ * can be used.
+ * * -EBADMSG if the message is inauthentic
+ */
+int __must_check aes_ccm_decrypt_final(struct aes_ccm_ctx *ctx,
+ const u8 *authtag);
+
+#endif /* _CRYPTO_AES_CCM_H */
diff --git a/include/crypto/aes-ctr.h b/include/crypto/aes-ctr.h
new file mode 100644
index 000000000000..8e214a85716b
--- /dev/null
+++ b/include/crypto/aes-ctr.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-CTR and AES-XCTR stream ciphers
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_CTR_H
+#define _CRYPTO_AES_CTR_H
+
+#include <crypto/aes.h>
+
+/**
+ * aes_ctr() - AES-CTR en/decryption
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to en/decrypt
+ * @ctr: The counter. It will be incremented by ceil(@len / AES_BLOCK_SIZE).
+ * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()
+ *
+ * This implements AES in counter mode with a 128-bit big endian counter.
+ *
+ * This exists only for use by the implementation of modes built on top of CTR
+ * (e.g., GCM and CCM) and some legacy protocols that use CTR mode directly.
+ * Callers are expected to know how to use CTR mode appropriately, including
+ * choosing (key, counter) pairs appropriately to avoid keystream reuse.
+ *
+ * This supports incremental en/decryption. The length of each non-final chunk
+ * must be a multiple of AES_BLOCK_SIZE, and the updated @ctr must be passed in
+ * each time.
+ *
+ * Context: Any context.
+ */
+void aes_ctr(u8 *dst, const u8 *src, size_t len,
+ u8 ctr[at_least AES_BLOCK_SIZE], aes_encrypt_arg key);
+
+/**
+ * aes_xctr() - AES-XCTR en/decryption
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to en/decrypt
+ * @ctr: The block counter (in host endianness). For the first call, set it to
+ * 1. It will be incremented by ceil(@len / AES_BLOCK_SIZE).
+ * @iv: The initialization vector
+ * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()
+ *
+ * This implements AES in XOR Counter mode, as specified in the paper
+ * "Length-preserving encryption with HCTR2"
+ * (https://eprint.iacr.org/2021/1441.pdf).
+ *
+ * This exists only for use by the implementation of modes built on top of XCTR.
+ * Callers are expected to know how to use XCTR mode appropriately, including
+ * choosing (key, IV) pairs appropriately to avoid keystream reuse.
+ *
+ * This supports incremental en/decryption. The length of each non-final chunk
+ * must be a multiple of AES_BLOCK_SIZE, and the updated @ctr must be passed in
+ * each time.
+ *
+ * Context: Any context.
+ */
+void aes_xctr(u8 *dst, const u8 *src, size_t len, u64 *ctr,
+ const u8 iv[at_least AES_BLOCK_SIZE], aes_encrypt_arg key);
+
+#endif /* _CRYPTO_AES_CTR_H */
diff --git a/include/crypto/aes-ecb.h b/include/crypto/aes-ecb.h
new file mode 100644
index 000000000000..8cac1f8794c7
--- /dev/null
+++ b/include/crypto/aes-ecb.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-ECB unauthenticated encryption and decryption
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_ECB_H
+#define _CRYPTO_AES_ECB_H
+
+#include <crypto/aes.h>
+
+/**
+ * aes_ecb_encrypt() - Encrypt data using AES-ECB
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to encrypt. Must be a multiple of AES_BLOCK_SIZE.
+ * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()
+ *
+ * ECB mode is insecure by itself. This function exists only for compatibility
+ * with legacy protocols and for internal use by other modes.
+ *
+ * This supports incremental encryption, but the length of each chunk must be a
+ * multiple of AES_BLOCK_SIZE.
+ *
+ * Context: Any context.
+ */
+void aes_ecb_encrypt(u8 *dst, const u8 *src, size_t len, aes_encrypt_arg key);
+
+/**
+ * aes_ecb_decrypt() - Decrypt data using AES-ECB
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to decrypt. Must be a multiple of AES_BLOCK_SIZE.
+ * @key: The key, already prepared using aes_preparekey()
+ *
+ * ECB mode is insecure by itself. This function exists only for compatibility
+ * with legacy protocols and for internal use by other modes.
+ *
+ * This supports incremental decryption, but the length of each chunk must be a
+ * multiple of AES_BLOCK_SIZE.
+ *
+ * Context: Any context.
+ */
+void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len,
+ const struct aes_key *key);
+
+#endif /* _CRYPTO_AES_ECB_H */
diff --git a/include/crypto/aes-gcm.h b/include/crypto/aes-gcm.h
new file mode 100644
index 000000000000..2aee62f01989
--- /dev/null
+++ b/include/crypto/aes-gcm.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-GCM authenticated encryption and decryption
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_GCM_H
+#define _CRYPTO_AES_GCM_H
+
+#include <crypto/aes.h>
+#include <crypto/gcm.h>
+#include <crypto/gf128hash.h>
+
+/**
+ * struct aes_gcm_key - A key prepared for AES-GCM encryption and decryption
+ */
+struct aes_gcm_key {
+ /* private: */
+ struct aes_enckey aes;
+ struct ghash_key ghash;
+ size_t authtag_len; /* Length of authentication tags in bytes */
+};
+
+/**
+ * struct aes_gcm_ctx - Context for incrementally en/decrypting a message
+ */
+struct aes_gcm_ctx {
+ /* private: */
+ /*
+ * Pointer to the key, which is assumed to live at least as long as this
+ * struct.
+ */
+ const struct aes_gcm_key *key;
+ /* The current GHASH context */
+ struct ghash_ctx ghash;
+ /*
+ * The current counter. This can be viewed as either a 128-bit big
+ * endian counter, or as a 96-bit nonce followed by a 32-bit big endian
+ * counter; it doesn't matter, since the last 32-bit word starts at 1,
+ * and AES-GCM is undefined for messages that would overflow that part.
+ * In practice this means that code optimized for AES-GCM can just
+ * increment the last 32-bit word (wrapping at 2^32), but when needed it
+ * can still call AES-CTR code that does a 128-bit increment.
+ *
+ * 'long' alignment is for crypto_xor() to work more efficiently.
+ */
+ union {
+ u8 ctr[AES_BLOCK_SIZE];
+ __be32 ctr32[AES_BLOCK_SIZE / 4];
+ } __aligned(__alignof__(long));
+ /* Buffered keystream for partial block updates */
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+ /* Encrypted counter of 1. This gets XOR'ed with the tag at the end. */
+ u8 j0_enc[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+ /* Number of associated data bytes processed so far */
+ u64 ad_len;
+ /* Number of en/decrypted bytes processed so far */
+ u64 data_len;
+};
+
+/**
+ * aes_gcm_preparekey() - Prepare a key for AES-GCM encryption and decryption
+ * @key: (output) The key structure to initialize
+ * @in_key: The raw AES-GCM key
+ * @key_len: Length of the raw key in bytes: 16, 24, or 32
+ * @authtag_len: Length of the authentication tag in bytes:
+ * 4, 8, 12, 13, 14, 15, or 16. 16 is recommended.
+ *
+ * Users should use memzero_explicit() to zeroize the key struct at the end of
+ * its lifetime. (But if this function fails, zeroization is unnecessary.)
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success
+ * * -EINVAL if either of the lengths is invalid
+ */
+int __must_check aes_gcm_preparekey(struct aes_gcm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len);
+
+/**
+ * aes_gcm_encrypt() - Encrypt a message with AES-GCM
+ * @dst: The destination ciphertext data. Can be in-place or out-of-place.
+ * For other overlaps the behavior is unspecified.
+ * @src: The source plaintext data
+ * @data_len: Length of plaintext in bytes (and ciphertext excluding the tag):
+ * at most 2^36 - 32
+ * @authtag: The output authentication tag. Length is the authtag_len that was
+ * passed to aes_gcm_preparekey(). Usually protocols using AES-GCM
+ * put the tag at the end of the ciphertext, in which case this should
+ * be set to @dst + @data_len and @dst must have room for the tag.
+ * @ad: The associated data
+ * @ad_len: Length of associated data in bytes: at most 2^61 - 1
+ * @nonce: The 12-byte nonce. All (key, nonce) pairs used MUST be distinct.
+ * @key: The key, already prepared using aes_gcm_preparekey()
+ *
+ * For AES-GMAC (i.e., AES-GCM without any data en/decrypted), use dst=NULL,
+ * src=NULL, and data_len=0 to generate the AES-GMAC value.
+ *
+ * Context: Any context.
+ */
+void aes_gcm_encrypt(u8 *dst, const u8 *src, size_t data_len, u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 nonce[at_least 12],
+ const struct aes_gcm_key *key);
+
+/**
+ * aes_gcm_decrypt() - Decrypt a message with AES-GCM
+ * @dst: The destination plaintext data. Can be in-place or out-of-place.
+ * For other overlaps the behavior is unspecified.
+ * @src: The source ciphertext data
+ * @data_len: Length of plaintext in bytes (and ciphertext excluding the tag):
+ * at most 2^36 - 32
+ * @authtag: The stored authentication tag. Length is the authtag_len that was
+ * passed to aes_gcm_preparekey(). Usually protocols using AES-GCM
+ * put the tag at the end of the ciphertext, in which case this should
+ * be set to @src + @data_len and @src must have room for the tag.
+ * @ad: The associated data
+ * @ad_len: Length of associated data in bytes: at most 2^61 - 1
+ * @nonce: The 12-byte nonce
+ * @key: The key, already prepared using aes_gcm_preparekey()
+ *
+ * For AES-GMAC (i.e., AES-GCM without any data en/decrypted), use dst=NULL,
+ * src=NULL, and data_len=0 to verify the AES-GMAC value.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success. This is the only case where any decrypted or associated data
+ * can be used.
+ * * -EBADMSG if the message is inauthentic
+ */
+int __must_check aes_gcm_decrypt(u8 *dst, const u8 *src, size_t data_len,
+ const u8 *authtag, const u8 *ad, size_t ad_len,
+ const u8 nonce[at_least 12],
+ const struct aes_gcm_key *key);
+
+/**
+ * aes_gcm_init() - Initialize context for incremental AES-GCM encryption or
+ * decryption, or for AES-GMAC computation
+ * @ctx: The context to initialize
+ * @nonce: The 12-byte nonce. All (key, nonce) pairs used for encryption or MAC
+ * generation MUST be distinct.
+ * @key: The key, already prepared using aes_gcm_preparekey(). Note that a
+ * pointer to the key is saved in the context, so the key must live at
+ * least as long as the context.
+ *
+ * The context should be zeroized at the end of its lifetime. Normally that
+ * happens in aes_gcm_encrypt_final() or aes_gcm_decrypt_final(), but callers
+ * that abandon a context without finalizing it should explicitly zeroize it.
+ *
+ * IMPORTANT: Callers that are decrypting data or computing a GMAC value for
+ * verification MUST NOT assume that any decrypted or associated data is
+ * authentic until the authentication tag has been verified. This incremental
+ * API is provided solely to support callers that can't efficiently use the
+ * one-shot functions due to using a nonlinear data layout.
+ *
+ * For incremental AES-GCM encryption, use:
+ *
+ * 1. aes_gcm_init()
+ * 2. aes_gcm_auth_update() (any number of times)
+ * 3. aes_gcm_encrypt_update() (any number of times)
+ * 4. aes_gcm_encrypt_final()
+ *
+ * For incremental AES-GCM decryption, use:
+ *
+ * 1. aes_gcm_init()
+ * 2. aes_gcm_auth_update() (any number of times)
+ * 3. aes_gcm_decrypt_update() (any number of times)
+ * 4. aes_gcm_decrypt_final()
+ *
+ * AES-GMAC is just AES-GCM with zero bytes en/decrypted. For incremental
+ * AES-GMAC computation, use:
+ *
+ * 1. aes_gcm_init()
+ * 2. aes_gcm_auth_update() (any number of times)
+ * 3. aes_gcm_encrypt_final() to return the computed tag to the caller, or
+ * aes_gcm_decrypt_final() to directly verify the computed tag
+ *
+ * Context: Any context.
+ */
+void aes_gcm_init(struct aes_gcm_ctx *ctx, const u8 nonce[at_least 12],
+ const struct aes_gcm_key *key);
+
+/**
+ * aes_gcm_auth_update() - Incrementally process AES-GCM associated data
+ * @ctx: An AES-GCM context
+ * @ad: The associated data
+ * @len: Number of bytes provided. The caller must ensure that the total
+ * associated data length doesn't exceed GCM's limit of 2^61 - 1.
+ *
+ * IMPORTANT: Callers MUST NOT assume that any decrypted or associated data is
+ * authentic until the authentication tag has been verified.
+ *
+ * Context: Any context.
+ */
+void aes_gcm_auth_update(struct aes_gcm_ctx *ctx, const u8 *ad, size_t len);
+
+/**
+ * aes_gcm_encrypt_update() - Incrementally encrypt data with AES-GCM
+ * @ctx: An AES-GCM context
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source plaintext data
+ * @len: Number of bytes to encrypt. The caller must ensure that the total
+ * number of bytes encrypted doesn't exceed GCM's limit of 2^36 - 32.
+ *
+ * This can be called only after all associated data has been processed.
+ *
+ * Context: Any context.
+ */
+void aes_gcm_encrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len);
+
+/**
+ * aes_gcm_decrypt_update() - Incrementally decrypt data with AES-GCM
+ * @ctx: An AES-GCM context
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source ciphertext data (not including auth tag)
+ * @len: Number of bytes to decrypt. The caller must ensure that the total
+ * number of bytes decrypted doesn't exceed GCM's limit of 2^36 - 32.
+ *
+ * This can be called only after all associated data has been processed.
+ *
+ * IMPORTANT: Callers MUST NOT assume that any decrypted or associated data is
+ * authentic until the authentication tag has been verified.
+ *
+ * Context: Any context.
+ */
+void aes_gcm_decrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len);
+
+/**
+ * aes_gcm_encrypt_final() - Finish encrypting a message with AES-GCM
+ * @ctx: An AES-GCM context
+ * @authtag: The output authentication tag. Length is the authtag_len that was
+ * passed to aes_gcm_preparekey().
+ *
+ * This also zeroizes @ctx, so the caller doesn't need to do it.
+ *
+ * Context: Any context.
+ */
+void aes_gcm_encrypt_final(struct aes_gcm_ctx *ctx, u8 *authtag);
+
+/**
+ * aes_gcm_decrypt_final() - Finish decrypting a message with AES-GCM
+ * @ctx: An AES-GCM context
+ * @authtag: The stored authentication tag. Length is the authtag_len that was
+ * passed to aes_gcm_preparekey().
+ *
+ * This also zeroizes @ctx, so the caller doesn't need to do it.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success. This is the only case where any decrypted or associated data
+ * can be used.
+ * * -EBADMSG if the message is inauthentic
+ */
+int __must_check aes_gcm_decrypt_final(struct aes_gcm_ctx *ctx,
+ const u8 *authtag);
+
+#endif /* _CRYPTO_AES_GCM_H */
diff --git a/include/crypto/aes-xts.h b/include/crypto/aes-xts.h
new file mode 100644
index 000000000000..b9e828265e58
--- /dev/null
+++ b/include/crypto/aes-xts.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AES-XTS unauthenticated encryption and decryption
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_XTS_H
+#define _CRYPTO_AES_XTS_H
+
+#include <crypto/aes.h>
+#include <crypto/xts.h>
+
+/**
+ * struct aes_xts_key - A key prepared for AES-XTS encryption and decryption
+ *
+ * Note that (depending on the architecture) this typically is around 768 bytes,
+ * which makes it a bit too large to allocate on the stack in most cases.
+ */
+struct aes_xts_key {
+ /* private: */
+ struct aes_key main_key;
+ struct aes_enckey tweak_key;
+};
+
+/**
+ * aes_xts_preparekey() - Prepare a key for AES-XTS encryption and decryption
+ * @key: (output) The key structure to initialize
+ * @in_key: The raw AES-XTS key
+ * @key_len: Length of the raw key in bytes
+ * @flags: Optional flag XTS_FORBID_WEAK_KEYS to forbid keys whose two halves
+ * are the same.
+ *
+ * Users should use memzero_explicit() to zeroize the key struct at the end of
+ * its lifetime. (But if this function fails, zeroization is unnecessary.)
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 on success
+ * * -EINVAL if the key is rejected because its length isn't 32, 64, or (when
+ * FIPS mode isn't enabled) 48; or because its two halves are the same and
+ * either XTS_FORBID_WEAK_KEYS is given or FIPS mode is enabled.
+ */
+int __must_check aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key,
+ size_t key_len, int flags);
+
+/**
+ * aes_xts_encrypt() - Encrypt data using AES-XTS
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to encrypt. On non-final calls it must be a nonzero
+ * multiple of AES_BLOCK_SIZE. On the final call it can be any value >=
+ * AES_BLOCK_SIZE, i.e. ciphertext stealing is supported.
+ * @tweak: The tweak. It is updated with the next value, unless @len isn't a
+ * multiple of AES_BLOCK_SIZE in which case the value is unspecified.
+ * @key: The key, already prepared using aes_xts_preparekey()
+ * @cont: %false to begin encrypting a new message (do the tweak encryption);
+ * %true to continue encrypting a message (skip tweak encryption)
+ *
+ * This supports both one-shot and incremental encryption. On the first call,
+ * pass @cont = %false. On any later calls, pass @cont = %true and the updated
+ * @tweak; all earlier @len must have been multiples of AES_BLOCK_SIZE.
+ *
+ * Context: Any context.
+ */
+void aes_xts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[at_least AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont);
+
+/**
+ * aes_xts_decrypt() - Decrypt data using AES-XTS
+ * @dst: The destination buffer. Can be in-place or out-of-place. For other
+ * overlaps the behavior is unspecified.
+ * @src: The source data
+ * @len: Number of bytes to decrypt. On non-final calls it must be a nonzero
+ * multiple of AES_BLOCK_SIZE. On the final call it can be any value >=
+ * AES_BLOCK_SIZE, i.e. ciphertext stealing is supported.
+ * @tweak: The tweak. It is updated with the next value, unless @len isn't a
+ * multiple of AES_BLOCK_SIZE in which case the value is unspecified.
+ * @key: The key, already prepared using aes_xts_preparekey()
+ * @cont: %false to begin decrypting a new message (do the tweak encryption);
+ * %true to continue decrypting a message (skip tweak encryption)
+ *
+ * This supports both one-shot and incremental decryption. On the first call,
+ * pass @cont = %false. On any later calls, pass @cont = %true and the updated
+ * @tweak; all earlier @len must have been multiples of AES_BLOCK_SIZE.
+ *
+ * Context: Any context.
+ */
+void aes_xts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[at_least AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont);
+
+#endif /* _CRYPTO_AES_XTS_H */
diff --git a/include/crypto/gcm.h b/include/crypto/gcm.h
index 1d5f39ff1dc4..154038ca7343 100644
--- a/include/crypto/gcm.h
+++ b/include/crypto/gcm.h
@@ -3,9 +3,6 @@
#include <linux/errno.h>
-#include <crypto/aes.h>
-#include <crypto/gf128hash.h>
-
#define GCM_AES_IV_SIZE 12
#define GCM_RFC4106_IV_SIZE 8
#define GCM_RFC4543_IV_SIZE 8
@@ -13,7 +10,7 @@
/*
* validate authentication tag for GCM
*/
-static inline int crypto_gcm_check_authsize(unsigned int authsize)
+static inline int crypto_gcm_check_authsize(size_t authsize)
{
switch (authsize) {
case 4:
@@ -34,7 +31,7 @@ static inline int crypto_gcm_check_authsize(unsigned int authsize)
/*
* validate authentication tag for RFC4106
*/
-static inline int crypto_rfc4106_check_authsize(unsigned int authsize)
+static inline int crypto_rfc4106_check_authsize(size_t authsize)
{
switch (authsize) {
case 8:
@@ -64,22 +61,4 @@ static inline int crypto_ipsec_check_assoclen(unsigned int assoclen)
return 0;
}
-struct aesgcm_ctx {
- struct ghash_key ghash_key;
- struct aes_enckey aes_key;
- unsigned int authsize;
-};
-
-int aesgcm_expandkey(struct aesgcm_ctx *ctx, const u8 *key,
- unsigned int keysize, unsigned int authsize);
-
-void aesgcm_encrypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
- int crypt_len, const u8 *assoc, int assoc_len,
- const u8 iv[GCM_AES_IV_SIZE], u8 *authtag);
-
-bool __must_check aesgcm_decrypt(const struct aesgcm_ctx *ctx, u8 *dst,
- const u8 *src, int crypt_len, const u8 *assoc,
- int assoc_len, const u8 iv[GCM_AES_IV_SIZE],
- const u8 *authtag);
-
#endif
diff --git a/include/crypto/xts.h b/include/crypto/xts.h
index 15b16c4853d8..16aef89f021f 100644
--- a/include/crypto/xts.h
+++ b/include/crypto/xts.h
@@ -7,9 +7,9 @@
#include <linux/fips.h>
#define XTS_BLOCK_SIZE 16
+#define XTS_FORBID_WEAK_KEYS (1 << 0)
-static inline int xts_verify_key(struct crypto_skcipher *tfm,
- const u8 *key, unsigned int keylen)
+static inline int __xts_verify_key(const u8 *key, size_t keylen, int flags)
{
/*
* key consists of keys of equal size concatenated, therefore
@@ -29,12 +29,22 @@ static inline int xts_verify_key(struct crypto_skcipher *tfm,
* Ensure that the AES and tweak key are not identical when
* in FIPS mode or the FORBID_WEAK_KEYS flag is set.
*/
- if ((fips_enabled || (crypto_skcipher_get_flags(tfm) &
- CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) &&
+ if ((fips_enabled || (flags & XTS_FORBID_WEAK_KEYS)) &&
!crypto_memneq(key, key + (keylen / 2), keylen / 2))
return -EINVAL;
return 0;
}
+static inline int xts_verify_key(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ int flags = (crypto_skcipher_get_flags(tfm) &
+ CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) ?
+ XTS_FORBID_WEAK_KEYS :
+ 0;
+
+ return __xts_verify_key(key, keylen, flags);
+}
+
#endif /* _CRYPTO_XTS_H */
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 83d4c95e079e..56f308dd0273 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -8,6 +8,8 @@ config CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES
tristate
+ # Select dependencies of modes that are part of libaes.
+ select CRYPTO_LIB_GF128HASH if CRYPTO_LIB_AES_GCM != n
select CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES_ARCH
@@ -27,6 +29,12 @@ config CRYPTO_LIB_AESCFB
select CRYPTO_LIB_AES
select CRYPTO_LIB_UTILS
+config CRYPTO_LIB_AES_CBC
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-CBC and AES-CBC-CTS library functions.
+
config CRYPTO_LIB_AES_CBC_MACS
tristate
select CRYPTO_LIB_AES
@@ -35,11 +43,38 @@ config CRYPTO_LIB_AES_CBC_MACS
this if your module uses any of the functions from
<crypto/aes-cbc-macs.h>.
-config CRYPTO_LIB_AESGCM
+config CRYPTO_LIB_AES_CCM
tristate
select CRYPTO_LIB_AES
- select CRYPTO_LIB_GF128HASH
- select CRYPTO_LIB_UTILS
+ select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_AES_CTR
+ help
+ The AES-CCM library functions.
+
+config CRYPTO_LIB_AES_CTR
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-CTR and AES-XCTR library functions.
+
+config CRYPTO_LIB_AES_ECB
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-ECB library functions.
+
+config CRYPTO_LIB_AES_GCM
+ tristate
+ select CRYPTO_LIB_AES
+ select CRYPTO_LIB_AES_CTR
+ help
+ The AES-GCM library functions.
+
+config CRYPTO_LIB_AES_XTS
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-XTS library functions.
config CRYPTO_LIB_ARC4
tristate
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index f1e9bf89785f..ca068df1f71f 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -63,9 +63,6 @@ clean-files += powerpc/aesp8-ppc.S
obj-$(CONFIG_CRYPTO_LIB_AESCFB) += libaescfb.o
libaescfb-y := aescfb.o
-obj-$(CONFIG_CRYPTO_LIB_AESGCM) += libaesgcm.o
-libaesgcm-y := aesgcm.o
-
obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
libarc4-y := arc4.o
diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c
index ca733f15b2a8..4222a4cec2f2 100644
--- a/lib/crypto/aes.c
+++ b/lib/crypto/aes.c
@@ -5,7 +5,14 @@
*/
#include <crypto/aes-cbc-macs.h>
+#include <crypto/aes-cbc.h>
+#include <crypto/aes-ccm.h>
+#include <crypto/aes-ctr.h>
+#include <crypto/aes-ecb.h>
+#include <crypto/aes-gcm.h>
+#include <crypto/aes-xts.h>
#include <crypto/aes.h>
+#include <crypto/gf128mul.h>
#include <crypto/utils.h>
#include <linux/cache.h>
#include <linux/crypto.h>
@@ -737,6 +744,1162 @@ static inline void aes_cmac_fips_test(void)
}
#endif /* !CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_ECB)
+/*
+ * Hooks for optimized AES-ECB implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. Returning false
+ * causes the fallback implementation to be used instead.
+ */
+#ifndef aes_ecb_encrypt_arch
+static bool aes_ecb_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_ecb_decrypt_arch
+static bool aes_ecb_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_ecb_encrypt(u8 *dst, const u8 *src, size_t len, aes_encrypt_arg key)
+{
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_ecb_encrypt_arch(dst, src, len, key.enc_key)))
+ return;
+
+ for (size_t i = 0; i < len; i += AES_BLOCK_SIZE)
+ aes_encrypt(key, &dst[i], &src[i]);
+}
+EXPORT_SYMBOL_GPL(aes_ecb_encrypt);
+
+void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len,
+ const struct aes_key *key)
+{
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_ecb_decrypt_arch(dst, src, len, key)))
+ return;
+
+ for (size_t i = 0; i < len; i += AES_BLOCK_SIZE)
+ aes_decrypt(key, &dst[i], &src[i]);
+}
+EXPORT_SYMBOL_GPL(aes_ecb_decrypt);
+#endif /* CONFIG_CRYPTO_LIB_AES_ECB */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC)
+/*
+ * Hooks for optimized AES-CBC implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. Returning false
+ * causes the fallback implementation to be used instead.
+ */
+#ifndef aes_cbc_encrypt_arch
+static bool aes_cbc_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_cbc_decrypt_arch
+static bool aes_cbc_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_cbc_encrypt(u8 *dst, const u8 *src, size_t len, u8 iv[AES_BLOCK_SIZE],
+ aes_encrypt_arg key)
+{
+ const u8 *prev = iv;
+
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_cbc_encrypt_arch(dst, src, len, iv, key.enc_key)))
+ return;
+
+ do {
+ crypto_xor_cpy(dst, src, prev, AES_BLOCK_SIZE);
+ aes_encrypt(key, dst, dst);
+ prev = dst;
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ } while (len);
+ memcpy(iv, prev, AES_BLOCK_SIZE);
+}
+EXPORT_SYMBOL_GPL(aes_cbc_encrypt);
+
+void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len, u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ u8 next_iv[AES_BLOCK_SIZE];
+
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_cbc_decrypt_arch(dst, src, len, iv, key)))
+ return;
+
+ len -= AES_BLOCK_SIZE;
+ dst += len;
+ src += len;
+ memcpy(next_iv, src, AES_BLOCK_SIZE);
+ for (;;) {
+ aes_decrypt(key, dst, src);
+ if (len == 0)
+ break;
+ src -= AES_BLOCK_SIZE;
+ crypto_xor(dst, src, AES_BLOCK_SIZE);
+ dst -= AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ }
+ crypto_xor(dst, iv, AES_BLOCK_SIZE);
+ memcpy(iv, next_iv, AES_BLOCK_SIZE);
+}
+EXPORT_SYMBOL_GPL(aes_cbc_decrypt);
+
+/*
+ * Hooks for optimized AES-CBC-CTS implementations, overridable by the
+ * architecture. They are called with len > AES_BLOCK_SIZE. Returning false
+ * causes the fallback implementation to be used instead. The fallback
+ * implementation still uses the arch-optimized AES-CBC code if available, but
+ * direct implementation of AES-CBC-CTS is helpful on short messages.
+ */
+#ifndef aes_cbc_cts_encrypt_arch
+static bool aes_cbc_cts_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_cbc_cts_decrypt_arch
+static bool aes_cbc_cts_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_cbc_cts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE], aes_encrypt_arg key)
+{
+ /* Offset to P[n] and C[n] (last plaintext and ciphertext block) */
+ size_t pn_offset = round_down(len - 1, AES_BLOCK_SIZE);
+ /* Length of P[n] and C[n], 1 <= pn_len <= AES_BLOCK_SIZE */
+ size_t pn_len = len - pn_offset;
+ u8 tmp[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+ u8 *pad;
+
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (len == AES_BLOCK_SIZE) {
+ aes_cbc_encrypt(dst, src, len, iv, key);
+ return;
+ }
+ if (likely(aes_cbc_cts_encrypt_arch(dst, src, len, iv, key.enc_key)))
+ return;
+
+ /* CBC-encrypt all blocks except the last. */
+ aes_cbc_encrypt(dst, src, pn_offset, iv, key);
+
+ /*
+ * Compute C[n] and C[n - 1].
+ *
+ * Careful: src may equal dst (i.e., the encryption can be in-place), so
+ * src[pn_offset..] can't be read after dst[pn_offset..] is written.
+ */
+ pad = &dst[pn_offset - AES_BLOCK_SIZE];
+ memcpy(tmp, pad, AES_BLOCK_SIZE);
+ crypto_xor(tmp, &src[pn_offset], pn_len);
+ memcpy(&dst[pn_offset], pad, pn_len); /* C[n] */
+ aes_encrypt(key, pad, tmp); /* C[n - 1] */
+
+ memzero_explicit(tmp, sizeof(tmp));
+}
+EXPORT_SYMBOL_GPL(aes_cbc_cts_encrypt);
+
+void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE], const struct aes_key *key)
+{
+ /* Offset to P[n] and C[n] (last plaintext and ciphertext block) */
+ size_t pn_offset = round_down(len - 1, AES_BLOCK_SIZE);
+ /* Length of P[n] and C[n], 1 <= pn_len <= AES_BLOCK_SIZE */
+ size_t pn_len = len - pn_offset;
+ u8 *pad;
+
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (len == AES_BLOCK_SIZE) {
+ aes_cbc_decrypt(dst, src, len, iv, key);
+ return;
+ }
+ if (likely(aes_cbc_cts_decrypt_arch(dst, src, len, iv, key)))
+ return;
+
+ /* Compute P[0]..P[n - 2]. */
+ aes_cbc_decrypt(dst, src, pn_offset - AES_BLOCK_SIZE, iv, key);
+
+ /*
+ * Compute P[n] and P[n - 1].
+ *
+ * Careful: src may equal dst (i.e., the decryption can be in-place), so
+ * src[pn_offset..] can't be read after dst[pn_offset..] is written.
+ *
+ * To avoid needing a temporary buffer, do a "redundant" XOR to recover
+ * src[pn_offset..] from dst[pn_offset..] after the latter is written.
+ */
+ pad = &dst[pn_offset - AES_BLOCK_SIZE];
+ aes_decrypt(key, pad, &src[pn_offset - AES_BLOCK_SIZE]);
+ crypto_xor_cpy(&dst[pn_offset], &src[pn_offset], pad,
+ pn_len); /* P[n] */
+ crypto_xor(pad, &dst[pn_offset], pn_len);
+ aes_decrypt(key, pad, pad);
+ crypto_xor(pad, iv, AES_BLOCK_SIZE); /* P[n - 1] */
+}
+EXPORT_SYMBOL_GPL(aes_cbc_cts_decrypt);
+#endif /* CONFIG_CRYPTO_LIB_AES_CBC */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CTR)
+/*
+ * Hooks for optimized AES-CTR and AES-XCTR implementations, overridable by the
+ * architecture. They are called with any len >= 0. Returning false causes the
+ * fallback implementation to be used instead.
+ */
+#ifndef aes_ctr_arch
+static bool aes_ctr_arch(u8 *dst, const u8 *src, size_t len,
+ u8 ctr[AES_BLOCK_SIZE], const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_xctr_arch
+static bool aes_xctr_arch(u8 *dst, const u8 *src, size_t len, u64 *ctr,
+ const u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+
+static __always_inline void inc_be128_ctr(u8 ctr[AES_BLOCK_SIZE])
+{
+ /*
+ * 255 times out of 256 the first iteration is enough, so unroll the
+ * first iteration as a micro-optimization.
+ */
+ if ((++ctr[AES_BLOCK_SIZE - 1]) != 0)
+ return;
+ for (int i = AES_BLOCK_SIZE - 2; i >= 0; i--) {
+ if (++ctr[i] != 0)
+ break;
+ }
+}
+
+void aes_ctr(u8 *dst, const u8 *src, size_t len, u8 ctr[AES_BLOCK_SIZE],
+ aes_encrypt_arg key)
+{
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ if (likely(aes_ctr_arch(dst, src, len, ctr, key.enc_key)))
+ return;
+
+ /* Handle the full blocks. */
+ for (; len >= AES_BLOCK_SIZE; len -= AES_BLOCK_SIZE) {
+ aes_encrypt(key, keystream, ctr);
+ crypto_xor_cpy(dst, src, keystream, AES_BLOCK_SIZE);
+ inc_be128_ctr(ctr);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ }
+ /* Handle any partial block at the end. */
+ if (len) {
+ aes_encrypt(key, keystream, ctr);
+ crypto_xor_cpy(dst, src, keystream, len);
+ /* Counter is incremented even with just a partial block. */
+ inc_be128_ctr(ctr);
+ }
+ memzero_explicit(keystream, sizeof(keystream));
+}
+EXPORT_SYMBOL_GPL(aes_ctr);
+
+void aes_xctr(u8 *dst, const u8 *src, size_t len, u64 *ctr,
+ const u8 iv[AES_BLOCK_SIZE], aes_encrypt_arg key)
+{
+ const __le64 iv0 = get_unaligned((const __le64 *)&iv[0]);
+ __le64 aes_input[2];
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ if (likely(aes_xctr_arch(dst, src, len, ctr, iv, key.enc_key)))
+ return;
+
+ aes_input[1] = get_unaligned((const __le64 *)&iv[8]);
+ /* Handle the full blocks. */
+ for (; len >= AES_BLOCK_SIZE; len -= AES_BLOCK_SIZE) {
+ aes_input[0] = iv0 ^ cpu_to_le64((*ctr)++);
+ aes_encrypt(key, keystream, (const u8 *)aes_input);
+ crypto_xor_cpy(dst, src, keystream, AES_BLOCK_SIZE);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ }
+ /* Handle any partial block at the end. */
+ if (len) {
+ /* Counter is incremented even with just a partial block. */
+ aes_input[0] = iv0 ^ cpu_to_le64((*ctr)++);
+ aes_encrypt(key, keystream, (const u8 *)aes_input);
+ crypto_xor_cpy(dst, src, keystream, len);
+ }
+ memzero_explicit(keystream, sizeof(keystream));
+ memzero_explicit(aes_input, sizeof(aes_input));
+}
+EXPORT_SYMBOL_GPL(aes_xctr);
+#endif /* CONFIG_CRYPTO_LIB_AES_CTR */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS)
+int aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key,
+ size_t key_len, int flags)
+{
+ int err;
+
+ err = __xts_verify_key(in_key, key_len, flags);
+ if (unlikely(err))
+ goto out_zeroize;
+ /* First half of XTS key is the main key */
+ err = aes_preparekey(&key->main_key, in_key, key_len / 2);
+ if (unlikely(err))
+ goto out_zeroize;
+ /* Second half of XTS key is the tweak key */
+ err = aes_prepareenckey(&key->tweak_key, &in_key[key_len / 2],
+ key_len / 2);
+ if (unlikely(err))
+ goto out_zeroize;
+ return 0;
+
+out_zeroize:
+ memzero_explicit(key, sizeof(*key));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_xts_preparekey);
+
+/*
+ * Hooks for optimized AES-XTS implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. In other words,
+ * they aren't expected to handle ciphertext stealing or empty inputs.
+ * Returning false causes the fallback implementation to be used instead.
+ *
+ * (Currently, all users of AES-XTS in the kernel seem to en/decrypt whole
+ * numbers of blocks anyway, with len >= 512. So there's no need to heavily
+ * optimize ciphertext stealing for short messages.)
+ */
+#ifndef aes_xts_encrypt_arch
+static bool aes_xts_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont)
+{
+ return false;
+}
+#endif
+#ifndef aes_xts_decrypt_arch
+static bool aes_xts_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont)
+{
+ return false;
+}
+#endif
+
+static noinline void aes_xts_crypt_nocts_blockbyblock(
+ u8 *dst, const u8 *src, size_t len, u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont, bool enc)
+{
+ le128 t;
+
+ if (cont)
+ memcpy(&t, tweak, sizeof(t));
+ else
+ aes_encrypt(&key->tweak_key, (u8 *)&t, tweak);
+ do {
+ crypto_xor_cpy(dst, src, (const u8 *)&t, AES_BLOCK_SIZE);
+ if (enc)
+ aes_encrypt(&key->main_key, dst, dst);
+ else
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, (const u8 *)&t, AES_BLOCK_SIZE);
+ gf128mul_x_ble(&t, &t);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ } while (len);
+ memcpy(tweak, &t, sizeof(t));
+ memzero_explicit(&t, sizeof(t));
+}
+
+/* Requires len > 0 && len % AES_BLOCK_SIZE == 0 */
+static __always_inline void aes_xts_encrypt_nocts(u8 *dst, const u8 *src,
+ size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ if (likely(aes_xts_encrypt_arch(dst, src, len, tweak, key, cont)))
+ return;
+
+ /*
+ * For the fallback, just go block-by-block. It could be implemented on
+ * top of AES-ECB, which could be significantly faster than this if the
+ * arch has optimized AES-ECB code but not AES-XTS. However, AES-XTS
+ * performance is important enough that it needs to be (and has been)
+ * implemented directly by every non-obsolete arch anyway.
+ */
+ aes_xts_crypt_nocts_blockbyblock(dst, src, len, tweak, key, cont,
+ /* enc= */ true);
+}
+
+/* Requires len > 0 && len % AES_BLOCK_SIZE == 0 */
+static __always_inline void aes_xts_decrypt_nocts(u8 *dst, const u8 *src,
+ size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ if (likely(aes_xts_decrypt_arch(dst, src, len, tweak, key, cont)))
+ return;
+
+ /* Just go block-by-block. See comment in aes_xts_encrypt_nocts(). */
+ aes_xts_crypt_nocts_blockbyblock(dst, src, len, tweak, key, cont,
+ /* enc= */ false);
+}
+
+static noinline void aes_xts_encrypt_cts(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ size_t partial_len = len % AES_BLOCK_SIZE; /* Length of partial block */
+ size_t nocts_len = round_down(len, AES_BLOCK_SIZE);
+ u8 tmp_block[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ /* Encrypt all full blocks. */
+ aes_xts_encrypt_nocts(dst, src, nocts_len, tweak, key, cont);
+ dst += nocts_len - AES_BLOCK_SIZE;
+ src += nocts_len - AES_BLOCK_SIZE;
+
+ /*
+ * Swap the partial block with the first 'partial_len' bytes of the
+ * encrypted last full block. Note that a temporary buffer is needed to
+ * support in-place encryption.
+ */
+ memcpy(tmp_block, src + AES_BLOCK_SIZE, partial_len);
+ memcpy(dst + AES_BLOCK_SIZE, dst, partial_len);
+ memcpy(dst, tmp_block, partial_len);
+
+ /* Encrypt the last full block again. */
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ aes_encrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ memzero_explicit(tmp_block, sizeof(tmp_block));
+}
+
+static noinline void aes_xts_decrypt_cts(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ size_t partial_len = len % AES_BLOCK_SIZE; /* Length of partial block */
+ size_t nocts_len = round_down(len, AES_BLOCK_SIZE) - AES_BLOCK_SIZE;
+ union {
+ u8 block[AES_BLOCK_SIZE];
+ le128 tweak;
+ } tmp __aligned(__alignof__(long));
+
+ /*
+ * Decrypt all blocks except the last full block and the partial block.
+ * The last full block has to be handled specially because decryption
+ * ciphertext stealing uses the last two tweaks in reverse order.
+ *
+ * nocts_len == 0 is possible here, which aes_xts_decrypt_nocts()
+ * doesn't handle (so that the length doesn't get checked redundantly in
+ * the fast path). So handle that case specially as well.
+ */
+ if (nocts_len)
+ aes_xts_decrypt_nocts(dst, src, nocts_len, tweak, key, cont);
+ else if (!cont)
+ aes_encrypt(&key->tweak_key, tweak, tweak);
+ dst += nocts_len;
+ src += nocts_len;
+
+ /* Copy the tweak, advance it again, then decrypt last full block. */
+ memcpy(&tmp.tweak, tweak, AES_BLOCK_SIZE);
+ gf128mul_x_ble(&tmp.tweak, &tmp.tweak);
+ crypto_xor_cpy(dst, src, tmp.block, AES_BLOCK_SIZE);
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tmp.block, AES_BLOCK_SIZE);
+
+ /*
+ * Swap the partial block with the first 'partial_len' bytes of the
+ * decrypted last full block. Note that a temporary buffer is needed to
+ * support in-place decryption.
+ */
+ memcpy(tmp.block, src + AES_BLOCK_SIZE, partial_len);
+ memcpy(dst + AES_BLOCK_SIZE, dst, partial_len);
+ memcpy(dst, tmp.block, partial_len);
+
+ /* Decrypt the last full block again. */
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ memzero_explicit(&tmp, sizeof(tmp));
+}
+
+void aes_xts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE], const struct aes_xts_key *key,
+ bool cont)
+{
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (unlikely(len % AES_BLOCK_SIZE)) {
+ aes_xts_encrypt_cts(dst, src, len, tweak, key, cont);
+ return;
+ }
+
+ aes_xts_encrypt_nocts(dst, src, len, tweak, key, cont);
+}
+EXPORT_SYMBOL_GPL(aes_xts_encrypt);
+
+void aes_xts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE], const struct aes_xts_key *key,
+ bool cont)
+{
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (unlikely(len % AES_BLOCK_SIZE)) {
+ aes_xts_decrypt_cts(dst, src, len, tweak, key, cont);
+ return;
+ }
+
+ aes_xts_decrypt_nocts(dst, src, len, tweak, key, cont);
+}
+EXPORT_SYMBOL_GPL(aes_xts_decrypt);
+#endif /* CONFIG_CRYPTO_LIB_AES_XTS */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_GCM)
+/*
+ * Hooks for optimized AES-GCM implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. I.e. they aren't
+ * expected to handle empty inputs or partial blocks, as those cases are handled
+ * by non-arch-specific code instead.
+ *
+ * The GHASH accumulator is provided in POLYVAL format. The counter is provided
+ * in big endian format, and it's read-only, as the caller handles updating it.
+ *
+ * Returning false causes the fallback implementation to be used instead.
+ *
+ * These hooks are used only for en/decrypted data. For the associated data the
+ * GHASH functions are called instead, so those should be implemented too.
+ */
+#ifndef aes_gcm_encrypt_update_arch
+static bool aes_gcm_encrypt_update_arch(u8 *dst, const u8 *src, size_t len,
+ struct polyval_elem *ghash_acc,
+ const __be32 ctr32[4],
+ const struct aes_enckey *aes_key,
+ const struct ghash_key *ghash_key)
+{
+ return false;
+}
+#endif
+#ifndef aes_gcm_decrypt_update_arch
+static bool aes_gcm_decrypt_update_arch(u8 *dst, const u8 *src, size_t len,
+ struct polyval_elem *ghash_acc,
+ const __be32 ctr32[4],
+ const struct aes_enckey *aes_key,
+ const struct ghash_key *ghash_key)
+{
+ return false;
+}
+#endif
+
+int aes_gcm_preparekey(struct aes_gcm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len)
+{
+ u8 h[AES_BLOCK_SIZE] = { 0 };
+ int err;
+
+ err = crypto_gcm_check_authsize(authtag_len);
+ if (unlikely(err))
+ return err;
+
+ err = aes_prepareenckey(&key->aes, in_key, key_len);
+ if (unlikely(err))
+ return err;
+
+ aes_encrypt(&key->aes, h, h);
+ ghash_preparekey(&key->ghash, h);
+
+ key->authtag_len = authtag_len;
+
+ memzero_explicit(h, sizeof(h));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_preparekey);
+
+void aes_gcm_init(struct aes_gcm_ctx *ctx, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ ctx->key = key;
+ ctx->ad_len = 0;
+ ctx->data_len = 0;
+ ghash_init(&ctx->ghash, &key->ghash);
+ memset(ctx->keystream, 0, sizeof(ctx->keystream));
+
+ memcpy(ctx->ctr32, nonce, 12);
+ ctx->ctr32[3] = cpu_to_be32(1);
+
+ aes_encrypt(&key->aes, ctx->j0_enc, ctx->ctr);
+ ctx->ctr32[3] = cpu_to_be32(2);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_init);
+
+void aes_gcm_auth_update(struct aes_gcm_ctx *ctx, const u8 *ad, size_t len)
+{
+ WARN_ON_ONCE(ctx->data_len != 0);
+ if (len) {
+ ghash_update(&ctx->ghash, ad, len);
+ ctx->ad_len += len;
+ }
+}
+EXPORT_SYMBOL_GPL(aes_gcm_auth_update);
+
+static const u8 gcm_zeroes[AES_BLOCK_SIZE];
+
+static __always_inline void ghash_pad(struct ghash_ctx *ghash, u64 len)
+{
+ if (len % AES_BLOCK_SIZE)
+ ghash_update(ghash, gcm_zeroes, -len % AES_BLOCK_SIZE);
+}
+
+static __always_inline void aes_gcm_crypt_update(struct aes_gcm_ctx *ctx,
+ u8 *dst, const u8 *src,
+ size_t len, bool enc)
+{
+ size_t partial_len, n;
+
+ if (unlikely(len == 0))
+ return;
+
+ partial_len = ctx->data_len % AES_BLOCK_SIZE;
+ if (ctx->data_len == 0)
+ ghash_pad(&ctx->ghash, ctx->ad_len);
+ ctx->data_len += len;
+
+ if (unlikely(partial_len != 0)) {
+ /*
+ * The previous call ended on a non-block-aligned data_len, so
+ * continue using a previously-generated keystream block.
+ */
+ n = min(len, AES_BLOCK_SIZE - partial_len);
+ if (enc) {
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len],
+ n);
+ ghash_update(&ctx->ghash, dst, n);
+ } else {
+ ghash_update(&ctx->ghash, src, n);
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len],
+ n);
+ }
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len >= AES_BLOCK_SIZE) {
+ n = round_down(len, AES_BLOCK_SIZE);
+ if (enc) {
+ if (likely(aes_gcm_encrypt_update_arch(
+ dst, src, n, &ctx->ghash.acc, ctx->ctr32,
+ &ctx->key->aes, &ctx->key->ghash))) {
+ be32_add_cpu(&ctx->ctr32[3],
+ n / AES_BLOCK_SIZE);
+ } else {
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ ghash_update(&ctx->ghash, dst, n);
+ }
+ } else {
+ if (likely(aes_gcm_decrypt_update_arch(
+ dst, src, n, &ctx->ghash.acc, ctx->ctr32,
+ &ctx->key->aes, &ctx->key->ghash))) {
+ be32_add_cpu(&ctx->ctr32[3],
+ n / AES_BLOCK_SIZE);
+ } else {
+ ghash_update(&ctx->ghash, src, n);
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ }
+ }
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len != 0) {
+ /*
+ * Ending on a non-block aligned data_len. Generate the next
+ * keystream block, use the needed portion of it, and leave it
+ * cached in ctx->keystream in case this isn't the final call.
+ */
+ aes_encrypt(&ctx->key->aes, ctx->keystream, ctx->ctr);
+ be32_add_cpu(&ctx->ctr32[3], 1);
+ if (enc) {
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ ghash_update(&ctx->ghash, dst, len);
+ } else {
+ ghash_update(&ctx->ghash, src, len);
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ }
+ }
+}
+
+void aes_gcm_encrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_gcm_crypt_update(ctx, dst, src, len, /* enc= */ true);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt_update);
+
+void aes_gcm_decrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_gcm_crypt_update(ctx, dst, src, len, /* enc= */ false);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt_update);
+
+/* Maximum AES-GCM associated data length in bytes */
+#define AES_GCM_MAX_AD_LEN ((1ULL << 61) - 1)
+/* Maximum AES-GCM en/decrypted data length in bytes */
+#define AES_GCM_MAX_DATA_LEN ((1ULL << 36) - 32)
+
+void aes_gcm_encrypt_final(struct aes_gcm_ctx *ctx, u8 *authtag)
+{
+ __be64 tail[2];
+
+ WARN_ON_ONCE(ctx->ad_len > AES_GCM_MAX_AD_LEN);
+ WARN_ON_ONCE(ctx->data_len > AES_GCM_MAX_DATA_LEN);
+
+ ghash_pad(&ctx->ghash,
+ ctx->data_len == 0 ? ctx->ad_len : ctx->data_len);
+
+ tail[0] = cpu_to_be64(ctx->ad_len * 8);
+ tail[1] = cpu_to_be64(ctx->data_len * 8);
+ ghash_update(&ctx->ghash, (const u8 *)tail, 16);
+ ghash_final(&ctx->ghash, ctx->ctr); /* Use ctr as temp buffer */
+
+ crypto_xor_cpy(authtag, ctx->ctr, ctx->j0_enc, ctx->key->authtag_len);
+ memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt_final);
+
+int aes_gcm_decrypt_final(struct aes_gcm_ctx *ctx, const u8 *authtag)
+{
+ __be64 tail[2];
+ int err;
+
+ if (WARN_ON_ONCE(ctx->ad_len > AES_GCM_MAX_AD_LEN) ||
+ WARN_ON_ONCE(ctx->data_len > AES_GCM_MAX_DATA_LEN)) {
+ err = -EBADMSG;
+ goto out;
+ }
+
+ ghash_pad(&ctx->ghash,
+ ctx->data_len == 0 ? ctx->ad_len : ctx->data_len);
+
+ tail[0] = cpu_to_be64(ctx->ad_len * 8);
+ tail[1] = cpu_to_be64(ctx->data_len * 8);
+ ghash_update(&ctx->ghash, (const u8 *)tail, 16);
+ ghash_final(&ctx->ghash, ctx->ctr); /* Use ctr as temp buffer */
+ crypto_xor(ctx->ctr, ctx->j0_enc, ctx->key->authtag_len);
+ err = crypto_memneq(ctx->ctr, authtag, ctx->key->authtag_len) ?
+ -EBADMSG :
+ 0;
+out:
+ memzero_explicit(ctx, sizeof(*ctx));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt_final);
+
+void aes_gcm_encrypt(u8 *dst, const u8 *src, size_t data_len, u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ struct aes_gcm_ctx ctx;
+
+ aes_gcm_init(&ctx, nonce, key);
+ aes_gcm_auth_update(&ctx, ad, ad_len);
+ aes_gcm_encrypt_update(&ctx, dst, src, data_len);
+ aes_gcm_encrypt_final(&ctx, authtag);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt);
+
+int aes_gcm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ struct aes_gcm_ctx ctx;
+ int err;
+
+ aes_gcm_init(&ctx, nonce, key);
+ aes_gcm_auth_update(&ctx, ad, ad_len);
+ aes_gcm_decrypt_update(&ctx, dst, src, data_len);
+ err = aes_gcm_decrypt_final(&ctx, authtag);
+ if (unlikely(err) && data_len) {
+ /*
+ * Clear the inauthentic decrypted data so that callers won't
+ * receive it even if they fail to correctly handle errors.
+ */
+ memset(dst, 0, data_len);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt);
+
+#endif /* CONFIG_CRYPTO_LIB_AES_GCM */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CCM)
+int aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len)
+{
+ int err;
+
+ if (unlikely(authtag_len < 4 || authtag_len > 16 || authtag_len % 2))
+ return -EINVAL;
+
+ err = aes_prepareenckey(&key->aes, in_key, key_len);
+ if (unlikely(err))
+ return err;
+
+ key->authtag_len = authtag_len;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_preparekey);
+
+int aes_ccm_init(struct aes_ccm_ctx *ctx, u64 data_len, u64 ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_ccm_key *key)
+{
+ /*
+ * This is the value L defined in the CCM specification. It determines
+ * the maximum allowed message length, and it is itself determined by
+ * the nonce length. They are inversely related, i.e. the longer the
+ * nonce the smaller the maximum message length is.
+ */
+ unsigned int l = 15 - nonce_len;
+
+ if (unlikely(nonce_len < 7 || nonce_len > 13))
+ return -EINVAL;
+ /* Thus 2 <= l <= 8. */
+
+ /* Check whether data_len can be represented in 'l' bytes. */
+ if (unlikely(data_len > U64_MAX >> (64 - 8 * l)))
+ return -EOVERFLOW;
+
+ ctx->key = key;
+ ctx->ad_remaining = ad_len;
+ ctx->data_remaining = data_len;
+ ctx->ad_padded = false;
+
+ /*
+ * Initialize the zero-th counter block to:
+ *
+ * L - 1 || nonce || 0
+ *
+ * ... and the zero-th CBC-MAC block to:
+ *
+ * Flags || nonce || data_len
+ */
+ *(__be64 *)&ctx->ctr[8] = 0;
+ *(__be64 *)&ctx->mac[8] = cpu_to_be64(data_len);
+ ctx->ctr[0] = l - 1;
+ ctx->mac[0] = (ad_len ? 0x40 : 0) |
+ (((key->authtag_len - 2) / 2) << 3) | (l - 1);
+ memcpy(&ctx->ctr[1], nonce, nonce_len); /* Overlapping store */
+ memcpy(&ctx->mac[1], nonce, nonce_len); /* Overlapping store */
+
+ /*
+ * Generate S_0 by encrypting the counter (this is used to encrypt the
+ * auth tag later), and encrypt the zero-th CBC-MAC block.
+ */
+ aes_encrypt(&key->aes, ctx->s0, ctx->ctr);
+ aes_encrypt(&key->aes, ctx->mac, ctx->mac);
+
+ /* Increment the counter from 0 to 1. */
+ ctx->ctr[15] = 1;
+
+ if (ad_len) {
+ /*
+ * Update CBC-MAC with the associated data length, represented
+ * using either 2, 6, or 10 bytes depending on the length.
+ */
+ if (likely(ad_len < 0xff00)) {
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(ad_len);
+ ctx->partial_len = 2;
+ } else if (ad_len <= U32_MAX) {
+ __be32 *p = (__be32 *)&ctx->mac[2];
+
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(0xfffe);
+ put_unaligned(get_unaligned(p) ^ cpu_to_be32(ad_len),
+ p);
+ ctx->partial_len = 6;
+ } else {
+ __be64 *p = (__be64 *)&ctx->mac[2];
+
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(0xffff);
+ put_unaligned(get_unaligned(p) ^ cpu_to_be64(ad_len),
+ p);
+ ctx->partial_len = 10;
+ }
+ } else {
+ ctx->partial_len = 0;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_init);
+
+void aes_ccm_auth_update(struct aes_ccm_ctx *ctx, const u8 *ad, size_t len)
+{
+ size_t partial_len = ctx->partial_len;
+ bool enc_before = false;
+ size_t nblocks;
+
+ WARN_ON_ONCE(ctx->ad_padded);
+
+ /*
+ * We could warn on len > ad_remaining here, but underflow will be
+ * caught by the != 0 check at the end anyway. (It's a u64, so it isn't
+ * going to underflow all the way back to 0.)
+ */
+ ctx->ad_remaining -= len;
+
+ if (partial_len) {
+ size_t n = min(len, AES_BLOCK_SIZE - partial_len);
+
+ crypto_xor(&ctx->mac[partial_len], ad, n);
+ ad += n;
+ len -= n;
+ partial_len += n;
+ if (partial_len < AES_BLOCK_SIZE) {
+ ctx->partial_len = partial_len;
+ return;
+ }
+ enc_before = true;
+ }
+
+ nblocks = len / AES_BLOCK_SIZE;
+ len %= AES_BLOCK_SIZE;
+ if (nblocks == 0) {
+ if (enc_before)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ } else {
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, ad, nblocks,
+ enc_before, /* enc_after= */ true);
+ ad += nblocks * AES_BLOCK_SIZE;
+ }
+ crypto_xor(ctx->mac, ad, len);
+ ctx->partial_len = len;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_auth_update);
+
+static __always_inline void aes_ccm_crypt_update(struct aes_ccm_ctx *ctx,
+ u8 *dst, const u8 *src,
+ size_t len, bool enc)
+{
+ size_t partial_len = ctx->partial_len;
+ size_t n, nblocks;
+
+ if (unlikely(len == 0))
+ return;
+
+ WARN_ON_ONCE(ctx->ad_remaining != 0);
+
+ /*
+ * We could warn on len > data_remaining here, but underflow will be
+ * caught by the != 0 check at the end anyway. (It's a u64, so it isn't
+ * going to underflow all the way back to 0.)
+ */
+ ctx->data_remaining -= len;
+
+ if (!ctx->ad_padded) {
+ ctx->ad_padded = true;
+ if (partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ } else if (partial_len) {
+ /*
+ * The previous call ended on a non-block-aligned data_len, so
+ * continue using a previously-generated keystream block.
+ */
+ n = min(len, AES_BLOCK_SIZE - partial_len);
+ if (enc)
+ crypto_xor(&ctx->mac[partial_len], src, n);
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len], n);
+ if (!enc)
+ crypto_xor(&ctx->mac[partial_len], dst, n);
+ dst += n;
+ src += n;
+ len -= n;
+ partial_len += n;
+ if (partial_len < AES_BLOCK_SIZE) {
+ ctx->partial_len = partial_len;
+ return;
+ }
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ }
+
+ if (len >= AES_BLOCK_SIZE) {
+ n = round_down(len, AES_BLOCK_SIZE);
+ nblocks = len / AES_BLOCK_SIZE;
+ if (enc)
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, src,
+ nblocks, /* enc_before= */ false,
+ /* enc_after= */ true);
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ if (!enc)
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, dst,
+ nblocks, /* enc_before= */ false,
+ /* enc_after= */ true);
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len) {
+ /*
+ * Ending on a non-block aligned data_len. Generate the next
+ * keystream block, use the needed portion of it, and leave it
+ * cached in ctx->keystream in case this isn't the final call.
+ */
+ aes_encrypt(&ctx->key->aes, ctx->keystream, ctx->ctr);
+ inc_be128_ctr(ctx->ctr);
+ if (enc)
+ crypto_xor(ctx->mac, src, len);
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ if (!enc)
+ crypto_xor(ctx->mac, dst, len);
+ }
+ ctx->partial_len = len;
+}
+
+void aes_ccm_encrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_ccm_crypt_update(ctx, dst, src, len, /* enc= */ true);
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt_update);
+
+void aes_ccm_decrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_ccm_crypt_update(ctx, dst, src, len, /* enc= */ false);
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt_update);
+
+void aes_ccm_encrypt_final(struct aes_ccm_ctx *ctx, u8 *authtag)
+{
+ WARN_ON_ONCE(ctx->ad_remaining != 0);
+ WARN_ON_ONCE(ctx->data_remaining != 0);
+ if (ctx->partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ crypto_xor_cpy(authtag, ctx->mac, ctx->s0, ctx->key->authtag_len);
+ memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt_final);
+
+int aes_ccm_decrypt_final(struct aes_ccm_ctx *ctx, const u8 *authtag)
+{
+ int err;
+
+ if (WARN_ON_ONCE(ctx->ad_remaining != 0) ||
+ WARN_ON_ONCE(ctx->data_remaining != 0)) {
+ err = -EBADMSG;
+ goto out;
+ }
+
+ if (ctx->partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ crypto_xor(ctx->mac, ctx->s0, ctx->key->authtag_len);
+ err = crypto_memneq(ctx->mac, authtag, ctx->key->authtag_len) ?
+ -EBADMSG :
+ 0;
+out:
+ memzero_explicit(ctx, sizeof(*ctx));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt_final);
+
+int aes_ccm_encrypt(u8 *dst, const u8 *src, size_t data_len, u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct aes_ccm_key *key)
+{
+ struct aes_ccm_ctx ctx;
+ int err;
+
+ err = aes_ccm_init(&ctx, data_len, ad_len, nonce, nonce_len, key);
+ if (unlikely(err))
+ return err;
+ aes_ccm_auth_update(&ctx, ad, ad_len);
+ aes_ccm_encrypt_update(&ctx, dst, src, data_len);
+ aes_ccm_encrypt_final(&ctx, authtag);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt);
+
+int aes_ccm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct aes_ccm_key *key)
+{
+ struct aes_ccm_ctx ctx;
+ int err;
+
+ err = aes_ccm_init(&ctx, data_len, ad_len, nonce, nonce_len, key);
+ if (unlikely(err))
+ return err;
+ aes_ccm_auth_update(&ctx, ad, ad_len);
+ aes_ccm_decrypt_update(&ctx, dst, src, data_len);
+ err = aes_ccm_decrypt_final(&ctx, authtag);
+ if (unlikely(err) && data_len) {
+ /*
+ * Clear the inauthentic decrypted data so that callers won't
+ * receive it even if they fail to correctly handle errors.
+ */
+ memset(dst, 0, data_len);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt);
+#endif /* CONFIG_CRYPTO_LIB_AES_CCM */
+
static int __init aes_mod_init(void)
{
#ifdef aes_mod_init_arch
diff --git a/lib/crypto/aesgcm.c b/lib/crypto/aesgcm.c
deleted file mode 100644
index 1da31e1f747d..000000000000
--- a/lib/crypto/aesgcm.c
+++ /dev/null
@@ -1,721 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Minimal library implementation of GCM
- *
- * Copyright 2022 Google LLC
- */
-
-#include <crypto/gcm.h>
-#include <crypto/utils.h>
-#include <linux/export.h>
-#include <linux/module.h>
-
-/**
- * aesgcm_expandkey - Expands the AES and GHASH keys for the AES-GCM key
- * schedule
- *
- * @ctx: The data structure that will hold the AES-GCM key schedule
- * @key: The AES encryption input key
- * @keysize: The length in bytes of the input key
- * @authsize: The size in bytes of the GCM authentication tag
- *
- * Returns: 0 on success, or -EINVAL if @keysize or @authsize contain values
- * that are not permitted by the GCM specification.
- */
-int aesgcm_expandkey(struct aesgcm_ctx *ctx, const u8 *key,
- unsigned int keysize, unsigned int authsize)
-{
- u8 h[AES_BLOCK_SIZE] = {};
- int ret;
-
- ret = crypto_gcm_check_authsize(authsize) ?:
- aes_prepareenckey(&ctx->aes_key, key, keysize);
- if (ret)
- return ret;
-
- ctx->authsize = authsize;
- aes_encrypt(&ctx->aes_key, h, h);
- ghash_preparekey(&ctx->ghash_key, h);
- memzero_explicit(h, sizeof(h));
- return 0;
-}
-EXPORT_SYMBOL(aesgcm_expandkey);
-
-/**
- * aesgcm_mac - Generates the authentication tag using AES-GCM algorithm.
- * @ctx: The data structure that will hold the AES-GCM key schedule
- * @src: The input source data.
- * @src_len: Length of the source data.
- * @assoc: Points to the associated data.
- * @assoc_len: Length of the associated data values.
- * @ctr: Points to the counter value.
- * @authtag: The output buffer for the authentication tag.
- *
- * It takes in the AES-GCM context, source data, associated data, counter value,
- * and an output buffer for the authentication tag.
- */
-static void aesgcm_mac(const struct aesgcm_ctx *ctx, const u8 *src, int src_len,
- const u8 *assoc, int assoc_len, __be32 *ctr, u8 *authtag)
-{
- static const u8 zeroes[GHASH_BLOCK_SIZE];
- __be64 tail[2] = {
- cpu_to_be64((u64)assoc_len * 8),
- cpu_to_be64((u64)src_len * 8),
- };
- struct ghash_ctx ghash;
- u8 ghash_out[AES_BLOCK_SIZE];
- u8 enc_ctr[AES_BLOCK_SIZE];
-
- ghash_init(&ghash, &ctx->ghash_key);
-
- ghash_update(&ghash, assoc, assoc_len);
- ghash_update(&ghash, zeroes, -assoc_len & (GHASH_BLOCK_SIZE - 1));
-
- ghash_update(&ghash, src, src_len);
- ghash_update(&ghash, zeroes, -src_len & (GHASH_BLOCK_SIZE - 1));
-
- ghash_update(&ghash, (const u8 *)&tail, sizeof(tail));
-
- ghash_final(&ghash, ghash_out);
-
- ctr[3] = cpu_to_be32(1);
- aes_encrypt(&ctx->aes_key, enc_ctr, (const u8 *)ctr);
- crypto_xor_cpy(authtag, ghash_out, enc_ctr, ctx->authsize);
-
- memzero_explicit(ghash_out, sizeof(ghash_out));
- memzero_explicit(enc_ctr, sizeof(enc_ctr));
-}
-
-static void aesgcm_crypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
- int len, __be32 *ctr)
-{
- u8 buf[AES_BLOCK_SIZE];
- unsigned int n = 2;
-
- while (len > 0) {
- /*
- * The counter increment below must not result in overflow or
- * carry into the next 32-bit word, as this could result in
- * inadvertent IV reuse, which must be avoided at all cost for
- * stream ciphers such as AES-CTR. Given the range of 'int
- * len', this cannot happen, so no explicit test is necessary.
- */
- ctr[3] = cpu_to_be32(n++);
- aes_encrypt(&ctx->aes_key, buf, (const u8 *)ctr);
- crypto_xor_cpy(dst, src, buf, min(len, AES_BLOCK_SIZE));
-
- dst += AES_BLOCK_SIZE;
- src += AES_BLOCK_SIZE;
- len -= AES_BLOCK_SIZE;
- }
- memzero_explicit(buf, sizeof(buf));
-}
-
-/**
- * aesgcm_encrypt - Perform AES-GCM encryption on a block of data
- *
- * @ctx: The AES-GCM key schedule
- * @dst: Pointer to the ciphertext output buffer
- * @src: Pointer the plaintext (may equal @dst for encryption in place)
- * @crypt_len: The size in bytes of the plaintext and ciphertext.
- * @assoc: Pointer to the associated data,
- * @assoc_len: The size in bytes of the associated data
- * @iv: The initialization vector (IV) to use for this block of data
- * (must be 12 bytes in size as per the GCM spec recommendation)
- * @authtag: The address of the buffer in memory where the authentication
- * tag should be stored. The buffer is assumed to have space for
- * @ctx->authsize bytes.
- */
-void aesgcm_encrypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
- int crypt_len, const u8 *assoc, int assoc_len,
- const u8 iv[GCM_AES_IV_SIZE], u8 *authtag)
-{
- __be32 ctr[4];
-
- memcpy(ctr, iv, GCM_AES_IV_SIZE);
-
- aesgcm_crypt(ctx, dst, src, crypt_len, ctr);
- aesgcm_mac(ctx, dst, crypt_len, assoc, assoc_len, ctr, authtag);
-}
-EXPORT_SYMBOL(aesgcm_encrypt);
-
-/**
- * aesgcm_decrypt - Perform AES-GCM decryption on a block of data
- *
- * @ctx: The AES-GCM key schedule
- * @dst: Pointer to the plaintext output buffer
- * @src: Pointer the ciphertext (may equal @dst for decryption in place)
- * @crypt_len: The size in bytes of the plaintext and ciphertext.
- * @assoc: Pointer to the associated data,
- * @assoc_len: The size in bytes of the associated data
- * @iv: The initialization vector (IV) to use for this block of data
- * (must be 12 bytes in size as per the GCM spec recommendation)
- * @authtag: The address of the buffer in memory where the authentication
- * tag is stored.
- *
- * Returns: true on success, or false if the ciphertext failed authentication.
- * On failure, no plaintext will be returned.
- */
-bool __must_check aesgcm_decrypt(const struct aesgcm_ctx *ctx, u8 *dst,
- const u8 *src, int crypt_len, const u8 *assoc,
- int assoc_len, const u8 iv[GCM_AES_IV_SIZE],
- const u8 *authtag)
-{
- u8 tagbuf[AES_BLOCK_SIZE];
- __be32 ctr[4];
-
- memcpy(ctr, iv, GCM_AES_IV_SIZE);
-
- aesgcm_mac(ctx, src, crypt_len, assoc, assoc_len, ctr, tagbuf);
- if (crypto_memneq(authtag, tagbuf, ctx->authsize)) {
- memzero_explicit(tagbuf, sizeof(tagbuf));
- return false;
- }
- aesgcm_crypt(ctx, dst, src, crypt_len, ctr);
- return true;
-}
-EXPORT_SYMBOL(aesgcm_decrypt);
-
-MODULE_DESCRIPTION("Generic AES-GCM library");
-MODULE_AUTHOR("Ard Biesheuvel <ardb@kernel.org>");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_CRYPTO_SELFTESTS
-
-/*
- * Test code below. Vectors taken from crypto/testmgr.h
- */
-
-static const u8 __initconst ctext0[16] __nonstring =
- "\x58\xe2\xfc\xce\xfa\x7e\x30\x61"
- "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a";
-
-static const u8 __initconst ptext1[16];
-
-static const u8 __initconst ctext1[32] __nonstring =
- "\x03\x88\xda\xce\x60\xb6\xa3\x92"
- "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78"
- "\xab\x6e\x47\xd4\x2c\xec\x13\xbd"
- "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf";
-
-static const u8 __initconst ptext2[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext2[80] __nonstring =
- "\x42\x83\x1e\xc2\x21\x77\x74\x24"
- "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
- "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
- "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
- "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
- "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
- "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
- "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
- "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
- "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4";
-
-static const u8 __initconst ptext3[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext3[76] __nonstring =
- "\x42\x83\x1e\xc2\x21\x77\x74\x24"
- "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
- "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
- "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
- "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
- "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
- "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
- "\x3d\x58\xe0\x91"
- "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
- "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47";
-
-static const u8 __initconst ctext4[16] __nonstring =
- "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b"
- "\xa0\x0e\xd1\xf3\x12\x57\x24\x35";
-
-static const u8 __initconst ctext5[32] __nonstring =
- "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
- "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
- "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
- "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb";
-
-static const u8 __initconst ptext6[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext6[80] __nonstring =
- "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
- "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
- "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
- "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
- "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
- "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
- "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
- "\xcc\xda\x27\x10\xac\xad\xe2\x56"
- "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
- "\xb1\x18\x02\x4d\xb8\x67\x4a\x14";
-
-static const u8 __initconst ctext7[16] __nonstring =
- "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9"
- "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b";
-
-static const u8 __initconst ctext8[32] __nonstring =
- "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e"
- "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18"
- "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0"
- "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19";
-
-static const u8 __initconst ptext9[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext9[80] __nonstring =
- "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
- "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
- "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
- "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
- "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
- "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
- "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
- "\xbc\xc9\xf6\x62\x89\x80\x15\xad"
- "\xb0\x94\xda\xc5\xd9\x34\x71\xbd"
- "\xec\x1a\x50\x22\x70\xe3\xcc\x6c";
-
-static const u8 __initconst ptext10[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext10[76] __nonstring =
- "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
- "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
- "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
- "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
- "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
- "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
- "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
- "\xbc\xc9\xf6\x62"
- "\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
- "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b";
-
-static const u8 __initconst ptext11[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext11[76] __nonstring =
- "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
- "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
- "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
- "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
- "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
- "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
- "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
- "\xcc\xda\x27\x10"
- "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
- "\x37\xba\x55\xbd\x6d\x27\x61\x8c";
-
-static const u8 __initconst ptext12[719] __nonstring =
- "\x42\xc1\xcc\x08\x48\x6f\x41\x3f"
- "\x2f\x11\x66\x8b\x2a\x16\xf0\xe0"
- "\x58\x83\xf0\xc3\x70\x14\xc0\x5b"
- "\x3f\xec\x1d\x25\x3c\x51\xd2\x03"
- "\xcf\x59\x74\x1f\xb2\x85\xb4\x07"
- "\xc6\x6a\x63\x39\x8a\x5b\xde\xcb"
- "\xaf\x08\x44\xbd\x6f\x91\x15\xe1"
- "\xf5\x7a\x6e\x18\xbd\xdd\x61\x50"
- "\x59\xa9\x97\xab\xbb\x0e\x74\x5c"
- "\x00\xa4\x43\x54\x04\x54\x9b\x3b"
- "\x77\xec\xfd\x5c\xa6\xe8\x7b\x08"
- "\xae\xe6\x10\x3f\x32\x65\xd1\xfc"
- "\xa4\x1d\x2c\x31\xfb\x33\x7a\xb3"
- "\x35\x23\xf4\x20\x41\xd4\xad\x82"
- "\x8b\xa4\xad\x96\x1c\x20\x53\xbe"
- "\x0e\xa6\xf4\xdc\x78\x49\x3e\x72"
- "\xb1\xa9\xb5\x83\xcb\x08\x54\xb7"
- "\xad\x49\x3a\xae\x98\xce\xa6\x66"
- "\x10\x30\x90\x8c\x55\x83\xd7\x7c"
- "\x8b\xe6\x53\xde\xd2\x6e\x18\x21"
- "\x01\x52\xd1\x9f\x9d\xbb\x9c\x73"
- "\x57\xcc\x89\x09\x75\x9b\x78\x70"
- "\xed\x26\x97\x4d\xb4\xe4\x0c\xa5"
- "\xfa\x70\x04\x70\xc6\x96\x1c\x7d"
- "\x54\x41\x77\xa8\xe3\xb0\x7e\x96"
- "\x82\xd9\xec\xa2\x87\x68\x55\xf9"
- "\x8f\x9e\x73\x43\x47\x6a\x08\x36"
- "\x93\x67\xa8\x2d\xde\xac\x41\xa9"
- "\x5c\x4d\x73\x97\x0f\x70\x68\xfa"
- "\x56\x4d\x00\xc2\x3b\x1f\xc8\xb9"
- "\x78\x1f\x51\x07\xe3\x9a\x13\x4e"
- "\xed\x2b\x2e\xa3\xf7\x44\xb2\xe7"
- "\xab\x19\x37\xd9\xba\x76\x5e\xd2"
- "\xf2\x53\x15\x17\x4c\x6b\x16\x9f"
- "\x02\x66\x49\xca\x7c\x91\x05\xf2"
- "\x45\x36\x1e\xf5\x77\xad\x1f\x46"
- "\xa8\x13\xfb\x63\xb6\x08\x99\x63"
- "\x82\xa2\xed\xb3\xac\xdf\x43\x19"
- "\x45\xea\x78\x73\xd9\xb7\x39\x11"
- "\xa3\x13\x7c\xf8\x3f\xf7\xad\x81"
- "\x48\x2f\xa9\x5c\x5f\xa0\xf0\x79"
- "\xa4\x47\x7d\x80\x20\x26\xfd\x63"
- "\x0a\xc7\x7e\x6d\x75\x47\xff\x76"
- "\x66\x2e\x8a\x6c\x81\x35\xaf\x0b"
- "\x2e\x6a\x49\x60\xc1\x10\xe1\xe1"
- "\x54\x03\xa4\x09\x0c\x37\x7a\x15"
- "\x23\x27\x5b\x8b\x4b\xa5\x64\x97"
- "\xae\x4a\x50\x73\x1f\x66\x1c\x5c"
- "\x03\x25\x3c\x8d\x48\x58\x71\x34"
- "\x0e\xec\x4e\x55\x1a\x03\x6a\xe5"
- "\xb6\x19\x2b\x84\x2a\x20\xd1\xea"
- "\x80\x6f\x96\x0e\x05\x62\xc7\x78"
- "\x87\x79\x60\x38\x46\xb4\x25\x57"
- "\x6e\x16\x63\xf8\xad\x6e\xd7\x42"
- "\x69\xe1\x88\xef\x6e\xd5\xb4\x9a"
- "\x3c\x78\x6c\x3b\xe5\xa0\x1d\x22"
- "\x86\x5c\x74\x3a\xeb\x24\x26\xc7"
- "\x09\xfc\x91\x96\x47\x87\x4f\x1a"
- "\xd6\x6b\x2c\x18\x47\xc0\xb8\x24"
- "\xa8\x5a\x4a\x9e\xcb\x03\xe7\x2a"
- "\x09\xe6\x4d\x9c\x6d\x86\x60\xf5"
- "\x2f\x48\x69\x37\x9f\xf2\xd2\xcb"
- "\x0e\x5a\xdd\x6e\x8a\xfb\x6a\xfe"
- "\x0b\x63\xde\x87\x42\x79\x8a\x68"
- "\x51\x28\x9b\x7a\xeb\xaf\xb8\x2f"
- "\x9d\xd1\xc7\x45\x90\x08\xc9\x83"
- "\xe9\x83\x84\xcb\x28\x69\x09\x69"
- "\xce\x99\x46\x00\x54\xcb\xd8\x38"
- "\xf9\x53\x4a\xbf\x31\xce\x57\x15"
- "\x33\xfa\x96\x04\x33\x42\xe3\xc0"
- "\xb7\x54\x4a\x65\x7a\x7c\x02\xe6"
- "\x19\x95\xd0\x0e\x82\x07\x63\xf9"
- "\xe1\x2b\x2a\xfc\x55\x92\x52\xc9"
- "\xb5\x9f\x23\x28\x60\xe7\x20\x51"
- "\x10\xd3\xed\x6d\x9b\xab\xb8\xe2"
- "\x5d\x9a\x34\xb3\xbe\x9c\x64\xcb"
- "\x78\xc6\x91\x22\x40\x91\x80\xbe"
- "\xd7\x78\x5c\x0e\x0a\xdc\x08\xe9"
- "\x67\x10\xa4\x83\x98\x79\x23\xe7"
- "\x92\xda\xa9\x22\x16\xb1\xe7\x78"
- "\xa3\x1c\x6c\x8f\x35\x7c\x4d\x37"
- "\x2f\x6e\x0b\x50\x5c\x34\xb9\xf9"
- "\xe6\x3d\x91\x0d\x32\x95\xaa\x3d"
- "\x48\x11\x06\xbb\x2d\xf2\x63\x88"
- "\x3f\x73\x09\xe2\x45\x56\x31\x51"
- "\xfa\x5e\x4e\x62\xf7\x90\xf9\xa9"
- "\x7d\x7b\x1b\xb1\xc8\x26\x6e\x66"
- "\xf6\x90\x9a\x7f\xf2\x57\xcc\x23"
- "\x59\xfa\xfa\xaa\x44\x04\x01\xa7"
- "\xa4\x78\xdb\x74\x3d\x8b\xb5";
-
-static const u8 __initconst ctext12[735] __nonstring =
- "\x84\x0b\xdb\xd5\xb7\xa8\xfe\x20"
- "\xbb\xb1\x12\x7f\x41\xea\xb3\xc0"
- "\xa2\xb4\x37\x19\x11\x58\xb6\x0b"
- "\x4c\x1d\x38\x05\x54\xd1\x16\x73"
- "\x8e\x1c\x20\x90\xa2\x9a\xb7\x74"
- "\x47\xe6\xd8\xfc\x18\x3a\xb4\xea"
- "\xd5\x16\x5a\x2c\x53\x01\x46\xb3"
- "\x18\x33\x74\x6c\x50\xf2\xe8\xc0"
- "\x73\xda\x60\x22\xeb\xe3\xe5\x9b"
- "\x20\x93\x6c\x4b\x37\x99\xb8\x23"
- "\x3b\x4e\xac\xe8\x5b\xe8\x0f\xb7"
- "\xc3\x8f\xfb\x4a\x37\xd9\x39\x95"
- "\x34\xf1\xdb\x8f\x71\xd9\xc7\x0b"
- "\x02\xf1\x63\xfc\x9b\xfc\xc5\xab"
- "\xb9\x14\x13\x21\xdf\xce\xaa\x88"
- "\x44\x30\x1e\xce\x26\x01\x92\xf8"
- "\x9f\x00\x4b\x0c\x4b\xf7\x5f\xe0"
- "\x89\xca\x94\x66\x11\x21\x97\xca"
- "\x3e\x83\x74\x2d\xdb\x4d\x11\xeb"
- "\x97\xc2\x14\xff\x9e\x1e\xa0\x6b"
- "\x08\xb4\x31\x2b\x85\xc6\x85\x6c"
- "\x90\xec\x39\xc0\xec\xb3\xb5\x4e"
- "\xf3\x9c\xe7\x83\x3a\x77\x0a\xf4"
- "\x56\xfe\xce\x18\x33\x6d\x0b\x2d"
- "\x33\xda\xc8\x05\x5c\xb4\x09\x2a"
- "\xde\x6b\x52\x98\x01\xef\x36\x3d"
- "\xbd\xf9\x8f\xa8\x3e\xaa\xcd\xd1"
- "\x01\x2d\x42\x49\xc3\xb6\x84\xbb"
- "\x48\x96\xe0\x90\x93\x6c\x48\x64"
- "\xd4\xfa\x7f\x93\x2c\xa6\x21\xc8"
- "\x7a\x23\x7b\xaa\x20\x56\x12\xae"
- "\x16\x9d\x94\x0f\x54\xa1\xec\xca"
- "\x51\x4e\xf2\x39\xf4\xf8\x5f\x04"
- "\x5a\x0d\xbf\xf5\x83\xa1\x15\xe1"
- "\xf5\x3c\xd8\x62\xa3\xed\x47\x89"
- "\x85\x4c\xe5\xdb\xac\x9e\x17\x1d"
- "\x0c\x09\xe3\x3e\x39\x5b\x4d\x74"
- "\x0e\xf5\x34\xee\x70\x11\x4c\xfd"
- "\xdb\x34\xb1\xb5\x10\x3f\x73\xb7"
- "\xf5\xfa\xed\xb0\x1f\xa5\xcd\x3c"
- "\x8d\x35\x83\xd4\x11\x44\x6e\x6c"
- "\x5b\xe0\x0e\x69\xa5\x39\xe5\xbb"
- "\xa9\x57\x24\x37\xe6\x1f\xdd\xcf"
- "\x16\x2a\x13\xf9\x6a\x2d\x90\xa0"
- "\x03\x60\x7a\xed\x69\xd5\x00\x8b"
- "\x7e\x4f\xcb\xb9\xfa\x91\xb9\x37"
- "\xc1\x26\xce\x90\x97\x22\x64\x64"
- "\xc1\x72\x43\x1b\xf6\xac\xc1\x54"
- "\x8a\x10\x9c\xdd\x8d\xd5\x8e\xb2"
- "\xe4\x85\xda\xe0\x20\x5f\xf4\xb4"
- "\x15\xb5\xa0\x8d\x12\x74\x49\x23"
- "\x3a\xdf\x4a\xd3\xf0\x3b\x89\xeb"
- "\xf8\xcc\x62\x7b\xfb\x93\x07\x41"
- "\x61\x26\x94\x58\x70\xa6\x3c\xe4"
- "\xff\x58\xc4\x13\x3d\xcb\x36\x6b"
- "\x32\xe5\xb2\x6d\x03\x74\x6f\x76"
- "\x93\x77\xde\x48\xc4\xfa\x30\x4a"
- "\xda\x49\x80\x77\x0f\x1c\xbe\x11"
- "\xc8\x48\xb1\xe5\xbb\xf2\x8a\xe1"
- "\x96\x2f\x9f\xd1\x8e\x8a\x5c\xe2"
- "\xf7\xd7\xd8\x54\xf3\x3f\xc4\x91"
- "\xb8\xfb\x86\xdc\x46\x24\x91\x60"
- "\x6c\x2f\xc9\x41\x37\x51\x49\x54"
- "\x09\x81\x21\xf3\x03\x9f\x2b\xe3"
- "\x1f\x39\x63\xaf\xf4\xd7\x53\x60"
- "\xa7\xc7\x54\xf9\xee\xb1\xb1\x7d"
- "\x75\x54\x65\x93\xfe\xb1\x68\x6b"
- "\x57\x02\xf9\xbb\x0e\xf9\xf8\xbf"
- "\x01\x12\x27\xb4\xfe\xe4\x79\x7a"
- "\x40\x5b\x51\x4b\xdf\x38\xec\xb1"
- "\x6a\x56\xff\x35\x4d\x42\x33\xaa"
- "\x6f\x1b\xe4\xdc\xe0\xdb\x85\x35"
- "\x62\x10\xd4\xec\xeb\xc5\x7e\x45"
- "\x1c\x6f\x17\xca\x3b\x8e\x2d\x66"
- "\x4f\x4b\x36\x56\xcd\x1b\x59\xaa"
- "\xd2\x9b\x17\xb9\x58\xdf\x7b\x64"
- "\x8a\xff\x3b\x9c\xa6\xb5\x48\x9e"
- "\xaa\xe2\x5d\x09\x71\x32\x5f\xb6"
- "\x29\xbe\xe7\xc7\x52\x7e\x91\x82"
- "\x6b\x6d\x33\xe1\x34\x06\x36\x21"
- "\x5e\xbe\x1e\x2f\x3e\xc1\xfb\xea"
- "\x49\x2c\xb5\xca\xf7\xb0\x37\xea"
- "\x1f\xed\x10\x04\xd9\x48\x0d\x1a"
- "\x1c\xfb\xe7\x84\x0e\x83\x53\x74"
- "\xc7\x65\xe2\x5c\xe5\xba\x73\x4c"
- "\x0e\xe1\xb5\x11\x45\x61\x43\x46"
- "\xaa\x25\x8f\xbd\x85\x08\xfa\x4c"
- "\x15\xc1\xc0\xd8\xf5\xdc\x16\xbb"
- "\x7b\x1d\xe3\x87\x57\xa7\x2a\x1d"
- "\x38\x58\x9e\x8a\x43\xdc\x57"
- "\xd1\x81\x7d\x2b\xe9\xff\x99\x3a"
- "\x4b\x24\x52\x58\x55\xe1\x49\x14";
-
-static struct {
- const u8 *ptext;
- const u8 *ctext;
-
- u8 key[AES_MAX_KEY_SIZE] __nonstring;
- u8 iv[GCM_AES_IV_SIZE] __nonstring;
- u8 assoc[20] __nonstring;
-
- int klen;
- int clen;
- int plen;
- int alen;
-} const aesgcm_tv[] __initconst = {
- { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
- .klen = 16,
- .ctext = ctext0,
- .clen = sizeof(ctext0),
- }, {
- .klen = 16,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext1,
- .clen = sizeof(ctext1),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 16,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext2,
- .plen = sizeof(ptext2),
- .ctext = ctext2,
- .clen = sizeof(ctext2),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 16,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext3,
- .plen = sizeof(ptext3),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext3,
- .clen = sizeof(ctext3),
- }, {
- .klen = 24,
- .ctext = ctext4,
- .clen = sizeof(ctext4),
- }, {
- .klen = 24,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext5,
- .clen = sizeof(ctext5),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
- .klen = 24,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext6,
- .plen = sizeof(ptext6),
- .ctext = ctext6,
- .clen = sizeof(ctext6),
- }, {
- .klen = 32,
- .ctext = ctext7,
- .clen = sizeof(ctext7),
- }, {
- .klen = 32,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext8,
- .clen = sizeof(ctext8),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 32,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext9,
- .plen = sizeof(ptext9),
- .ctext = ctext9,
- .clen = sizeof(ctext9),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 32,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext10,
- .plen = sizeof(ptext10),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext10,
- .clen = sizeof(ctext10),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
- .klen = 24,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext11,
- .plen = sizeof(ptext11),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext11,
- .clen = sizeof(ctext11),
- }, {
- .key = "\x62\x35\xf8\x95\xfc\xa5\xeb\xf6"
- "\x0e\x92\x12\x04\xd3\xa1\x3f\x2e"
- "\x8b\x32\xcf\xe7\x44\xed\x13\x59"
- "\x04\x38\x77\xb0\xb9\xad\xb4\x38",
- .klen = 32,
- .iv = "\x00\xff\xff\xff\xff\x00\x00\xff"
- "\xff\xff\x00\xff",
- .ptext = ptext12,
- .plen = sizeof(ptext12),
- .ctext = ctext12,
- .clen = sizeof(ctext12),
- }
-};
-
-static int __init libaesgcm_init(void)
-{
- for (int i = 0; i < ARRAY_SIZE(aesgcm_tv); i++) {
- u8 tagbuf[AES_BLOCK_SIZE];
- int plen = aesgcm_tv[i].plen;
- struct aesgcm_ctx ctx;
- static u8 buf[sizeof(ptext12)];
-
- if (aesgcm_expandkey(&ctx, aesgcm_tv[i].key, aesgcm_tv[i].klen,
- aesgcm_tv[i].clen - plen)) {
- pr_err("aesgcm_expandkey() failed on vector %d\n", i);
- return -ENODEV;
- }
-
- if (!aesgcm_decrypt(&ctx, buf, aesgcm_tv[i].ctext, plen,
- aesgcm_tv[i].assoc, aesgcm_tv[i].alen,
- aesgcm_tv[i].iv, aesgcm_tv[i].ctext + plen)
- || memcmp(buf, aesgcm_tv[i].ptext, plen)) {
- pr_err("aesgcm_decrypt() #1 failed on vector %d\n", i);
- return -ENODEV;
- }
-
- /* encrypt in place */
- aesgcm_encrypt(&ctx, buf, buf, plen, aesgcm_tv[i].assoc,
- aesgcm_tv[i].alen, aesgcm_tv[i].iv, tagbuf);
- if (memcmp(buf, aesgcm_tv[i].ctext, plen)) {
- pr_err("aesgcm_encrypt() failed on vector %d\n", i);
- return -ENODEV;
- }
-
- /* decrypt in place */
- if (!aesgcm_decrypt(&ctx, buf, buf, plen, aesgcm_tv[i].assoc,
- aesgcm_tv[i].alen, aesgcm_tv[i].iv, tagbuf)
- || memcmp(buf, aesgcm_tv[i].ptext, plen)) {
- pr_err("aesgcm_decrypt() #2 failed on vector %d\n", i);
- return -ENODEV;
- }
- }
- return 0;
-}
-module_init(libaesgcm_init);
-
-static void __exit libaesgcm_exit(void)
-{
-}
-module_exit(libaesgcm_exit);
-#endif
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 9409c1a935c3..bc084dde424f 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -144,7 +144,13 @@ config CRYPTO_LIB_SM3_KUNIT_TEST
config CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT
tristate "Enable all crypto library code for KUnit tests"
depends on KUNIT
+ select CRYPTO_LIB_AES_CBC
select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_AES_CCM
+ select CRYPTO_LIB_AES_CTR
+ select CRYPTO_LIB_AES_ECB
+ select CRYPTO_LIB_AES_GCM
+ select CRYPTO_LIB_AES_XTS
select CRYPTO_LIB_BLAKE2B
select CRYPTO_LIB_CHACHA20POLY1305
select CRYPTO_LIB_CURVE25519
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index c4470958b0d5..4a32e4f80b48 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -164,7 +164,7 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
{
uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX];
- struct aes_cmac_key key;
+ struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
int err;
if (len > CMAC_MSG_MAX)
@@ -178,6 +178,7 @@ static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
SMP_DBG("key %16phN", k);
err = aes_cmac_preparekey(&key, tmp, 16);
+ memzero_explicit(tmp, sizeof(tmp));
if (WARN_ON_ONCE(err)) /* Should never happen, as 16 is valid keylen */
return err;
aes_cmac(&key, msg_msb, len, mac_msb);
diff --git a/net/mac80211/fils_aead.c b/net/mac80211/fils_aead.c
index d2f4a17eab99..293590976489 100644
--- a/net/mac80211/fils_aead.c
+++ b/net/mac80211/fils_aead.c
@@ -24,7 +24,7 @@ static int aes_s2v(const u8 *in_key, size_t key_len,
size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
{
u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
- struct aes_cmac_key key;
+ struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
struct aes_cmac_ctx ctx;
size_t i;
int res;
@@ -62,7 +62,6 @@ static int aes_s2v(const u8 *in_key, size_t key_len,
aes_cmac_update(&ctx, d, AES_BLOCK_SIZE);
aes_cmac_final(&ctx, v);
- memzero_explicit(&key, sizeof(key));
return 0;
}