mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 10:00:03 -04:00
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
This commit is contained in:
20
Documentation/crypto/libcrypto-auth-encryption.rst
Normal file
20
Documentation/crypto/libcrypto-auth-encryption.rst
Normal file
@@ -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
|
||||
49
Documentation/crypto/libcrypto-unauth-encryption.rst
Normal file
49
Documentation/crypto/libcrypto-unauth-encryption.rst
Normal file
@@ -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
|
||||
@@ -159,8 +159,10 @@ API documentation
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
libcrypto-auth-encryption
|
||||
libcrypto-blockcipher
|
||||
libcrypto-hash
|
||||
libcrypto-signature
|
||||
libcrypto-unauth-encryption
|
||||
libcrypto-utils
|
||||
sha3
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
892
crypto/aes.c
892
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
|
||||
|
||||
@@ -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 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
|
||||
* 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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -24,6 +25,19 @@ struct aes_cmac_key {
|
||||
} k_final[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -40,6 +54,19 @@ struct aes_cmac_ctx {
|
||||
u8 h[AES_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -47,6 +74,10 @@ struct aes_cmac_ctx {
|
||||
* @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)
|
||||
|
||||
77
include/crypto/aes-cbc.h
Normal file
77
include/crypto/aes-cbc.h
Normal file
@@ -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 */
|
||||
266
include/crypto/aes-ccm.h
Normal file
266
include/crypto/aes-ccm.h
Normal file
@@ -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 */
|
||||
65
include/crypto/aes-ctr.h
Normal file
65
include/crypto/aes-ctr.h
Normal file
@@ -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 */
|
||||
49
include/crypto/aes-ecb.h
Normal file
49
include/crypto/aes-ecb.h
Normal file
@@ -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 */
|
||||
260
include/crypto/aes-gcm.h
Normal file
260
include/crypto/aes-gcm.h
Normal file
@@ -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 */
|
||||
94
include/crypto/aes-xts.h
Normal file
94
include/crypto/aes-xts.h
Normal file
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
1163
lib/crypto/aes.c
1163
lib/crypto/aes.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user