diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-20 15:38:53 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-20 15:38:53 -1000 |
| commit | 95615dd9ff28148e40a3889e813de00274929448 (patch) | |
| tree | 4ab1df21e0178284329a396cfe910fb9debe0636 /lib | |
| parent | 9e947d96915af63e28896caae85a81b74855621b (diff) | |
| parent | 20ec6916d8712e84d58e8c688a25cd368ddeb82b (diff) | |
Merge tag 'libcrypto-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux
Pull crypto library updates from Eric Biggers:
- Migrate the x86 and riscv optimized implementations of various AES
modes (ECB, CBC, CBC-CTS, CTR, XCTR, XTS) into lib/crypto/.
This makes the library APIs be properly accelerated on these
architectures, while still accelerating crypto_skcipher as well.
It removes a lot of redundant glue code, since the crypto API
boilerplate no longer needs to be duplicated for these architectures.
It also fixes the longstanding issue where optimizations for these
AES modes were disabled by default on these architectures.
- Optimize AES-XTS on SPARC64 using the SPARC crypto opcodes
- Move the SipHash code into lib/crypto/
- Update the ChaCha and Poly1305 functions to take size_t lengths,
resolving issues where lengths over INT_MAX were mishandled
- Make frame pointer unwinding work properly in some of the x86
assembly functions, by following the standard %rbp convention
- Add helper functions for zeroizing structs
- Make a few documentation improvements
* tag 'libcrypto-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux: (49 commits)
lib/crypto: md5: remove unused header
lib/crypto: mips/chacha: Handle lengths of 2 GiB or more
lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code
lib/crypto: chacha: Use size_t length
lib/crypto: poly1305: Use size_t length
lib/crypto: x86/sha512: Follow the normal %rbp convention
lib/crypto: x86/sha256: Follow the normal %rbp convention
lib/crypto: x86/sha1: Follow the normal %rbp convention
lib/crypto: chacha20poly1305: zeroize state in __chacha20poly1305_decrypt
lib/crypto: sparc/aes-xts: Add optimization using the AES opcodes
lib: Move SipHash into lib/crypto/
lib/crypto: x86/aes-ctr: Remove some unreachable code
crypto: x86/aesni-intel - Add transitional selections
crypto: aes - Boost priority of encryption modes further
lib/crypto: x86/aes: Set RNDKEY in aes_cbc_encrypt_aesni()
lib/crypto: riscv/aes-xts: Migrate optimized code into library
lib/crypto: riscv/aes-ctr: Migrate optimized code into library
lib/crypto: riscv/aes-cbc: Migrate optimized code into library
lib/crypto: riscv/aes-ecb: Migrate optimized code into library
lib/crypto: riscv/aes: Pass key struct to assembly code
...
Diffstat (limited to 'lib')
57 files changed, 4036 insertions, 282 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6b24a2c89b84..c9acfefb6d62 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -3090,17 +3090,6 @@ config HW_BREAKPOINT_KUNIT_TEST source "lib/crypto/tests/Kconfig" -config SIPHASH_KUNIT_TEST - tristate "Perform selftest on siphash functions" if !KUNIT_ALL_TESTS - depends on KUNIT - default KUNIT_ALL_TESTS - help - Enable this option to test the kernel's siphash (<linux/siphash.h>) hash - functions on boot (or module load). - - This is intended to help people writing architecture-specific - optimized versions. If unsure, say N. - config USERCOPY_KUNIT_TEST tristate "KUnit Test for user/kernel boundary protections" depends on KUNIT diff --git a/lib/Makefile b/lib/Makefile index dfab958327c5..e1eb91d62a30 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -38,7 +38,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ maple_tree.o idr.o extable.o irq_regs.o argv_split.o \ flex_proportions.o ratelimit.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ - earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ + earlycpio.o seq_buf.o dec_and_lock.o \ nmi_backtrace.o win_minmax.o memcat_p.o \ buildid.o objpool.o iomem_copy.o sys_info.o diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig index 60e0a77f9889..6f218cd2d0c3 100644 --- a/lib/crypto/.kunitconfig +++ b/lib/crypto/.kunitconfig @@ -19,4 +19,5 @@ CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST=y CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST=y CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST=y CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST=y +CONFIG_CRYPTO_LIB_SIPHASH_KUNIT_TEST=y CONFIG_CRYPTO_LIB_SM3_KUNIT_TEST=y diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile index ca068df1f71f..832d170cab94 100644 --- a/lib/crypto/Makefile +++ b/lib/crypto/Makefile @@ -51,8 +51,22 @@ endif # !CONFIG_SPE endif # CONFIG_PPC libaes-$(CONFIG_RISCV) += riscv/aes-riscv64-zvkned.o +ifneq ($(CONFIG_CRYPTO_LIB_AES_CTR),) +libaes-$(CONFIG_RISCV) += riscv/aes-riscv64-zvkned-zvkb.o +endif +ifneq ($(CONFIG_CRYPTO_LIB_AES_XTS),) +libaes-$(CONFIG_RISCV) += riscv/aes-riscv64-zvkned-zvbb-zvkg.o +endif + libaes-$(CONFIG_SPARC) += sparc/aes_asm.o + libaes-$(CONFIG_X86) += x86/aes-aesni.o +ifneq ($(CONFIG_CRYPTO_LIB_AES_CTR),) +libaes-$(CONFIG_X86_64) += x86/aes-ctr-avx-x86_64.o +endif +ifneq ($(CONFIG_CRYPTO_LIB_AES_XTS),) +libaes-$(CONFIG_X86_64) += x86/aes-xts-avx-x86_64.o +endif endif # CONFIG_CRYPTO_LIB_AES_ARCH # clean-files must be defined unconditionally @@ -362,6 +376,12 @@ endif # CONFIG_CRYPTO_LIB_SHA3_ARCH ################################################################################ +# SipHash support is always built-in because it's used by core components such +# as printk (for pointer hashing) and networking. +obj-y += siphash.o + +################################################################################ + obj-$(CONFIG_CRYPTO_LIB_SM3) += libsm3.o libsm3-y := sm3.o ifeq ($(CONFIG_CRYPTO_LIB_SM3_ARCH),y) diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c index f1549839b3de..e1c191551736 100644 --- a/lib/crypto/aes.c +++ b/lib/crypto/aes.c @@ -539,7 +539,7 @@ static void __init aes_fips_test(void) if (memcmp(fips_test_data, data, sizeof(data)) != 0) panic("aes: FIPS self-test failed (wrong plaintext)\n"); - memzero_explicit(&key, sizeof(key)); + aes_zeroize_key(&key); } #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS) @@ -827,7 +827,7 @@ static void __init aes_ecb_fips_test(void) if (memcmp(fips_test_data, data, sizeof(data)) != 0) panic("aes: ECB FIPS self-test failed (wrong plaintext)\n"); - memzero_explicit(&key, sizeof(key)); + aes_zeroize_key(&key); } #else /* CONFIG_CRYPTO_LIB_AES_ECB */ static inline void aes_ecb_fips_test(void) @@ -1040,7 +1040,7 @@ static void __init aes_cbc_fips_test(void) if (memcmp(fips_test_data, data, sizeof(data)) != 0) panic("aes: CBC FIPS self-test failed (wrong plaintext)\n"); - memzero_explicit(&key, sizeof(key)); + aes_zeroize_key(&key); } /* FIPS cryptographic algorithm self-test for AES-CBC-CTS */ @@ -1069,7 +1069,7 @@ static void __init aes_cbc_cts_fips_test(void) if (memcmp(ptext, data, data_len) != 0) panic("aes: CBC-CTS FIPS self-test failed (wrong plaintext)\n"); - memzero_explicit(&key, sizeof(key)); + aes_zeroize_key(&key); } #else /* CONFIG_CRYPTO_LIB_AES_CBC */ static inline void aes_cbc_fips_test(void) @@ -1094,7 +1094,7 @@ static bool aes_ctr_arch(u8 *dst, const u8 *src, size_t len, } #endif #ifndef aes_xctr_arch -static bool aes_xctr_arch(u8 *dst, const u8 *src, size_t len, u64 *ctr, +static bool aes_xctr_arch(u8 *dst, const u8 *src, size_t len, u64 ctr, const u8 iv[AES_BLOCK_SIZE], const struct aes_enckey *key) { @@ -1150,8 +1150,10 @@ void aes_xctr(u8 *dst, const u8 *src, size_t len, u64 *ctr, __le64 aes_input[2]; u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long)); - if (likely(aes_xctr_arch(dst, src, len, ctr, iv, key.enc_key))) + if (likely(aes_xctr_arch(dst, src, len, *ctr, iv, key.enc_key))) { + *ctr += DIV_ROUND_UP(len, AES_BLOCK_SIZE); return; + } aes_input[1] = get_unaligned((const __le64 *)&iv[8]); /* Handle the full blocks. */ @@ -1194,7 +1196,7 @@ static void __init aes_ctr_fips_test(void) if (memcmp(fips_test_data, data, sizeof(data)) != 0) panic("aes: CTR FIPS self-test failed (wrong plaintext)\n"); - memzero_explicit(&key, sizeof(key)); + aes_zeroize_enckey(&key); } #else /* CONFIG_CRYPTO_LIB_AES_CTR */ static inline void aes_ctr_fips_test(void) @@ -1223,7 +1225,7 @@ int aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key, return 0; out_zeroize: - memzero_explicit(key, sizeof(*key)); + aes_xts_zeroize_key(key); return err; } EXPORT_SYMBOL_GPL(aes_xts_preparekey); @@ -1670,7 +1672,7 @@ void aes_gcm_encrypt_final(struct aes_gcm_ctx *ctx, u8 *authtag) ghash_final(&ctx->ghash, ctx->ctr); /* Use ctr as temp buffer */ crypto_xor_cpy(authtag, ctx->ctr, ctx->j0_enc, ctx->key->authtag_len); - memzero_explicit(ctx, sizeof(*ctx)); + aes_gcm_zeroize_ctx(ctx); } EXPORT_SYMBOL_GPL(aes_gcm_encrypt_final); @@ -1697,7 +1699,7 @@ int aes_gcm_decrypt_final(struct aes_gcm_ctx *ctx, const u8 *authtag) -EBADMSG : 0; out: - memzero_explicit(ctx, sizeof(*ctx)); + aes_gcm_zeroize_ctx(ctx); return err; } EXPORT_SYMBOL_GPL(aes_gcm_decrypt_final); @@ -1742,7 +1744,7 @@ static void __init aes_gcm_fips_test(void) { const size_t data_len = sizeof(fips_test_data); u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE]; - struct aes_gcm_key key; + struct aes_gcm_key key __cleanup(aes_gcm_zeroize_key); int err; if (aes_gcm_preparekey(&key, fips_test_key, sizeof(fips_test_key), @@ -1760,8 +1762,6 @@ static void __init aes_gcm_fips_test(void) panic("aes: GCM FIPS self-test failed (decryption failed)\n"); if (memcmp(fips_test_data, buf, data_len) != 0) panic("aes: GCM FIPS self-test failed (wrong plaintext)\n"); - - memzero_explicit(&key, sizeof(key)); } #else /* CONFIG_CRYPTO_LIB_AES_GCM */ static inline void aes_gcm_fips_test(void) @@ -2013,7 +2013,7 @@ void aes_ccm_encrypt_final(struct aes_ccm_ctx *ctx, u8 *authtag) if (ctx->partial_len) aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac); crypto_xor_cpy(authtag, ctx->mac, ctx->s0, ctx->key->authtag_len); - memzero_explicit(ctx, sizeof(*ctx)); + aes_ccm_zeroize_ctx(ctx); } EXPORT_SYMBOL_GPL(aes_ccm_encrypt_final); @@ -2034,7 +2034,7 @@ int aes_ccm_decrypt_final(struct aes_ccm_ctx *ctx, const u8 *authtag) -EBADMSG : 0; out: - memzero_explicit(ctx, sizeof(*ctx)); + aes_ccm_zeroize_ctx(ctx); return err; } EXPORT_SYMBOL_GPL(aes_ccm_decrypt_final); @@ -2086,7 +2086,7 @@ static void __init aes_ccm_fips_test(void) const size_t data_len = sizeof(fips_test_data); const size_t nonce_len = 13; u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE]; - struct aes_ccm_key key; + struct aes_ccm_key key __cleanup(aes_ccm_zeroize_key); int err; if (aes_ccm_preparekey(&key, fips_test_key, sizeof(fips_test_key), @@ -2108,8 +2108,6 @@ static void __init aes_ccm_fips_test(void) panic("aes: CCM FIPS self-test failed (decryption failed)\n"); if (memcmp(fips_test_data, buf, data_len) != 0) panic("aes: CCM FIPS self-test failed (wrong plaintext)\n"); - - memzero_explicit(&key, sizeof(key)); } #else /* CONFIG_CRYPTO_LIB_AES_CCM */ static inline void aes_ccm_fips_test(void) diff --git a/lib/crypto/arm/chacha-scalar-core.S b/lib/crypto/arm/chacha-scalar-core.S index 4951df05c158..d9d0a8cee941 100644 --- a/lib/crypto/arm/chacha-scalar-core.S +++ b/lib/crypto/arm/chacha-scalar-core.S @@ -163,7 +163,7 @@ // Use slow path if fewer than 64 bytes remain. cmp r11, #64 - blt .Lxor_slowpath\@ + blo .Lxor_slowpath\@ // Use slow path if IN and/or OUT isn't 4-byte aligned. Needed even on // ARMv6+, since ldmia and stmia (used below) still require alignment. @@ -324,8 +324,8 @@ ldr r14, [sp, #160] // OUT cmp r9, #64 mov r0, sp - movle r1, r9 - movgt r1, #64 + movls r1, r9 + movhi r1, #64 // r1 is number of bytes to XOR, in range [1, 64] .if __LINUX_ARM_ARCH__ < 6 @@ -360,13 +360,13 @@ .Lxor_slowpath_done\@: subs r9, #64 add sp, #96 - bgt .Lprepare_for_next_block\@ + bhi .Lprepare_for_next_block\@ .Ldone\@: .endm // _chacha /* - * void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes, + * void chacha_doarm(u8 *dst, const u8 *src, size_t bytes, * const struct chacha_state *state, int nrounds); */ ENTRY(chacha_doarm) diff --git a/lib/crypto/arm/chacha.h b/lib/crypto/arm/chacha.h index 836e49088e98..5b366f4de78d 100644 --- a/lib/crypto/arm/chacha.h +++ b/lib/crypto/arm/chacha.h @@ -17,14 +17,14 @@ asmlinkage void chacha_block_xor_neon(const struct chacha_state *state, u8 *dst, const u8 *src, int nrounds); asmlinkage void chacha_4block_xor_neon(const struct chacha_state *state, - u8 *dst, const u8 *src, - int nrounds, unsigned int nbytes); + u8 *dst, const u8 *src, int nrounds, + size_t nbytes); asmlinkage void hchacha_block_arm(const struct chacha_state *state, u32 out[HCHACHA_OUT_WORDS], int nrounds); asmlinkage void hchacha_block_neon(const struct chacha_state *state, u32 out[HCHACHA_OUT_WORDS], int nrounds); -asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes, +asmlinkage void chacha_doarm(u8 *dst, const u8 *src, size_t bytes, const struct chacha_state *state, int nrounds); static __ro_after_init DEFINE_STATIC_KEY_FALSE(use_neon); @@ -35,12 +35,12 @@ static inline bool neon_usable(void) } static void chacha_doneon(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) + size_t bytes, int nrounds) { u8 buf[CHACHA_BLOCK_SIZE]; while (bytes > CHACHA_BLOCK_SIZE) { - unsigned int l = min(bytes, CHACHA_BLOCK_SIZE * 4U); + size_t l = min(bytes, CHACHA_BLOCK_SIZE * 4U); chacha_4block_xor_neon(state, dst, src, nrounds, l); bytes -= l; @@ -73,17 +73,17 @@ static void hchacha_block_arch(const struct chacha_state *state, } static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() || bytes <= CHACHA_BLOCK_SIZE) { chacha_doarm(dst, src, bytes, state, nrounds); - state->x[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE); + state->x[12] += DIV_ROUND_UP_POW2(bytes, CHACHA_BLOCK_SIZE); return; } do { - unsigned int todo = min_t(unsigned int, bytes, SZ_4K); + size_t todo = min(bytes, SZ_4K); scoped_ksimd() chacha_doneon(state, dst, src, todo, nrounds); diff --git a/lib/crypto/arm/poly1305.h b/lib/crypto/arm/poly1305.h index 0fe903d8de55..6cad0824a2b4 100644 --- a/lib/crypto/arm/poly1305.h +++ b/lib/crypto/arm/poly1305.h @@ -14,9 +14,9 @@ asmlinkage void poly1305_block_init(struct poly1305_block_state *state, const u8 raw_key[POLY1305_BLOCK_SIZE]); asmlinkage void poly1305_blocks_arm(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_blocks_neon(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_emit(const struct poly1305_state *state, u8 digest[POLY1305_DIGEST_SIZE], const u32 nonce[4]); @@ -24,12 +24,12 @@ asmlinkage void poly1305_emit(const struct poly1305_state *state, static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); static void poly1305_blocks(struct poly1305_block_state *state, const u8 *src, - unsigned int len, u32 padbit) + size_t len, u32 padbit) { if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && static_branch_likely(&have_neon) && likely(may_use_simd())) { do { - unsigned int todo = min_t(unsigned int, len, SZ_4K); + size_t todo = min(len, SZ_4K); scoped_ksimd() poly1305_blocks_neon(state, src, todo, padbit); diff --git a/lib/crypto/arm64/chacha.h b/lib/crypto/arm64/chacha.h index c6f8ddf98e2d..793ee9112eb9 100644 --- a/lib/crypto/arm64/chacha.h +++ b/lib/crypto/arm64/chacha.h @@ -28,18 +28,18 @@ asmlinkage void chacha_block_xor_neon(const struct chacha_state *state, u8 *dst, const u8 *src, int nrounds); asmlinkage void chacha_4block_xor_neon(const struct chacha_state *state, - u8 *dst, const u8 *src, - int nrounds, int bytes); + u8 *dst, const u8 *src, int nrounds, + size_t bytes); asmlinkage void hchacha_block_neon(const struct chacha_state *state, u32 out[HCHACHA_OUT_WORDS], int nrounds); static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); static void chacha_doneon(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) + size_t bytes, int nrounds) { while (bytes) { - int l = min(bytes, CHACHA_BLOCK_SIZE * 5); + size_t l = min(bytes, CHACHA_BLOCK_SIZE * 5); if (l <= CHACHA_BLOCK_SIZE) { u8 buf[CHACHA_BLOCK_SIZE]; @@ -70,7 +70,7 @@ static void hchacha_block_arch(const struct chacha_state *state, } static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { if (!static_branch_likely(&have_neon) || bytes <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) diff --git a/lib/crypto/arm64/poly1305.h b/lib/crypto/arm64/poly1305.h index 3d4bde857699..2ebd2d919c93 100644 --- a/lib/crypto/arm64/poly1305.h +++ b/lib/crypto/arm64/poly1305.h @@ -14,9 +14,9 @@ asmlinkage void poly1305_block_init(struct poly1305_block_state *state, const u8 raw_key[POLY1305_BLOCK_SIZE]); asmlinkage void poly1305_blocks_arm64(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_blocks_neon(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_emit(const struct poly1305_state *state, u8 digest[POLY1305_DIGEST_SIZE], const u32 nonce[4]); @@ -24,7 +24,7 @@ asmlinkage void poly1305_emit(const struct poly1305_state *state, static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); static void poly1305_blocks(struct poly1305_block_state *state, const u8 *src, - unsigned int len, u32 padbit) + size_t len, u32 padbit) { if (static_branch_likely(&have_neon) && likely(may_use_simd())) { scoped_ksimd() diff --git a/lib/crypto/blake2b.c b/lib/crypto/blake2b.c index 581b7f8486fa..55d6c437f311 100644 --- a/lib/crypto/blake2b.c +++ b/lib/crypto/blake2b.c @@ -148,7 +148,7 @@ void blake2b_final(struct blake2b_ctx *ctx, u8 *out) blake2b_compress(ctx, ctx->buf, 1, ctx->buflen); cpu_to_le64_array(ctx->h, ARRAY_SIZE(ctx->h)); memcpy(out, ctx->h, ctx->outlen); - memzero_explicit(ctx, sizeof(*ctx)); + blake2b_zeroize_ctx(ctx); } EXPORT_SYMBOL(blake2b_final); diff --git a/lib/crypto/blake2s.c b/lib/crypto/blake2s.c index 71578a084742..24f7f34334b0 100644 --- a/lib/crypto/blake2s.c +++ b/lib/crypto/blake2s.c @@ -142,7 +142,7 @@ void blake2s_final(struct blake2s_ctx *ctx, u8 *out) blake2s_compress(ctx, ctx->buf, 1, ctx->buflen); cpu_to_le32_array(ctx->h, ARRAY_SIZE(ctx->h)); memcpy(out, ctx->h, ctx->outlen); - memzero_explicit(ctx, sizeof(*ctx)); + blake2s_zeroize_ctx(ctx); } EXPORT_SYMBOL(blake2s_final); diff --git a/lib/crypto/chacha.c b/lib/crypto/chacha.c index 86e5d382a4e0..95ecd6f989e3 100644 --- a/lib/crypto/chacha.c +++ b/lib/crypto/chacha.c @@ -11,9 +11,9 @@ #include <linux/kernel.h> #include <linux/module.h> -static void __maybe_unused -chacha_crypt_generic(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) +static void __maybe_unused chacha_crypt_generic(struct chacha_state *state, + u8 *dst, const u8 *src, + size_t bytes, int nrounds) { /* aligned to potentially speed up crypto_xor() */ u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long)); @@ -39,7 +39,7 @@ chacha_crypt_generic(struct chacha_state *state, u8 *dst, const u8 *src, #endif void chacha_crypt(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) + size_t bytes, int nrounds) { chacha_crypt_arch(state, dst, src, bytes, nrounds); } diff --git a/lib/crypto/chacha20poly1305.c b/lib/crypto/chacha20poly1305.c index ea42a28f4ff7..c3995ac8acb7 100644 --- a/lib/crypto/chacha20poly1305.c +++ b/lib/crypto/chacha20poly1305.c @@ -137,9 +137,6 @@ __chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, __le64 lens[2]; } b; - if (unlikely(src_len < POLY1305_DIGEST_SIZE)) - return false; - chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); poly1305_init(&poly1305_state, b.block0); @@ -162,6 +159,7 @@ __chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, if (likely(!ret)) chacha20_crypt(chacha_state, dst, src, dst_len); + chacha_zeroize_state(chacha_state); memzero_explicit(&b, sizeof(b)); return !ret; @@ -177,6 +175,9 @@ bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, __le64 iv[2]; bool ret; + if (unlikely(src_len < POLY1305_DIGEST_SIZE)) + return false; + chacha_load_key(k, key); iv[0] = 0; @@ -186,7 +187,6 @@ bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, &chacha_state); - chacha_zeroize_state(&chacha_state); memzero_explicit(iv, sizeof(iv)); memzero_explicit(k, sizeof(k)); return ret; @@ -200,6 +200,9 @@ bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, { struct chacha_state chacha_state; + if (unlikely(src_len < POLY1305_DIGEST_SIZE)) + return false; + xchacha_init(&chacha_state, key, nonce); return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, &chacha_state); diff --git a/lib/crypto/md5.c b/lib/crypto/md5.c index 3d2b017a0525..c54dbf728e0c 100644 --- a/lib/crypto/md5.c +++ b/lib/crypto/md5.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> -#include <linux/unaligned.h> #include <linux/wordpart.h> static const struct md5_block_state md5_iv = { @@ -271,7 +270,7 @@ void hmac_md5_final(struct hmac_md5_ctx *ctx, u8 out[MD5_DIGEST_SIZE]) cpu_to_le32_array(ctx->ostate.h, ARRAY_SIZE(ctx->ostate.h)); memcpy(out, ctx->ostate.h, MD5_DIGEST_SIZE); - memzero_explicit(ctx, sizeof(*ctx)); + hmac_md5_zeroize_ctx(ctx); } EXPORT_SYMBOL_GPL(hmac_md5_final); diff --git a/lib/crypto/mips/chacha-core.S b/lib/crypto/mips/chacha-core.S index 706aeb850fb0..1a2253d91af7 100644 --- a/lib/crypto/mips/chacha-core.S +++ b/lib/crypto/mips/chacha-core.S @@ -196,9 +196,9 @@ CONCAT3(.Lchacha_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \ .text .set reorder .set noat -.globl chacha_crypt_arch -.ent chacha_crypt_arch -chacha_crypt_arch: +.globl chacha_crypt_mips +.ent chacha_crypt_mips +chacha_crypt_mips: .frame $sp, STACK_SIZE, $ra /* Load number of rounds */ @@ -414,7 +414,7 @@ chacha_crypt_arch: /* Jump table */ FOR_EACH_WORD(JMPTBL_UNALIGNED) -.end chacha_crypt_arch +.end chacha_crypt_mips .set at /* Input arguments diff --git a/lib/crypto/mips/chacha.h b/lib/crypto/mips/chacha.h index 0c18c0dc2a40..15b39c744c28 100644 --- a/lib/crypto/mips/chacha.h +++ b/lib/crypto/mips/chacha.h @@ -6,9 +6,26 @@ */ #include <linux/kernel.h> +#include <linux/sizes.h> -asmlinkage void chacha_crypt_arch(struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int bytes, int nrounds); +asmlinkage void chacha_crypt_mips(struct chacha_state *state, u8 *dst, + const u8 *src, size_t bytes, int nrounds); asmlinkage void hchacha_block_arch(const struct chacha_state *state, u32 out[HCHACHA_OUT_WORDS], int nrounds); + +static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, + const u8 *src, size_t bytes, int nrounds) +{ + /* + * chacha_crypt_mips() compares the length as a signed value, so pass + * it at most 1 GiB at a time. + */ + do { + size_t todo = min(bytes, SZ_1G); + + chacha_crypt_mips(state, dst, src, todo, nrounds); + bytes -= todo; + src += todo; + dst += todo; + } while (bytes); +} diff --git a/lib/crypto/mips/poly1305.h b/lib/crypto/mips/poly1305.h index 85de450f1a93..9e9147f40d17 100644 --- a/lib/crypto/mips/poly1305.h +++ b/lib/crypto/mips/poly1305.h @@ -8,7 +8,7 @@ asmlinkage void poly1305_block_init(struct poly1305_block_state *state, const u8 raw_key[POLY1305_BLOCK_SIZE]); asmlinkage void poly1305_blocks(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_emit(const struct poly1305_state *state, u8 digest[POLY1305_DIGEST_SIZE], const u32 nonce[4]); diff --git a/lib/crypto/poly1305-donna32.c b/lib/crypto/poly1305-donna32.c index b66131b3f6d4..5977785cd76e 100644 --- a/lib/crypto/poly1305-donna32.c +++ b/lib/crypto/poly1305-donna32.c @@ -31,7 +31,7 @@ EXPORT_SYMBOL(poly1305_core_setkey); void poly1305_core_blocks(struct poly1305_state *state, const struct poly1305_core_key *key, const void *src, - unsigned int nblocks, u32 hibit) + size_t nblocks, u32 hibit) { const u8 *input = src; u32 r0, r1, r2, r3, r4; diff --git a/lib/crypto/poly1305-donna64.c b/lib/crypto/poly1305-donna64.c index 8a72a5a84944..d0e4234c1c4c 100644 --- a/lib/crypto/poly1305-donna64.c +++ b/lib/crypto/poly1305-donna64.c @@ -32,7 +32,7 @@ EXPORT_SYMBOL(poly1305_core_setkey); void poly1305_core_blocks(struct poly1305_state *state, const struct poly1305_core_key *key, const void *src, - unsigned int nblocks, u32 hibit) + size_t nblocks, u32 hibit) { const u8 *input = src; u64 hibit64; diff --git a/lib/crypto/poly1305.c b/lib/crypto/poly1305.c index 048c7afe8613..f08abf4c0a62 100644 --- a/lib/crypto/poly1305.c +++ b/lib/crypto/poly1305.c @@ -34,14 +34,14 @@ void poly1305_init(struct poly1305_desc_ctx *desc, } EXPORT_SYMBOL(poly1305_init); -void poly1305_update(struct poly1305_desc_ctx *desc, - const u8 *src, unsigned int nbytes) +void poly1305_update(struct poly1305_desc_ctx *desc, const u8 *src, + size_t nbytes) { - if (desc->buflen + nbytes >= POLY1305_BLOCK_SIZE) { - unsigned int bulk_len; + if (nbytes >= POLY1305_BLOCK_SIZE - desc->buflen) { + size_t bulk_len; if (desc->buflen) { - unsigned int l = POLY1305_BLOCK_SIZE - desc->buflen; + size_t l = POLY1305_BLOCK_SIZE - desc->buflen; memcpy(&desc->buf[desc->buflen], src, l); src += l; diff --git a/lib/crypto/powerpc/chacha-p10le-8x.S b/lib/crypto/powerpc/chacha-p10le-8x.S index b29562bd5d40..7a32fc6493f1 100644 --- a/lib/crypto/powerpc/chacha-p10le-8x.S +++ b/lib/crypto/powerpc/chacha-p10le-8x.S @@ -573,7 +573,7 @@ # # void chacha_p10le_8x(const struct chacha_state *state, u8 *dst, const u8 *src, -# unsigned int len, int nrounds); +# size_t len, int nrounds); # SYM_FUNC_START(chacha_p10le_8x) .align 5 diff --git a/lib/crypto/powerpc/chacha.h b/lib/crypto/powerpc/chacha.h index 1df6e1ce31c4..706060b2fa1b 100644 --- a/lib/crypto/powerpc/chacha.h +++ b/lib/crypto/powerpc/chacha.h @@ -13,7 +13,7 @@ #include <asm/switch_to.h> asmlinkage void chacha_p10le_8x(const struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int len, int nrounds); + const u8 *src, size_t len, int nrounds); static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_p10); @@ -30,9 +30,9 @@ static void vsx_end(void) } static void chacha_p10_do_8x(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) + size_t bytes, int nrounds) { - unsigned int l = bytes & ~0x0FF; + size_t l = bytes & ~0x0FF; if (l > 0) { chacha_p10le_8x(state, dst, src, l, nrounds); @@ -49,14 +49,14 @@ static void chacha_p10_do_8x(struct chacha_state *state, u8 *dst, const u8 *src, #define hchacha_block_arch hchacha_block_generic /* not implemented yet */ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { if (!static_branch_likely(&have_p10) || bytes <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) return chacha_crypt_generic(state, dst, src, bytes, nrounds); do { - unsigned int todo = min_t(unsigned int, bytes, SZ_4K); + size_t todo = min(bytes, SZ_4K); vsx_begin(); chacha_p10_do_8x(state, dst, src, todo, nrounds); diff --git a/lib/crypto/powerpc/poly1305-p10le_64.S b/lib/crypto/powerpc/poly1305-p10le_64.S index a3c1987f1ecd..ffd5b4aa0a5b 100644 --- a/lib/crypto/powerpc/poly1305-p10le_64.S +++ b/lib/crypto/powerpc/poly1305-p10le_64.S @@ -46,11 +46,11 @@ # r4, r3, r2, r1, r0 ; # # -# poly1305_p10le_4blocks( uint8_t *k, uint32_t mlen, uint8_t *m) -# k = 32 bytes key -# r3 = k (r, s) -# r4 = mlen -# r5 = m +# void poly1305_p10le_4blocks(struct poly1305_block_state *state, const u8 *m, +# size_t mlen); +# r3 = state +# r4 = m +# r5 = mlen # #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> @@ -519,11 +519,11 @@ SYM_FUNC_END(do_mul) .endm # -# poly1305_p10le_4blocks( uint8_t *k, uint32_t mlen, uint8_t *m) -# k = 32 bytes key -# r3 = k (r, s) -# r4 = mlen -# r5 = m +# void poly1305_p10le_4blocks(struct poly1305_block_state *state, const u8 *m, +# size_t mlen); +# r3 = state +# r4 = m +# r5 = mlen # SYM_FUNC_START(poly1305_p10le_4blocks) .align 5 @@ -919,7 +919,8 @@ SYM_FUNC_END(Carry_reduction) # d2 = h0 * r0 # # -# unsigned int poly1305_test_64s(unisgned char *state, const byte *src, size_t len, highbit) +# void poly1305_64s(struct poly1305_block_state *state, const u8 *m, +# size_t mlen, int highbit); # - no highbit if final leftover block (highbit = 0) # SYM_FUNC_START(poly1305_64s) diff --git a/lib/crypto/powerpc/poly1305.h b/lib/crypto/powerpc/poly1305.h index b8ed098a0e95..f758c24b3129 100644 --- a/lib/crypto/powerpc/poly1305.h +++ b/lib/crypto/powerpc/poly1305.h @@ -10,8 +10,10 @@ #include <linux/kernel.h> #include <linux/unaligned.h> -asmlinkage void poly1305_p10le_4blocks(struct poly1305_block_state *state, const u8 *m, u32 mlen); -asmlinkage void poly1305_64s(struct poly1305_block_state *state, const u8 *m, u32 mlen, int highbit); +asmlinkage void poly1305_p10le_4blocks(struct poly1305_block_state *state, + const u8 *m, size_t mlen); +asmlinkage void poly1305_64s(struct poly1305_block_state *state, const u8 *m, + size_t mlen, int highbit); asmlinkage void poly1305_emit_64(const struct poly1305_state *state, const u32 nonce[4], u8 digest[POLY1305_DIGEST_SIZE]); static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_p10); @@ -40,7 +42,7 @@ static void poly1305_block_init(struct poly1305_block_state *dctx, } static void poly1305_blocks(struct poly1305_block_state *state, const u8 *src, - unsigned int len, u32 padbit) + size_t len, u32 padbit) { if (!static_key_enabled(&have_p10)) return poly1305_blocks_generic(state, src, len, padbit); diff --git a/lib/crypto/riscv/aes-macros.S b/lib/crypto/riscv/aes-macros.S new file mode 100644 index 000000000000..1ab18e358474 --- /dev/null +++ b/lib/crypto/riscv/aes-macros.S @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */ +// +// This file is dual-licensed, meaning that you can use it under your +// choice of either of the following two licenses: +// +// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +// +// Licensed under the Apache License 2.0 (the "License"). You can obtain +// a copy in the file LICENSE in the source distribution or at +// https://www.openssl.org/source/license.html +// +// or +// +// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu> +// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com> +// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com> +// Copyright 2024 Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file contains macros that are shared by the other aes-*.S files. The +// generated code of these macros depends on the following RISC-V extensions: +// - RV64I +// - RISC-V Vector ('V') with VLEN >= 128 +// - RISC-V Vector AES block cipher extension ('Zvkned') + +// Offsets in struct aes_enckey +#define OFFSETOF_KEYLEN 0 +#define OFFSETOF_RNDKEYS 16 + +// Loads the AES round keys from the struct aes_enckey \keyp into vector +// registers and jumps to code specific to the length of the key. Specifically: +// - If AES-128, loads round keys into v1-v11 and jumps to \label128. +// - If AES-192, loads round keys into v1-v13 and jumps to \label192. +// - If AES-256, loads round keys into v1-v15 and continues onwards. +// +// Also sets vl=4 and vtype=e32,m1,ta,ma. Clobbers \keyp, t0, and t1. +.macro aes_begin keyp, label128, label192 + lwu t0, OFFSETOF_KEYLEN(\keyp) // t0 = key length in bytes + addi \keyp, \keyp, OFFSETOF_RNDKEYS + li t1, 24 // t1 = key length for AES-192 + vsetivli zero, 4, e32, m1, ta, ma + vle32.v v1, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v2, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v3, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v4, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v5, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v6, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v7, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v8, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v9, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v10, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v11, (\keyp) + blt t0, t1, \label128 // If AES-128, goto label128. + addi \keyp, \keyp, 16 + vle32.v v12, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v13, (\keyp) + beq t0, t1, \label192 // If AES-192, goto label192. + // Else, it's AES-256. + addi \keyp, \keyp, 16 + vle32.v v14, (\keyp) + addi \keyp, \keyp, 16 + vle32.v v15, (\keyp) +.endm + +// Encrypts \data using zvkned instructions, using the round keys loaded into +// v1-v11 (for AES-128), v1-v13 (for AES-192), or v1-v15 (for AES-256). \keylen +// is the AES key length in bits. vl and vtype must already be set +// appropriately. Note that if vl > 4, multiple blocks are encrypted. +.macro aes_encrypt data, keylen + vaesz.vs \data, v1 + vaesem.vs \data, v2 + vaesem.vs \data, v3 + vaesem.vs \data, v4 + vaesem.vs \data, v5 + vaesem.vs \data, v6 + vaesem.vs \data, v7 + vaesem.vs \data, v8 + vaesem.vs \data, v9 + vaesem.vs \data, v10 +.if \keylen == 128 + vaesef.vs \data, v11 +.elseif \keylen == 192 + vaesem.vs \data, v11 + vaesem.vs \data, v12 + vaesef.vs \data, v13 +.else + vaesem.vs \data, v11 + vaesem.vs \data, v12 + vaesem.vs \data, v13 + vaesem.vs \data, v14 + vaesef.vs \data, v15 +.endif +.endm + +// Same as aes_encrypt, but decrypts instead of encrypts. +.macro aes_decrypt data, keylen +.if \keylen == 128 + vaesz.vs \data, v11 +.elseif \keylen == 192 + vaesz.vs \data, v13 + vaesdm.vs \data, v12 + vaesdm.vs \data, v11 +.else + vaesz.vs \data, v15 + vaesdm.vs \data, v14 + vaesdm.vs \data, v13 + vaesdm.vs \data, v12 + vaesdm.vs \data, v11 +.endif + vaesdm.vs \data, v10 + vaesdm.vs \data, v9 + vaesdm.vs \data, v8 + vaesdm.vs \data, v7 + vaesdm.vs \data, v6 + vaesdm.vs \data, v5 + vaesdm.vs \data, v4 + vaesdm.vs \data, v3 + vaesdm.vs \data, v2 + vaesdf.vs \data, v1 +.endm + +// Expands to aes_encrypt or aes_decrypt according to \enc, which is 1 or 0. +.macro aes_crypt data, enc, keylen +.if \enc + aes_encrypt \data, \keylen +.else + aes_decrypt \data, \keylen +.endif +.endm diff --git a/lib/crypto/riscv/aes-riscv64-zvkned-zvbb-zvkg.S b/lib/crypto/riscv/aes-riscv64-zvkned-zvbb-zvkg.S new file mode 100644 index 000000000000..c45aaed80ce6 --- /dev/null +++ b/lib/crypto/riscv/aes-riscv64-zvkned-zvbb-zvkg.S @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */ +// +// This file is dual-licensed, meaning that you can use it under your +// choice of either of the following two licenses: +// +// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +// +// Licensed under the Apache License 2.0 (the "License"). You can obtain +// a copy in the file LICENSE in the source distribution or at +// https://www.openssl.org/source/license.html +// +// or +// +// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com> +// Copyright 2024 Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The generated code of this file depends on the following RISC-V extensions: +// - RV64I +// - RISC-V Vector ('V') with VLEN >= 128 && VLEN < 2048 +// - RISC-V Vector AES block cipher extension ('Zvkned') +// - RISC-V Vector Bit-manipulation extension ('Zvbb') +// - RISC-V Vector GCM/GMAC extension ('Zvkg') + +#include <linux/linkage.h> + +.text +.option arch, +zvkned, +zvbb, +zvkg + +#include "aes-macros.S" + +#define DST a0 +#define SRC a1 +#define LEN a2 +#define TWEAKP a3 +#define KEYP a4 + +#define LEN32 a5 +#define VL a7 +#define VLMAX t4 + +// v1-v15 contain the AES round keys, but they are used for temporaries before +// the AES round keys have been loaded. +#define TWEAKS v16 // LMUL=4 (most of the time) +#define TWEAKS_BREV v20 // LMUL=4 (most of the time) +#define MULTS_BREV v24 // LMUL=4 (most of the time) +#define TMP0 v28 + +// xts_init initializes the following values: +// +// TWEAKS: N 128-bit tweaks T*(x^i) for i in 0..(N - 1) +// TWEAKS_BREV: same as TWEAKS, but bit-reversed +// MULTS_BREV: N 128-bit values x^N, bit-reversed. Only if N > 1. +// +// N is the maximum number of blocks that will be processed per loop iteration, +// computed using vsetvli. +// +// The field convention used by XTS is the same as that of GHASH, but with the +// bits reversed within each byte. The zvkg extension provides the vgmul +// instruction which does multiplication in this field. Therefore, for tweak +// computation we use vgmul to do multiplications in parallel, instead of +// serially multiplying by x using shifting+xoring. Note that for this to work, +// the inputs and outputs to vgmul must be bit-reversed (we do it with vbrev8). +.macro xts_init + + // Load the first tweak T. + vsetivli zero, 4, e32, m1, ta, ma + vle32.v TWEAKS, (TWEAKP) + + // If there's only one block (or no blocks at all), then skip the tweak + // sequence computation because (at most) T itself is needed. + li t0, 16 + ble LEN, t0, .Linit_single_block\@ + + // Save a copy of T bit-reversed in v12. + vbrev8.v v12, TWEAKS + + // + // Generate x^i for i in 0..(N - 1), i.e. 128-bit values 1 << i assuming + // that N <= 128. Though, this code actually requires N < 64 (or + // equivalently VLEN < 2048) due to the use of 64-bit intermediate + // values here and in the x^N computation later. + // + vsetvli VL, LEN32, e32, m4, ta, ma + srli t0, VL, 2 // t0 = N (num blocks) + // Generate two sequences, each with N 32-bit values: + // v0=[1, 1, 1, ...] and v1=[0, 1, 2, ...]. + vsetvli zero, t0, e32, m1, ta, ma + vmv.v.i v0, 1 + vid.v v1 + // Use vzext to zero-extend the sequences to 64 bits. Reinterpret them + // as two sequences, each with 2*N 32-bit values: + // v2=[1, 0, 1, 0, 1, 0, ...] and v4=[0, 0, 1, 0, 2, 0, ...]. + vsetvli zero, t0, e64, m2, ta, ma + vzext.vf2 v2, v0 + vzext.vf2 v4, v1 + slli t1, t0, 1 // t1 = 2*N + vsetvli zero, t1, e32, m2, ta, ma + // Use vwsll to compute [1<<0, 0<<0, 1<<1, 0<<0, 1<<2, 0<<0, ...], + // widening to 64 bits per element. When reinterpreted as N 128-bit + // values, this is the needed sequence of 128-bit values 1 << i (x^i). + vwsll.vv v8, v2, v4 + + // Copy the bit-reversed T to all N elements of TWEAKS_BREV, then + // multiply by x^i. This gives the sequence T*(x^i), bit-reversed. + vsetvli zero, LEN32, e32, m4, ta, ma + vmv.v.i TWEAKS_BREV, 0 + vaesz.vs TWEAKS_BREV, v12 + vbrev8.v v8, v8 + vgmul.vv TWEAKS_BREV, v8 + + // Save a copy of the sequence T*(x^i) with the bit reversal undone. + vbrev8.v TWEAKS, TWEAKS_BREV + + // Generate N copies of x^N, i.e. 128-bit values 1 << N, bit-reversed. + li t1, 1 + sll t1, t1, t0 // t1 = 1 << N + vsetivli zero, 2, e64, m1, ta, ma + vmv.v.i v0, 0 + vsetivli zero, 1, e64, m1, tu, ma + vmv.v.x v0, t1 + vbrev8.v v0, v0 + vsetvli zero, LEN32, e32, m4, ta, ma + vmv.v.i MULTS_BREV, 0 + vaesz.vs MULTS_BREV, v0 + + j .Linit_done\@ + +.Linit_single_block\@: + vbrev8.v TWEAKS_BREV, TWEAKS +.Linit_done\@: +.endm + +// Set the first 128 bits of MULTS_BREV to 0x40, i.e. 'x' bit-reversed. This is +// the multiplier required to advance the tweak by one. +.macro load_x + li t0, 0x40 + vsetivli zero, 4, e32, m1, ta, ma + vmv.v.i MULTS_BREV, 0 + vsetivli zero, 1, e8, m1, tu, ma + vmv.v.x MULTS_BREV, t0 +.endm + +.macro __aes_xts_crypt enc, keylen + vsetvli VLMAX, zero, e32, m4, ta, ma +1: + vsetvli VL, LEN32, e32, m4, ta, ma +2: + // Encrypt or decrypt VL/4 blocks. + vle32.v TMP0, (SRC) + vxor.vv TMP0, TMP0, TWEAKS + aes_crypt TMP0, \enc, \keylen + vxor.vv TMP0, TMP0, TWEAKS + vse32.v TMP0, (DST) + + // Update the pointers and the remaining length. + slli t0, VL, 2 + add SRC, SRC, t0 + add DST, DST, t0 + sub LEN32, LEN32, VL + + // Check whether more blocks remain. + beqz LEN32, .Lmain_loop_done\@ + + // Compute the next sequence of tweaks by multiplying the previous + // sequence by x^N. Store the result in both bit-reversed order and + // regular order (i.e. with the bit reversal undone). + vgmul.vv TWEAKS_BREV, MULTS_BREV + vbrev8.v TWEAKS, TWEAKS_BREV + + // Since we compute the tweak multipliers x^N in advance, we require + // that each iteration process the same length except possibly the last. + // This conflicts slightly with the behavior allowed by RISC-V Vector + // Extension, where CPUs can select a lower length for both of the last + // two iterations. E.g., vl might take the sequence of values + // [16, 16, 16, 12, 12], whereas we need [16, 16, 16, 16, 8] so that we + // can use x^4 again instead of computing x^3. Therefore, we explicitly + // keep the vl at VLMAX if there is at least VLMAX remaining. + bge LEN32, VLMAX, 2b + j 1b + +.Lmain_loop_done\@: + load_x + + // Compute the next tweak. + addi t0, VL, -4 + vsetivli zero, 4, e32, m4, ta, ma + vslidedown.vx TWEAKS_BREV, TWEAKS_BREV, t0 // Extract last tweak + vsetivli zero, 4, e32, m1, ta, ma + vgmul.vv TWEAKS_BREV, MULTS_BREV // Advance to next tweak + + // Update *TWEAKP to contain the next tweak. + vbrev8.v TWEAKS, TWEAKS_BREV + vse32.v TWEAKS, (TWEAKP) + ret +.endm + +.macro aes_xts_crypt enc + srli LEN32, LEN, 2 + xts_init + aes_begin KEYP, 128f, 192f + __aes_xts_crypt \enc, 256 +128: + __aes_xts_crypt \enc, 128 +192: + __aes_xts_crypt \enc, 192 +.endm + +// void aes_xts_encrypt_zvkned_zvbb_zvkg(u8 *dst, const u8 *src, size_t len, +// u8 tweak[AES_BLOCK_SIZE], +// const struct aes_key *key); +// +// Encrypts `len` bytes of data using AES-XTS using the given `key` and `tweak`. +// `key` is just the main key; `tweak` is assumed to have already been encrypted +// by the tweak key. `len` is assumed to be a multiple of 16. `tweak` is +// updated to contain the next tweak, allowing for incremental computation. +SYM_FUNC_START(aes_xts_encrypt_zvkned_zvbb_zvkg) + aes_xts_crypt 1 +SYM_FUNC_END(aes_xts_encrypt_zvkned_zvbb_zvkg) + +// Same prototype and calling convention as the encryption function +SYM_FUNC_START(aes_xts_decrypt_zvkned_zvbb_zvkg) + aes_xts_crypt 0 +SYM_FUNC_END(aes_xts_decrypt_zvkned_zvbb_zvkg) diff --git a/lib/crypto/riscv/aes-riscv64-zvkned-zvkb.S b/lib/crypto/riscv/aes-riscv64-zvkned-zvkb.S new file mode 100644 index 000000000000..2981d8182de6 --- /dev/null +++ b/lib/crypto/riscv/aes-riscv64-zvkned-zvkb.S @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */ +// +// This file is dual-licensed, meaning that you can use it under your +// choice of either of the following two licenses: +// +// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +// +// Licensed under the Apache License 2.0 (the "License"). You can obtain +// a copy in the file LICENSE in the source distribution or at +// https://www.openssl.org/source/license.html +// +// or +// +// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com> +// Copyright 2024 Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The generated code of this file depends on the following RISC-V extensions: +// - RV64I +// - RISC-V Vector ('V') with VLEN >= 128 +// - RISC-V Vector AES block cipher extension ('Zvkned') +// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb') + +#include <linux/linkage.h> + +.text +.option arch, +zvkned, +zvkb + +#include "aes-macros.S" + +#define DST a0 +#define SRC a1 +#define LEN a2 +#define IVP a3 +#define KEYP a4 + +#define LEN32 a5 +#define VL_E32 a6 +#define VL_BLOCKS a7 + +.macro aes_ctr32_crypt keylen + // LEN32 = number of blocks, rounded up, in 32-bit words. + addi t0, LEN, 15 + srli t0, t0, 4 + slli LEN32, t0, 2 + + // Create a mask that selects the last 32-bit word of each 128-bit + // block. This is the word that contains the (big-endian) counter. + li t0, 0x88 + vsetvli t1, zero, e8, m1, ta, ma + vmv.v.x v0, t0 + + // Load the IV into v31. The last 32-bit word contains the counter. + vsetivli zero, 4, e32, m1, ta, ma + vle32.v v31, (IVP) + + // Convert the big-endian counter into little-endian. + vsetivli zero, 4, e32, m1, ta, mu + vrev8.v v31, v31, v0.t + + // Splat the IV to v16 (with LMUL=4). The number of copies is the + // maximum number of blocks that will be processed per iteration. + vsetvli zero, LEN32, e32, m4, ta, ma + vmv.v.i v16, 0 + vaesz.vs v16, v31 + + // v20 = [x, x, x, 0, x, x, x, 1, ...] + viota.m v20, v0, v0.t + // v16 = [IV0, IV1, IV2, counter+0, IV0, IV1, IV2, counter+1, ...] + vsetvli VL_E32, LEN32, e32, m4, ta, mu + vadd.vv v16, v16, v20, v0.t + + j 2f +1: + // Set the number of blocks to process in this iteration. vl=VL_E32 is + // the length in 32-bit words, i.e. 4 times the number of blocks. + vsetvli VL_E32, LEN32, e32, m4, ta, mu + + // Increment the counters by the number of blocks processed in the + // previous iteration. + vadd.vx v16, v16, VL_BLOCKS, v0.t +2: + // Prepare the AES inputs into v24. + vmv.v.v v24, v16 + vrev8.v v24, v24, v0.t // Convert counters back to big-endian. + + // Encrypt the AES inputs to create the next portion of the keystream. + aes_encrypt v24, \keylen + + // XOR the data with the keystream. + vsetvli t0, LEN, e8, m4, ta, ma + vle8.v v20, (SRC) + vxor.vv v20, v20, v24 + vse8.v v20, (DST) + + // Advance the pointers and update the remaining length. + add SRC, SRC, t0 + add DST, DST, t0 + sub LEN, LEN, t0 + sub LEN32, LEN32, VL_E32 + srli VL_BLOCKS, VL_E32, 2 + + // Repeat if more data remains. + bnez LEN, 1b + + // Update *IVP to contain the next counter. + vsetivli zero, 4, e32, m1, ta, mu + vadd.vx v16, v16, VL_BLOCKS, v0.t + vrev8.v v16, v16, v0.t // Convert counters back to big-endian. + vse32.v v16, (IVP) + + ret +.endm + +// void aes_ctr32_crypt_zvkned_zvkb(u8 *dst, const u8 *src, size_t len, +// u8 iv[16], const struct aes_enckey *key); +SYM_FUNC_START(aes_ctr32_crypt_zvkned_zvkb) + aes_begin KEYP, 128f, 192f + aes_ctr32_crypt 256 +128: + aes_ctr32_crypt 128 +192: + aes_ctr32_crypt 192 +SYM_FUNC_END(aes_ctr32_crypt_zvkned_zvkb) diff --git a/lib/crypto/riscv/aes-riscv64-zvkned.S b/lib/crypto/riscv/aes-riscv64-zvkned.S index 0d988bc3d37b..61c1f185c33d 100644 --- a/lib/crypto/riscv/aes-riscv64-zvkned.S +++ b/lib/crypto/riscv/aes-riscv64-zvkned.S @@ -48,12 +48,11 @@ .text .option arch, +zvkned -#include "../../arch/riscv/crypto/aes-macros.S" +#include "aes-macros.S" -#define RNDKEYS a0 -#define KEY_LEN a1 -#define OUTP a2 -#define INP a3 +#define KEYP a0 +#define OUTP a1 +#define INP a2 .macro __aes_crypt_zvkned enc, keybits vle32.v v16, (INP) @@ -63,7 +62,7 @@ .endm .macro aes_crypt_zvkned enc - aes_begin RNDKEYS, 128f, 192f, KEY_LEN + aes_begin KEYP, 128f, 192f __aes_crypt_zvkned \enc, 256 128: __aes_crypt_zvkned \enc, 128 @@ -71,14 +70,300 @@ __aes_crypt_zvkned \enc, 192 .endm -// void aes_encrypt_zvkned(const u32 rndkeys[], int key_len, -// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); +// void aes_encrypt_zvkned(const struct aes_enckey *key, u8 out[AES_BLOCK_SIZE], +// const u8 in[AES_BLOCK_SIZE]); SYM_FUNC_START(aes_encrypt_zvkned) aes_crypt_zvkned 1 SYM_FUNC_END(aes_encrypt_zvkned) -// void aes_decrypt_zvkned(const u32 rndkeys[], int key_len, -// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); +// void aes_decrypt_zvkned(const struct aes_key *key, u8 out[AES_BLOCK_SIZE], +// const u8 in[AES_BLOCK_SIZE]); SYM_FUNC_START(aes_decrypt_zvkned) aes_crypt_zvkned 0 SYM_FUNC_END(aes_decrypt_zvkned) + +#undef KEYP +#undef OUTP +#undef INP + +#define DST a0 +#define SRC a1 +#define LEN a2 +#define KEYP a3 + +.macro __aes_ecb_crypt enc, keylen + srli t0, LEN, 2 + // t0 is the remaining length in 32-bit words. It's a multiple of 4. +1: + vsetvli t1, t0, e32, m8, ta, ma + sub t0, t0, t1 // Subtract number of words processed + slli t1, t1, 2 // Words to bytes + vle32.v v16, (SRC) + aes_crypt v16, \enc, \keylen + vse32.v v16, (DST) + add SRC, SRC, t1 + add DST, DST, t1 + bnez t0, 1b + + ret +.endm + +.macro aes_ecb_crypt enc + aes_begin KEYP, 128f, 192f + __aes_ecb_crypt \enc, 256 +128: + __aes_ecb_crypt \enc, 128 +192: + __aes_ecb_crypt \enc, 192 +.endm + +// void aes_ecb_encrypt_zvkned(u8 *dst, const u8 *src, size_t len, +// const struct aes_enckey *key); +// +// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE). +SYM_FUNC_START(aes_ecb_encrypt_zvkned) + aes_ecb_crypt 1 +SYM_FUNC_END(aes_ecb_encrypt_zvkned) + +// void aes_ecb_decrypt_zvkned(u8 *dst, const u8 *src, size_t len, +// const struct aes_key *key); +// +// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE). +SYM_FUNC_START(aes_ecb_decrypt_zvkned) + aes_ecb_crypt 0 +SYM_FUNC_END(aes_ecb_decrypt_zvkned) + +#undef DST +#undef SRC +#undef LEN +#undef KEYP + +#define DST a0 +#define SRC a1 +#define LEN a2 +#define IVP a3 +#define KEYP a4 + +.macro aes_cbc_encrypt keylen + vle32.v v16, (IVP) // Load IV +1: + vle32.v v17, (SRC) // Load plaintext block + vxor.vv v16, v16, v17 // XOR with IV or prev ciphertext block + aes_encrypt v16, \keylen // Encrypt + vse32.v v16, (DST) // Store ciphertext block + addi SRC, SRC, 16 + addi DST, DST, 16 + addi LEN, LEN, -16 + bnez LEN, 1b + + vse32.v v16, (IVP) // Store next IV + ret +.endm + +.macro aes_cbc_decrypt keylen + srli LEN, LEN, 2 // Convert LEN from bytes to words + vle32.v v16, (IVP) // Load IV +1: + vsetvli t0, LEN, e32, m4, ta, ma + vle32.v v20, (SRC) // Load ciphertext blocks + vslideup.vi v16, v20, 4 // Setup prev ciphertext blocks + addi t1, t0, -4 + vslidedown.vx v24, v20, t1 // Save last ciphertext block + aes_decrypt v20, \keylen // Decrypt the blocks + vxor.vv v20, v20, v16 // XOR with prev ciphertext blocks + vse32.v v20, (DST) // Store plaintext blocks + vmv.v.v v16, v24 // Next "IV" is last ciphertext block + slli t1, t0, 2 // Words to bytes + add SRC, SRC, t1 + add DST, DST, t1 + sub LEN, LEN, t0 + bnez LEN, 1b + + vsetivli zero, 4, e32, m1, ta, ma + vse32.v v16, (IVP) // Store next IV + ret +.endm + +// void aes_cbc_encrypt_zvkned(u8 *dst, const u8 *src, size_t len, +// u8 iv[AES_BLOCK_SIZE], +// const struct aes_enckey *key); +// +// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE). +SYM_FUNC_START(aes_cbc_encrypt_zvkned) + aes_begin KEYP, 128f, 192f + aes_cbc_encrypt 256 +128: + aes_cbc_encrypt 128 +192: + aes_cbc_encrypt 192 +SYM_FUNC_END(aes_cbc_encrypt_zvkned) + +// void aes_cbc_decrypt_zvkned(u8 *dst, const u8 *src, size_t len, +// u8 iv[AES_BLOCK_SIZE], +// const struct aes_key *key); +// +// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE). +SYM_FUNC_START(aes_cbc_decrypt_zvkned) + aes_begin KEYP, 128f, 192f + aes_cbc_decrypt 256 +128: + aes_cbc_decrypt 128 +192: + aes_cbc_decrypt 192 +SYM_FUNC_END(aes_cbc_decrypt_zvkned) + +#undef DST +#undef SRC +#undef LEN +#undef IVP +#undef KEYP + +#define DST a0 +#define SRC a1 +#define LEN a2 +#define IVP a3 +#define KEYP a4 +#define ENC a5 + +.macro aes_cbc_cts_encrypt keylen + + // CBC-encrypt all blocks except the last. But don't store the + // second-to-last block to the output buffer yet, since it will be + // handled specially in the ciphertext stealing step. + li t0, 16 + j 2f +1: + vse32.v v16, (DST) // Store ciphertext block + addi DST, DST, 16 +2: + vle32.v v17, (SRC) // Load plaintext block + vxor.vv v16, v16, v17 // XOR with IV or prev ciphertext block + aes_encrypt v16, \keylen // Encrypt + addi SRC, SRC, 16 + addi LEN, LEN, -16 + bgt LEN, t0, 1b // Repeat if more than one block remains + + // Encrypt the last two blocks using ciphertext stealing as follows: + // C[n-1] = Encrypt(Encrypt(P[n-1] ^ C[n-2]) ^ P[n]) + // C[n] = Encrypt(P[n-1] ^ C[n-2])[0..LEN] + // + // C[i] denotes the i'th ciphertext block, and likewise P[i] the i'th + // plaintext block. Block n, the last block, may be partial; its length + // is 1 <= LEN <= 16. If there are only 2 blocks, C[n-2] means the IV. + // + // v16 already contains Encrypt(P[n-1] ^ C[n-2]). + // SRC points to P[n]. DST points to where C[n-1] should go. + // To support in-place encryption, load P[n] before storing C[n]. + addi t0, DST, 16 // Get pointer to where C[n] should go + vsetvli zero, LEN, e8, m1, tu, ma + vle8.v v17, (SRC) // Load P[n] + vse8.v v16, (t0) // Store C[n] + vxor.vv v16, v16, v17 // v16 = Encrypt(P[n-1] ^ C[n-2]) ^ P[n] + vsetivli zero, 4, e32, m1, ta, ma + aes_encrypt v16, \keylen + vse32.v v16, (DST) // Store C[n-1] + ret +.endm + +#define LEN32 t4 // Length of remaining full blocks in 32-bit words +#define LEN_MOD16 t5 // Length of message in bytes mod 16 + +.macro aes_cbc_cts_decrypt keylen + andi LEN32, LEN, ~15 + srli LEN32, LEN32, 2 + andi LEN_MOD16, LEN, 15 + + // Save C[n-2] in v28 so that it's available later during the ciphertext + // stealing step. If there are fewer than three blocks, C[n-2] means + // the IV, otherwise it means the third-to-last ciphertext block. + vmv.v.v v28, v16 // IV + add t0, LEN, -33 + bltz t0, .Lcts_decrypt_loop\@ + andi t0, t0, ~15 + add t0, t0, SRC + vle32.v v28, (t0) + + // CBC-decrypt all full blocks. For the last full block, or the last 2 + // full blocks if the message is block-aligned, this doesn't write the + // correct output blocks, because it XORs the wrong values with the raw + // AES plaintexts. But we fix this after this loop without redoing the + // AES decryptions. This approach allows more of the AES decryptions to + // be parallelized. +.Lcts_decrypt_loop\@: + vsetvli t0, LEN32, e32, m4, ta, ma + addi t1, t0, -4 + vle32.v v20, (SRC) // Load next set of ciphertext blocks + vmv.v.v v24, v16 // Get IV or last ciphertext block of prev set + vslideup.vi v24, v20, 4 // Setup prev ciphertext blocks + vslidedown.vx v16, v20, t1 // Save last ciphertext block of this set + aes_decrypt v20, \keylen // Decrypt this set of blocks + vxor.vv v24, v24, v20 // XOR prev ciphertext blocks with decrypted blocks + vse32.v v24, (DST) // Store this set of plaintext blocks + sub LEN32, LEN32, t0 + slli t0, t0, 2 // Words to bytes + add SRC, SRC, t0 + add DST, DST, t0 + bnez LEN32, .Lcts_decrypt_loop\@ + + vsetivli zero, 4, e32, m4, ta, ma + vslidedown.vx v20, v20, t1 // Extract raw plaintext of last full block + addi t0, DST, -16 // Get pointer to last full plaintext block + bnez LEN_MOD16, .Lcts_decrypt_non_block_aligned\@ + + // Block-aligned message. Just fix up the last 2 blocks. We need: + // + // P[n-1] = Decrypt(C[n]) ^ C[n-2] + // P[n] = Decrypt(C[n-1]) ^ C[n] + // + // We have C[n] in v16, Decrypt(C[n]) in v20, and C[n-2] in v28. + // Together with Decrypt(C[n-1]) ^ C[n-2] from the output buffer, this + // is everything needed to fix the output without re-decrypting blocks. + addi t1, DST, -32 // Get pointer to where P[n-1] should go + vxor.vv v20, v20, v28 // Decrypt(C[n]) ^ C[n-2] == P[n-1] + vle32.v v24, (t1) // Decrypt(C[n-1]) ^ C[n-2] + vse32.v v20, (t1) // Store P[n-1] + vxor.vv v20, v24, v16 // Decrypt(C[n-1]) ^ C[n-2] ^ C[n] == P[n] ^ C[n-2] + j .Lcts_decrypt_finish\@ + +.Lcts_decrypt_non_block_aligned\@: + // Decrypt the last two blocks using ciphertext stealing as follows: + // + // P[n-1] = Decrypt(C[n] || Decrypt(C[n-1])[LEN_MOD16..16]) ^ C[n-2] + // P[n] = (Decrypt(C[n-1]) ^ C[n])[0..LEN_MOD16] + // + // We already have Decrypt(C[n-1]) in v20 and C[n-2] in v28. + vmv.v.v v16, v20 // v16 = Decrypt(C[n-1]) + vsetvli zero, LEN_MOD16, e8, m1, tu, ma + vle8.v v20, (SRC) // v20 = C[n] || Decrypt(C[n-1])[LEN_MOD16..16] + vxor.vv v16, v16, v20 // v16 = Decrypt(C[n-1]) ^ C[n] + vse8.v v16, (DST) // Store P[n] + vsetivli zero, 4, e32, m1, ta, ma + aes_decrypt v20, \keylen // v20 = Decrypt(C[n] || Decrypt(C[n-1])[LEN_MOD16..16]) +.Lcts_decrypt_finish\@: + vxor.vv v20, v20, v28 // XOR with C[n-2] + vse32.v v20, (t0) // Store last full plaintext block + ret +.endm + +.macro aes_cbc_cts_crypt keylen + vle32.v v16, (IVP) // Load IV + beqz ENC, .Lcts_decrypt\@ + aes_cbc_cts_encrypt \keylen +.Lcts_decrypt\@: + aes_cbc_cts_decrypt \keylen +.endm + +// void aes_cbc_cts_crypt_zvkned(u8 *dst, const u8 *src, size_t len, +// const u8 iv[AES_BLOCK_SIZE], +// aes_encrypt_arg key, bool enc); +// +// Encrypts or decrypts len >= 17 bytes of data using the CS3 variant of +// AES-CBC-CTS. This is the variant that always swaps the last two blocks. +SYM_FUNC_START(aes_cbc_cts_crypt_zvkned) + aes_begin KEYP, 128f, 192f + aes_cbc_cts_crypt 256 +128: + aes_cbc_cts_crypt 128 +192: + aes_cbc_cts_crypt 192 +SYM_FUNC_END(aes_cbc_cts_crypt_zvkned) diff --git a/lib/crypto/riscv/aes.h b/lib/crypto/riscv/aes.h index 0b26f58faf2b..36e9218b507f 100644 --- a/lib/crypto/riscv/aes.h +++ b/lib/crypto/riscv/aes.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * AES using the RISC-V vector crypto extensions + * * Copyright (C) 2023 VRULL GmbH * Copyright (C) 2023 SiFive, Inc. * Copyright 2024 Google LLC @@ -9,11 +11,19 @@ #include <asm/vector.h> static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_zvkned); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_zvkned_zvkb); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_xts); -void aes_encrypt_zvkned(const u32 rndkeys[], int key_len, - u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); -void aes_decrypt_zvkned(const u32 rndkeys[], int key_len, - u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); +/* The assembly code assumes the following offsets. */ +static_assert(offsetof(struct aes_enckey, len) == 0); +static_assert(offsetof(struct aes_enckey, k.rndkeys) == 16); +static_assert(offsetof(struct aes_key, len) == 0); +static_assert(offsetof(struct aes_key, k.rndkeys) == 16); + +void aes_encrypt_zvkned(const struct aes_enckey *key, u8 out[AES_BLOCK_SIZE], + const u8 in[AES_BLOCK_SIZE]); +void aes_decrypt_zvkned(const struct aes_key *key, u8 out[AES_BLOCK_SIZE], + const u8 in[AES_BLOCK_SIZE]); static void aes_preparekey_arch(union aes_enckey_arch *k, union aes_invkey_arch *inv_k, @@ -29,7 +39,7 @@ static void aes_encrypt_arch(const struct aes_enckey *key, { if (static_branch_likely(&have_zvkned) && likely(may_use_simd())) { kernel_vector_begin(); - aes_encrypt_zvkned(key->k.rndkeys, key->len, out, in); + aes_encrypt_zvkned(key, out, in); kernel_vector_end(); } else { aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in); @@ -46,7 +56,7 @@ static void aes_decrypt_arch(const struct aes_key *key, */ if (static_branch_likely(&have_zvkned) && likely(may_use_simd())) { kernel_vector_begin(); - aes_decrypt_zvkned(key->k.rndkeys, key->len, out, in); + aes_decrypt_zvkned(key, out, in); kernel_vector_end(); } else { aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds, @@ -54,10 +64,230 @@ static void aes_decrypt_arch(const struct aes_key *key, } } +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_ECB) +void aes_ecb_encrypt_zvkned(u8 *dst, const u8 *src, size_t len, + const struct aes_enckey *key); +void aes_ecb_decrypt_zvkned(u8 *dst, const u8 *src, size_t len, + const struct aes_key *key); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_ecb_encrypt_arch aes_ecb_encrypt_arch +static bool aes_ecb_encrypt_arch(u8 *dst, const u8 *src, size_t len, + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + aes_ecb_encrypt_zvkned(dst, src, len, key); + kernel_vector_end(); + return true; +} + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_ecb_decrypt_arch aes_ecb_decrypt_arch +static bool aes_ecb_decrypt_arch(u8 *dst, const u8 *src, size_t len, + const struct aes_key *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + aes_ecb_decrypt_zvkned(dst, src, len, key); + kernel_vector_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_ECB */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC) +void aes_cbc_encrypt_zvkned(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], const struct aes_enckey *key); +void aes_cbc_decrypt_zvkned(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], const struct aes_key *key); +void aes_cbc_cts_crypt_zvkned(u8 *dst, const u8 *src, size_t len, + const u8 iv[AES_BLOCK_SIZE], + aes_encrypt_arg key, bool enc); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_cbc_encrypt_arch aes_cbc_encrypt_arch +static bool aes_cbc_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + aes_cbc_encrypt_zvkned(dst, src, len, iv, key); + kernel_vector_end(); + return true; +} + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_cbc_decrypt_arch aes_cbc_decrypt_arch +static bool aes_cbc_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_key *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + aes_cbc_decrypt_zvkned(dst, src, len, iv, key); + kernel_vector_end(); + return true; +} + +/* len can be any value greater than AES_BLOCK_SIZE here. */ +#define aes_cbc_cts_encrypt_arch aes_cbc_cts_encrypt_arch +static bool aes_cbc_cts_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + + kernel_vector_begin(); + aes_cbc_cts_crypt_zvkned(dst, src, len, iv, key, true); + kernel_vector_end(); + return true; +} + +/* len can be any value greater than AES_BLOCK_SIZE here. */ +#define aes_cbc_cts_decrypt_arch aes_cbc_cts_decrypt_arch +static bool aes_cbc_cts_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_key *key) +{ + if (!static_branch_likely(&have_zvkned) || unlikely(!may_use_simd())) + return false; + + kernel_vector_begin(); + aes_cbc_cts_crypt_zvkned(dst, src, len, iv, key, false); + kernel_vector_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_CBC */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CTR) +void aes_ctr32_crypt_zvkned_zvkb(u8 *dst, const u8 *src, size_t len, u8 iv[16], + const struct aes_enckey *key); + +static void aes_ctr_riscv(u8 *dst, const u8 *src, size_t len, + u8 ctr[AES_BLOCK_SIZE], const struct aes_enckey *key) +{ + u32 ctr32 = get_unaligned_be32(&ctr[12]); + u32 nblocks; + size_t part1_len; + + /* This assumes len <= U32_MAX * AES_BLOCK_SIZE. */ + nblocks = DIV_ROUND_UP(len, AES_BLOCK_SIZE); + ctr32 += nblocks; + + if (likely(ctr32 >= nblocks)) { + /* The low 32 bits of the counter won't overflow. */ + aes_ctr32_crypt_zvkned_zvkb(dst, src, len, ctr, key); + } else { + /* + * The low 32 bits of the counter will overflow. The + * assembly doesn't handle this case, so split the + * operation into two at the point where the overflow + * will occur. After the first part, add the carry bit. + */ + part1_len = + min(len, (size_t)(nblocks - ctr32) * AES_BLOCK_SIZE); + aes_ctr32_crypt_zvkned_zvkb(dst, src, part1_len, ctr, key); + for (int i = AES_BLOCK_SIZE - 5; i >= 0; i--) { + if (++ctr[i] != 0) + break; + } + if (part1_len < len) + aes_ctr32_crypt_zvkned_zvkb(dst + part1_len, + src + part1_len, + len - part1_len, ctr, key); + } +} + +#define aes_ctr_arch aes_ctr_arch +static bool aes_ctr_arch(u8 *dst, const u8 *src, size_t len, + u8 ctr[AES_BLOCK_SIZE], const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_zvkned_zvkb) || + unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + while (len) { + /* + * Split super long messages into chunks that each need at most + * 1 carry bit out of the low 32-bit word of the counter. Up to + * U32_MAX * AES_BLOCK_SIZE bytes could be allowed per chunk, + * but use a lower limit to guard against other errors. + */ + size_t n = min(len, round_down(S32_MAX, 32 * AES_BLOCK_SIZE)); + + aes_ctr_riscv(dst, src, n, ctr, key); + dst += n; + src += n; + len -= n; + } + kernel_vector_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_CTR */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS) +void aes_xts_encrypt_zvkned_zvbb_zvkg(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_decrypt_zvkned_zvbb_zvkg(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +static __always_inline bool +aes_xts_crypt_riscv(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont, bool enc) +{ + if (!static_branch_likely(&have_xts) || unlikely(!may_use_simd())) + return false; + kernel_vector_begin(); + if (!cont) + aes_encrypt_zvkned(&key->tweak_key, tweak, tweak); + if (enc) + aes_xts_encrypt_zvkned_zvbb_zvkg(dst, src, len, tweak, + &key->main_key); + else + aes_xts_decrypt_zvkned_zvbb_zvkg(dst, src, len, tweak, + &key->main_key); + kernel_vector_end(); + return true; +} + +#define aes_xts_encrypt_arch aes_xts_encrypt_arch +static bool aes_xts_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_riscv(dst, src, len, tweak, key, cont, true); +} + +#define aes_xts_decrypt_arch aes_xts_decrypt_arch +static bool aes_xts_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_riscv(dst, src, len, tweak, key, cont, false); +} +#endif /* CONFIG_CRYPTO_LIB_AES_XTS */ + #define aes_mod_init_arch aes_mod_init_arch static void aes_mod_init_arch(void) { if (riscv_isa_extension_available(NULL, ZVKNED) && - riscv_vector_vlen() >= 128) + riscv_vector_vlen() >= 128) { static_branch_enable(&have_zvkned); + if (riscv_isa_extension_available(NULL, ZVKB)) + static_branch_enable(&have_zvkned_zvkb); + if (riscv_isa_extension_available(NULL, ZVBB) && + riscv_isa_extension_available(NULL, ZVKG) && + riscv_vector_vlen() < 2048 /* Implementation limitation */) + static_branch_enable(&have_xts); + } } diff --git a/lib/crypto/riscv/chacha.h b/lib/crypto/riscv/chacha.h index 5c000c6aef4b..a84913c4ece8 100644 --- a/lib/crypto/riscv/chacha.h +++ b/lib/crypto/riscv/chacha.h @@ -19,11 +19,11 @@ asmlinkage void chacha_zvkb(struct chacha_state *state, const u8 *in, u8 *out, #define hchacha_block_arch hchacha_block_generic /* not implemented yet */ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { u8 block_buffer[CHACHA_BLOCK_SIZE]; - unsigned int full_blocks = bytes / CHACHA_BLOCK_SIZE; - unsigned int tail_bytes = bytes % CHACHA_BLOCK_SIZE; + size_t full_blocks = bytes / CHACHA_BLOCK_SIZE; + size_t tail_bytes = bytes % CHACHA_BLOCK_SIZE; if (!static_branch_likely(&use_zvkb) || !crypto_simd_usable()) return chacha_crypt_generic(state, dst, src, bytes, nrounds); diff --git a/lib/crypto/riscv/poly1305.h b/lib/crypto/riscv/poly1305.h index 88f3df44e355..aaf24d0f6674 100644 --- a/lib/crypto/riscv/poly1305.h +++ b/lib/crypto/riscv/poly1305.h @@ -8,7 +8,7 @@ asmlinkage void poly1305_block_init(struct poly1305_block_state *state, const u8 raw_key[POLY1305_BLOCK_SIZE]); asmlinkage void poly1305_blocks(struct poly1305_block_state *state, - const u8 *src, u32 len, u32 hibit); + const u8 *src, size_t len, u32 hibit); asmlinkage void poly1305_emit(const struct poly1305_state *state, u8 digest[POLY1305_DIGEST_SIZE], const u32 nonce[4]); diff --git a/lib/crypto/s390/chacha.h b/lib/crypto/s390/chacha.h index fd9c4a422365..fa7dfc63cb2f 100644 --- a/lib/crypto/s390/chacha.h +++ b/lib/crypto/s390/chacha.h @@ -15,7 +15,7 @@ #define hchacha_block_arch hchacha_block_generic /* not implemented yet */ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { /* s390 chacha20 implementation has 20 rounds hard-coded, * it cannot handle a block of data or less, but otherwise diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c index b687b89d97cb..c4361ef77166 100644 --- a/lib/crypto/sha1.c +++ b/lib/crypto/sha1.c @@ -275,7 +275,7 @@ void hmac_sha1_final(struct hmac_sha1_ctx *ctx, u8 out[SHA1_DIGEST_SIZE]) for (size_t i = 0; i < SHA1_DIGEST_SIZE; i += 4) put_unaligned_be32(ctx->ostate.h[i / 4], out + i); - memzero_explicit(ctx, sizeof(*ctx)); + hmac_sha1_zeroize_ctx(ctx); } EXPORT_SYMBOL_GPL(hmac_sha1_final); diff --git a/lib/siphash.c b/lib/crypto/siphash.c index 9e4e88752d2e..9e4e88752d2e 100644 --- a/lib/siphash.c +++ b/lib/crypto/siphash.c diff --git a/lib/crypto/sm3.c b/lib/crypto/sm3.c index b02b8a247adf..23059347b449 100644 --- a/lib/crypto/sm3.c +++ b/lib/crypto/sm3.c @@ -258,7 +258,7 @@ static void __sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE]) void sm3_final(struct sm3_ctx *ctx, u8 out[SM3_DIGEST_SIZE]) { __sm3_final(ctx, out); - memzero_explicit(ctx, sizeof(*ctx)); + sm3_zeroize_ctx(ctx); } EXPORT_SYMBOL_GPL(sm3_final); diff --git a/lib/crypto/sparc/aes.h b/lib/crypto/sparc/aes.h index e354aa507ee0..e1a060cf4953 100644 --- a/lib/crypto/sparc/aes.h +++ b/lib/crypto/sparc/aes.h @@ -133,6 +133,81 @@ static void aes_decrypt_arch(const struct aes_key *key, } } +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS) +void aes_sparc64_xts_encrypt_128(const u64 *key, const u64 *input, u64 *output, + size_t len, u64 tweak[2]); +void aes_sparc64_xts_encrypt_256(const u64 *key, const u64 *input, u64 *output, + size_t len, u64 tweak[2]); +void aes_sparc64_xts_decrypt_128(const u64 *key_end, const u64 *input, + u64 *output, size_t len, u64 tweak[2]); +void aes_sparc64_xts_decrypt_256(const u64 *key_end, const u64 *input, + u64 *output, size_t len, u64 tweak[2]); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +static __always_inline bool +aes_xts_crypt_sparc64(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont, bool enc) +{ + const struct aes_key *k = &key->main_key; + const u64 *rk = k->k.sparc_rndkeys; + const u64 *rk_end = rk + 2 * (k->nrounds + 1); + const u64 *in = (const u64 *)src; + u64 *out = (u64 *)dst; + u64 t[2]; + + /* The assembly code has no AES-192 and needs 8-byte aligned data. */ + if (!static_branch_likely(&have_aes_opcodes) || + k->len == AES_KEYSIZE_192 || + !IS_ALIGNED((uintptr_t)dst | (uintptr_t)src, 8)) + return false; + + if (cont) + memcpy(t, tweak, sizeof(t)); + else + aes_encrypt_arch(&key->tweak_key, (u8 *)t, tweak); + + if (k->len == AES_KEYSIZE_128) { + if (enc) { + aes_sparc64_load_encrypt_keys_128(rk); + aes_sparc64_xts_encrypt_128(rk, in, out, len, t); + } else { + aes_sparc64_load_decrypt_keys_128(rk); + aes_sparc64_xts_decrypt_128(rk_end, in, out, len, t); + } + } else { + if (enc) { + aes_sparc64_load_encrypt_keys_256(rk); + aes_sparc64_xts_encrypt_256(rk, in, out, len, t); + } else { + aes_sparc64_load_decrypt_keys_256(rk); + aes_sparc64_xts_decrypt_256(rk_end, in, out, len, t); + } + } + fprs_write(0); + + memcpy(tweak, t, sizeof(t)); + memzero_explicit(t, sizeof(t)); + return true; +} + +#define aes_xts_encrypt_arch aes_xts_encrypt_arch +static bool aes_xts_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_sparc64(dst, src, len, tweak, key, cont, true); +} + +#define aes_xts_decrypt_arch aes_xts_decrypt_arch +static bool aes_xts_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_sparc64(dst, src, len, tweak, key, cont, false); +} +#endif /* CONFIG_CRYPTO_LIB_AES_XTS */ + #define aes_mod_init_arch aes_mod_init_arch static void aes_mod_init_arch(void) { diff --git a/lib/crypto/sparc/aes_asm.S b/lib/crypto/sparc/aes_asm.S index f291174a72a1..fd90b129972f 100644 --- a/lib/crypto/sparc/aes_asm.S +++ b/lib/crypto/sparc/aes_asm.S @@ -2,6 +2,7 @@ #include <linux/linkage.h> #include <asm/opcodes.h> #include <asm/visasm.h> +#include <asm/asi.h> #define ENCRYPT_TWO_ROUNDS(KEY_BASE, I0, I1, T0, T1) \ AES_EROUND01(KEY_BASE + 0, I0, I1, T0) \ @@ -1541,3 +1542,167 @@ ENTRY(aes_sparc64_ctr_crypt_256) retl stx %g7, [%o4 + 0x08] ENDPROC(aes_sparc64_ctr_crypt_256) + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS) + /* XTS. The tweak is kept in %l0/%l1 as little-endian words, so that + * multiplying it by x is a 128-bit shift. XTS_TWEAK_BE stores it to + * a stack slot little-endian and reloads it big-endian, the byte order + * of the data. The slot is cleared before returning. + * + * A register window is needed because %g4-%g6 belong to the kernel. + * %l6 points at the slot and %l7 holds 8: an access with an immediate + * ASI cannot also take an immediate offset. + */ + +#define XTS_DOUBLE \ + srax %l1, 63, %l2; \ + and %l2, 0x87, %l2; \ + addcc %l0, %l0, %l0; \ + ADDXC_L1_L1_L1 \ + xor %l0, %l2, %l0; + +#define XTS_TWEAK_BE(A, B) \ + stxa %l0, [%l6] ASI_PL; \ + stxa %l1, [%l6 + %l7] ASI_PL; \ + ldx [%l6 + 0x00], A; \ + ldx [%l6 + 0x08], B; + + /* %i0=key (encrypt) or &key[key_len] (decrypt), %i1=input, + * %i2=output, %i3=len, %i4=tweak + */ +.macro __aes_xts_crypt enc, keylen + save %sp, -192, %sp +.if \keylen == 256 +.if \enc + mov %i0, %o0 +.else + sub %i0, 0xf0, %o0 +.endif +.endif + mov 8, %l7 + add %sp, 2047 + 176, %l6 + ldxa [%i4] ASI_PL, %l0 + ldxa [%i4 + %l7] ASI_PL, %l1 +.if \enc + ldx [%i0 + 0x00], %g1 + subcc %i3, 0x10, %i3 + be,pn %xcc, 10f + ldx [%i0 + 0x08], %g2 +.else + ldx [%i0 - 0x10], %g1 + subcc %i3, 0x10, %i3 + be,pn %xcc, 10f + ldx [%i0 - 0x08], %g2 +.endif +1: XTS_TWEAK_BE(%g3, %g7) + XTS_DOUBLE + XTS_TWEAK_BE(%l4, %l5) + XTS_DOUBLE + ldx [%i1 + 0x00], %o5 + xor %o5, %g3, %o5 + xor %o5, %g1, %o5 + MOVXTOD_O5_F0 + ldx [%i1 + 0x08], %o5 + xor %o5, %g7, %o5 + xor %o5, %g2, %o5 + MOVXTOD_O5_F2 + ldx [%i1 + 0x10], %o5 + xor %o5, %l4, %o5 + xor %o5, %g1, %o5 + MOVXTOD_O5_F4 + ldx [%i1 + 0x18], %o5 + xor %o5, %l5, %o5 + xor %o5, %g2, %o5 + MOVXTOD_O5_F6 +.if \enc && \keylen == 128 + ENCRYPT_128_2(8, 0, 2, 4, 6, 56, 58, 60, 62) +.elseif \enc + ENCRYPT_256_2(8, 0, 2, 4, 6) +.elseif \keylen == 128 + DECRYPT_128_2(8, 0, 2, 4, 6, 56, 58, 60, 62) +.else + DECRYPT_256_2(8, 0, 2, 4, 6) +.endif + MOVXTOD_G3_F60 + MOVXTOD_G7_F62 + MOVXTOD_L4_F56 + MOVXTOD_L5_F58 + fxor %f0, %f60, %f0 + fxor %f2, %f62, %f2 + fxor %f4, %f56, %f4 + fxor %f6, %f58, %f6 + std %f0, [%i2 + 0x00] + std %f2, [%i2 + 0x08] + std %f4, [%i2 + 0x10] + std %f6, [%i2 + 0x18] + subcc %i3, 0x20, %i3 + add %i1, 0x20, %i1 + brgz %i3, 1b + add %i2, 0x20, %i2 + brlz,pt %i3, 11f + nop +10: +.if \enc && \keylen == 256 + ldd [%o0 + 0xd0], %f56 + ldd [%o0 + 0xd8], %f58 + ldd [%o0 + 0xe0], %f60 + ldd [%o0 + 0xe8], %f62 +.elseif \keylen == 256 + ldd [%o0 + 0x18], %f56 + ldd [%o0 + 0x10], %f58 + ldd [%o0 + 0x08], %f60 + ldd [%o0 + 0x00], %f62 +.endif + XTS_TWEAK_BE(%g3, %g7) + XTS_DOUBLE + ldx [%i1 + 0x00], %o5 + xor %o5, %g3, %o5 + xor %o5, %g1, %o5 + MOVXTOD_O5_F0 + ldx [%i1 + 0x08], %o5 + xor %o5, %g7, %o5 + xor %o5, %g2, %o5 + MOVXTOD_O5_F2 +.if \enc && \keylen == 128 + ENCRYPT_128(8, 0, 2, 4, 6) +.elseif \enc + ENCRYPT_256(8, 0, 2, 4, 6) +.elseif \keylen == 128 + DECRYPT_128(8, 0, 2, 4, 6) +.else + DECRYPT_256(8, 0, 2, 4, 6) +.endif + MOVXTOD_G3_F4 + MOVXTOD_G7_F6 + fxor %f0, %f4, %f0 + fxor %f2, %f6, %f2 + std %f0, [%i2 + 0x00] + std %f2, [%i2 + 0x08] +11: stxa %l0, [%i4] ASI_PL + stxa %l1, [%i4 + %l7] ASI_PL + stx %g0, [%l6 + 0x00] + stx %g0, [%l6 + 0x08] + ret + restore +.endm + + .align 32 +ENTRY(aes_sparc64_xts_encrypt_128) + __aes_xts_crypt 1, 128 +ENDPROC(aes_sparc64_xts_encrypt_128) + + .align 32 +ENTRY(aes_sparc64_xts_encrypt_256) + __aes_xts_crypt 1, 256 +ENDPROC(aes_sparc64_xts_encrypt_256) + + .align 32 +ENTRY(aes_sparc64_xts_decrypt_128) + __aes_xts_crypt 0, 128 +ENDPROC(aes_sparc64_xts_decrypt_128) + + .align 32 +ENTRY(aes_sparc64_xts_decrypt_256) + __aes_xts_crypt 0, 256 +ENDPROC(aes_sparc64_xts_decrypt_256) +#endif /* CONFIG_CRYPTO_LIB_AES_XTS */ diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig index e121114624da..67026ef1e8f6 100644 --- a/lib/crypto/tests/Kconfig +++ b/lib/crypto/tests/Kconfig @@ -151,6 +151,15 @@ config CRYPTO_LIB_SHA3_KUNIT_TEST including SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128 and SHAKE256. +config CRYPTO_LIB_SIPHASH_KUNIT_TEST + tristate "KUnit tests for SipHash" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + # SipHash support is always built-in, so there's no kconfig option for + # it that needs to be depended on here. + help + KUnit tests for the SipHash cryptographically secure PRF. + config CRYPTO_LIB_SM3_KUNIT_TEST tristate "KUnit tests for SM3" if !KUNIT_ALL_TESTS depends on KUNIT && CRYPTO_LIB_SM3 diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile index c97c1d78784a..f639d76a8fb7 100644 --- a/lib/crypto/tests/Makefile +++ b/lib/crypto/tests/Makefile @@ -17,4 +17,5 @@ obj-$(CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST) += sha1_kunit.o obj-$(CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST) += sha224_kunit.o sha256_kunit.o obj-$(CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST) += sha384_kunit.o sha512_kunit.o obj-$(CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST) += sha3_kunit.o +obj-$(CONFIG_CRYPTO_LIB_SIPHASH_KUNIT_TEST) += siphash_kunit.o obj-$(CONFIG_CRYPTO_LIB_SM3_KUNIT_TEST) += sm3_kunit.o diff --git a/lib/tests/siphash_kunit.c b/lib/crypto/tests/siphash_kunit.c index 26bd4e8dc03e..26bd4e8dc03e 100644 --- a/lib/tests/siphash_kunit.c +++ b/lib/crypto/tests/siphash_kunit.c diff --git a/lib/crypto/x86/aes-aesni.S b/lib/crypto/x86/aes-aesni.S index b8c3e104a3be..6795e82c34c8 100644 --- a/lib/crypto/x86/aes-aesni.S +++ b/lib/crypto/x86/aes-aesni.S @@ -4,29 +4,156 @@ // // Copyright 2026 Google LLC // -// The code in this file supports 32-bit and 64-bit CPUs, and it doesn't require +// The code in this file supports 32-bit and 64-bit CPUs (except for +// aes_ctr64_crypt_aesni() which supports 64-bit only), and it doesn't require // AVX. It does use up to SSE4.1, which all CPUs with AES-NI have. #include <linux/linkage.h> -.section .rodata #ifdef __x86_64__ #define RODATA(label) label(%rip) -#else + +#define ARG0 %rdi +#define ARG1 %rsi +#define ARG2 %rdx +#define ARG2_32 %edx +#define ARG3 %rcx +#define ARG4 %r8 +#define TMP %rax +#define TMP_32 %eax +#define TMP_16 %ax +#define TMP_8 %al + +#else // __x86_64__ + #define RODATA(label) label + +// Caller-save GPRs and the first 3 function arguments, assuming -mregparm=3 +#define ARG0 %eax +#define ARG1 %edx +#define ARG2 %ecx +#define ARG2_32 %ecx + +// *Callee*-save GPRs. +#define ARG3 %edi +#define ARG4 %esi +#define TMP %ebx +#define TMP_32 %ebx +#define TMP_16 %bx +#define TMP_8 %bl +#endif // !__x86_64__ + +// Offsets in struct aes_key +#define OFFSETOF_NROUNDS 4 +#define OFFSETOF_ROUNDKEYS 16 +#define OFFSETOF_INVROUNDKEYS 256 + +.section .rodata +.p2align 4 +.Lxts_gf_poly: + // For XTS: a constant used when advancing the tweak by one block by + // multiplying by the polynomial 'x' in GF(2^128). The low 64 bits of + // this value represent the polynomial x^7 + x^2 + x + 1; it is the + // value that must be XOR'd into the low 64 bits of the tweak each time + // a 1 is carried out of the high 64 bits. + // + // The high 64 bits of this value is just the internal carry bit that + // exists when there's a carry out of the low 64 bits of the tweak. + .quad 0x87, 1 + +#ifdef __x86_64__ +.Lbswap_mask: + // A mask for pshufb that byte-reflects the value. + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 #endif +.Lexpandkey_mask: // A mask for pshufb that extracts the last dword, rotates it right by 8 // bits, and copies the result to all four dwords. -.p2align 4 -.Lmask: .byte 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12 - // The AES round constants, used during key expansion .Lrcon: + // The AES round constants, used during key expansion .long 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +.Lcts_permute_table: + .byte 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 + .byte 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 + .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + .byte 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 + .byte 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 + .text +// In 32-bit mode, push certain callee-saved GPRs and optionally load function +// arguments from the stack into them. Do nothing in 64-bit mode. +// +// TMP is always made available as a temporary register. +// +// \uses_arg3 is 0 to not touch ARG3, 1 to make it available as a temporary +// register only, or 2 to actually load it as an argument from the stack. +// Likewise for \uses_arg4 and ARG4. It's assumed the -mregparm=3 convention is +// being used and %esp hasn't been modified since function entry. +.macro _prologue uses_arg3=0, uses_arg4=0 +#ifdef __i386__ + .set ARG3_OFFSET, 4 // Assuming -mregparm=3 + .set ARG3_PUSHED, \uses_arg3 + .set ARG4_PUSHED, \uses_arg4 +.if \uses_arg3 + push ARG3 + .set ARG3_OFFSET, ARG3_OFFSET + 4 + .if \uses_arg3 == 2 + mov ARG3_OFFSET(%esp), ARG3 + .endif +.endif +.if \uses_arg4 + push ARG4 + .set ARG3_OFFSET, ARG3_OFFSET + 4 + .if \uses_arg4 == 2 + mov ARG3_OFFSET+4(%esp), ARG4 + .endif +.endif + push TMP + .set ARG3_OFFSET, ARG3_OFFSET + 4 +#endif // __i386__ +.endm + +.macro _reload_arg3 +#ifdef __i386__ + mov ARG3_OFFSET(%esp), ARG3 +#endif +.endm + +// Undo any pushes that _prologue did, then return. +.macro _epilogue +#ifdef __i386__ + pop TMP +.if ARG4_PUSHED + pop ARG4 +.endif +.if ARG3_PUSHED + pop ARG3 +.endif +#endif + RET +.endm + +.macro _aesenc enc, rndkey, data +.if \enc + aesenc \rndkey, \data +.else + aesdec \rndkey, \data +.endif +.endm + +.macro _aesenclast enc, rndkeylast, data +.if \enc + aesenclast \rndkeylast, \data +.else + aesdeclast \rndkeylast, \data +.endif +.endm + // Transform four dwords [a0, a1, a2, a3] in \a into // [a0, a0^a1, a0^a1^a2, a0^a1^a2^a3]. \tmp is a temporary xmm register. // @@ -71,32 +198,18 @@ .endm .macro _aes_expandkey_aesni is_aes128 -#ifdef __x86_64__ // Arguments - .set RNDKEYS, %rdi - .set INV_RNDKEYS, %rsi - .set IN_KEY, %rdx - - // Other local variables - .set RCON_PTR, %rcx - .set COUNTER, %eax -#else - // Arguments, assuming -mregparm=3 - .set RNDKEYS, %eax - .set INV_RNDKEYS, %edx - .set IN_KEY, %ecx + .set RNDKEYS, ARG0 + .set INV_RNDKEYS, ARG1 + .set IN_KEY, ARG2 // Other local variables - .set RCON_PTR, %ebx - .set COUNTER, %esi -#endif + .set RCON_PTR, ARG3 + .set COUNTER, TMP_32 .set RCON, %xmm6 .set MASK, %xmm7 -#ifdef __i386__ - push %ebx - push %esi -#endif + _prologue uses_arg3=1 .if \is_aes128 // AES-128: the first round key is simply a copy of the raw key. @@ -112,7 +225,7 @@ .endif // Generate the remaining round keys. - movdqa RODATA(.Lmask), MASK + movdqa RODATA(.Lexpandkey_mask), MASK .if \is_aes128 lea RODATA(.Lrcon), RCON_PTR mov $10, COUNTER @@ -176,11 +289,7 @@ movdqu %xmm0, 16(INV_RNDKEYS) // => Last inverse round key .Ldone\@: -#ifdef __i386__ - pop %esi - pop %ebx -#endif - RET + _epilogue .endm // void aes128_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys, @@ -195,67 +304,621 @@ SYM_FUNC_START(aes256_expandkey_aesni) _aes_expandkey_aesni 0 SYM_FUNC_END(aes256_expandkey_aesni) +// AES-encrypt (\enc=1) or AES-decrypt (\enc=0) the AESDATA registers specified +// in \vecs using the aes_enckey or aes_key pointed to by KEY. RNDKEY must be +// set to a temporary XMM register, NROUNDS to a temporary 32-bit GPR, and +// RNDKEY_PTR to a temporary full-size GPR. +.macro _do_aes enc, vecs:vararg + movl OFFSETOF_NROUNDS(KEY), NROUNDS + dec NROUNDS +.if \enc + .set rndkey0_offs, OFFSETOF_ROUNDKEYS +.else + .set rndkey0_offs, OFFSETOF_INVROUNDKEYS +.endif + + // Do the zero-th AES round. + movdqu rndkey0_offs(KEY), RNDKEY +.irp i, \vecs + pxor RNDKEY, AESDATA\i +.endr + // Do the regular AES rounds. + lea rndkey0_offs+16(KEY), RNDKEY_PTR +.Lnext_round\@: + movdqu (RNDKEY_PTR), RNDKEY + add $16, RNDKEY_PTR +.irp i, \vecs + _aesenc \enc, RNDKEY, AESDATA\i +.endr + dec NROUNDS + jnz .Lnext_round\@ + // Do the last AES round. + movdqu (RNDKEY_PTR), RNDKEY +.irp i, \vecs + _aesenclast \enc, RNDKEY, AESDATA\i +.endr +.endm + +.macro _do_aes_ecb enc, vecs:vararg +.irp i, \vecs + movdqu \i*16(SRC), AESDATA\i +.endr + _do_aes \enc, \vecs +.irp i, \vecs + movdqu AESDATA\i, \i*16(DST) +.endr +.endm + .macro _aes_crypt_aesni enc + .set DST, ARG0 + .set SRC, ARG1 + .set KEY, ARG2 + .set RNDKEY_PTR, ARG3 // Temporary register for _do_aes + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set AESDATA0, %xmm0 + .set RNDKEY, %xmm1 // Temporary register for _do_aes + + _prologue uses_arg3=1 + _do_aes_ecb \enc, 0 + _epilogue +.endm + +// void aes_encrypt_aesni(u8 dst[AES_BLOCK_SIZE], const u8 src[AES_BLOCK_SIZE], +// const struct aes_enckey *key); +SYM_FUNC_START(aes_encrypt_aesni) + _aes_crypt_aesni 1 +SYM_FUNC_END(aes_encrypt_aesni) + +// void aes_decrypt_aesni(u8 dst[AES_BLOCK_SIZE], const u8 src[AES_BLOCK_SIZE], +// const struct aes_key *key); +SYM_FUNC_START(aes_decrypt_aesni) + _aes_crypt_aesni 0 +SYM_FUNC_END(aes_decrypt_aesni) + +.macro _ecb_crypt enc + // Arguments + .set DST, ARG0 + .set SRC, ARG1 + .set NBLOCKS, ARG2 + .set NBLOCKS32, ARG2_32 // Used for improved code density + .set KEY, ARG3 + + // Other local variables + .set RNDKEY_PTR, ARG4 // Temporary register for _do_aes + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set AESDATA0, %xmm0 + .set AESDATA1, %xmm1 + .set AESDATA2, %xmm2 + .set AESDATA3, %xmm3 + .set RNDKEY, %xmm4 // Temporary register for _do_aes + _prologue uses_arg3=2, uses_arg4=1 + + sub $4, NBLOCKS + jl .Lecb_loop4_done\@ +.p2align 5 +.Lecb_loop4\@: + _do_aes_ecb \enc, 0,1,2,3 + add $64, SRC + add $64, DST + sub $4, NBLOCKS + jge .Lecb_loop4\@ +.Lecb_loop4_done\@: + add $4, NBLOCKS32 + jz .Lecb_done\@ + +.Lecb_loop1\@: + _do_aes_ecb \enc, 0 + add $16, SRC + add $16, DST + dec NBLOCKS32 + jnz .Lecb_loop1\@ + +.Lecb_done\@: + _epilogue +.endm + +// void aes_ecb_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// const struct aes_enckey *key); +SYM_FUNC_START(aes_ecb_encrypt_aesni) + _ecb_crypt 1 +SYM_FUNC_END(aes_ecb_encrypt_aesni) + +// void aes_ecb_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// const struct aes_key *key); +SYM_FUNC_START(aes_ecb_decrypt_aesni) + _ecb_crypt 0 +SYM_FUNC_END(aes_ecb_decrypt_aesni) + +// void aes_cbc_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// u8 iv[AES_BLOCK_SIZE], +// const struct aes_enckey *key); +// +// This assumes nblocks > 0. +SYM_FUNC_START(aes_cbc_encrypt_aesni) + // Arguments + .set DST, ARG0 + .set SRC, ARG1 + .set NBLOCKS, ARG2 + .set IV_PTR, ARG3 + .set KEY, ARG4 + + // Other local variables #ifdef __x86_64__ - .set RNDKEYS, %rdi - .set NROUNDS, %esi - .set OUT, %rdx - .set IN, %rcx + .set RNDKEY_PTR, %r9 // Temporary register for _do_aes #else - // Assuming -mregparm=3 - .set RNDKEYS, %eax - .set NROUNDS, %edx - .set OUT, %ecx - .set IN, %ebx // Passed on stack + .set RNDKEY_PTR, IV_PTR // IV_PTR is clobbered and reloaded later #endif + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set AESDATA0, %xmm0 + .set PTEXT, %xmm1 + .set RNDKEY, %xmm2 // Temporary register for _do_aes + _prologue uses_arg3=2, uses_arg4=2 -#ifdef __i386__ - push %ebx - mov 8(%esp), %ebx + movdqu (IV_PTR), AESDATA0 +.p2align 5 +.Lcbc_enc_loop: + movdqu (SRC), PTEXT + pxor PTEXT, AESDATA0 + _do_aes 1, 0 + movdqu AESDATA0, (DST) + add $16, SRC + add $16, DST + dec NBLOCKS + jnz .Lcbc_enc_loop + + // Store the next IV. On 32-bit, reload IV_PTR from stack first. + _reload_arg3 + movdqu AESDATA0, (IV_PTR) + _epilogue +SYM_FUNC_END(aes_cbc_encrypt_aesni) + +// void aes_cbc_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// u8 iv[AES_BLOCK_SIZE], const struct aes_key *key); +SYM_FUNC_START(aes_cbc_decrypt_aesni) + // Arguments + .set DST, ARG0 + .set SRC, ARG1 + .set NBLOCKS, ARG2 + .set NBLOCKS32, ARG2_32 // Used for improved code density + .set IV_PTR, ARG3 + .set KEY, ARG4 + + // Other local variables +#ifdef __x86_64__ + .set RNDKEY_PTR, %r9 // Temporary register for _do_aes +#else + .set RNDKEY_PTR, IV_PTR // IV_PTR is clobbered and reloaded later +#endif + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set AESDATA0, %xmm0 + .set AESDATA1, %xmm1 + .set AESDATA2, %xmm2 + .set AESDATA3, %xmm3 + .set RNDKEY, %xmm4 // Temporary register for _do_aes + .set IV, %xmm5 + .set CTEXT0, %xmm6 + .set CTEXT1, %xmm7 +#ifdef __x86_64__ + .set CTEXT2, %xmm8 + .set CTEXT3, %xmm9 #endif + _prologue uses_arg3=2, uses_arg4=2 - // Zero-th round - movdqu (IN), %xmm0 - movdqu (RNDKEYS), %xmm1 - pxor %xmm1, %xmm0 + movdqu (IV_PTR), IV - // Normal rounds - add $16, RNDKEYS - dec NROUNDS -.Lnext_round\@: - movdqu (RNDKEYS), %xmm1 + sub $4, NBLOCKS + jl .Lcbc_dec_loop4_done +.p2align 5 +.Lcbc_dec_loop4: + movdqu 0(SRC), AESDATA0 + movdqu 16(SRC), AESDATA1 + movdqu 32(SRC), AESDATA2 + movdqu 48(SRC), AESDATA3 + movdqa AESDATA0, CTEXT0 + movdqa AESDATA1, CTEXT1 +#ifdef __x86_64__ + movdqa AESDATA2, CTEXT2 + movdqa AESDATA3, CTEXT3 +#endif + _do_aes 0, 0,1,2,3 + pxor IV, AESDATA0 + pxor CTEXT0, AESDATA1 + pxor CTEXT1, AESDATA2 +#ifdef __x86_64__ + pxor CTEXT2, AESDATA3 + movdqa CTEXT3, IV +#else + movdqu 32(SRC), CTEXT0 + pxor CTEXT0, AESDATA3 + movdqu 48(SRC), IV +#endif + movdqu AESDATA0, 0(DST) + movdqu AESDATA1, 16(DST) + movdqu AESDATA2, 32(DST) + movdqu AESDATA3, 48(DST) + add $64, SRC + add $64, DST + sub $4, NBLOCKS + jge .Lcbc_dec_loop4 +.Lcbc_dec_loop4_done: + add $4, NBLOCKS32 + jz .Lcbc_dec_done + +.Lcbc_dec_loop1: + movdqu (SRC), AESDATA0 + movdqa AESDATA0, CTEXT0 + _do_aes 0, 0 + pxor IV, AESDATA0 + movdqa CTEXT0, IV + movdqu AESDATA0, (DST) + add $16, SRC + add $16, DST + dec NBLOCKS32 + jnz .Lcbc_dec_loop1 + +.Lcbc_dec_done: + // Store the next IV. On 32-bit, reload IV_PTR from stack first. + _reload_arg3 + movdqu IV, (IV_PTR) + _epilogue +SYM_FUNC_END(aes_cbc_decrypt_aesni) + +.macro _aes_cbc_cts_crypt enc + .set DST, ARG0 + .set SRC, ARG1 + .set PN_LEN, ARG2 + .set IV_PTR, ARG3 + .set KEY, ARG4 + .set RNDKEY_PTR, IV_PTR // Temporary register for _do_aes + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set RSHIFT_MASK, %xmm0 // range(16-PN_LEN,16) + [0x80, 0x80, ...] + // Must be %xmm0 for pblendvb to work. + .set LSHIFT_MASK, %xmm1 // [0x80, 0x80, ...] + range(PN_LEN) + .set AESDATA0, %xmm2 + .set AESDATA1, %xmm3 + .set RNDKEY, %xmm4 // Temporary register for _do_aes + .set IV, %xmm5 + + _prologue uses_arg3=2, uses_arg4=2 + + // Load LSHIFT_MASK and RSHIFT_MASK. + lea RODATA(.Lcts_permute_table), TMP + movdqu (TMP,PN_LEN), LSHIFT_MASK + sub PN_LEN, TMP + movdqu 32(TMP), RSHIFT_MASK + + // Load the IV, freeing up IV_PTR to reuse for RNDKEY_PTR. + movdqu (IV_PTR), IV + + // Load the second-from-last source block (P[n-1] or C[n-1]) and + // AES-en/decrypt it. In the encryption case, XOR it with the IV first. + movdqu (SRC), AESDATA0 .if \enc - aesenc %xmm1, %xmm0 -.else - aesdec %xmm1, %xmm0 + pxor IV, AESDATA0 .endif - add $16, RNDKEYS - dec NROUNDS - jne .Lnext_round\@ + _do_aes \enc, 0 + + // Load the last source block (P[n] or C[n]), left-aligned. + movdqu (SRC,PN_LEN), AESDATA1 - // Last round - movdqu (RNDKEYS), %xmm1 .if \enc - aesenclast %xmm1, %xmm0 + // Right-align P[n], XOR it with the first AES output, and AES-encrypt + // the result. This gives C[n-1] in AESDATA1. + pshufb RSHIFT_MASK, AESDATA1 + pxor AESDATA0, AESDATA1 + _do_aes 1, 1 + + // Left-align the first AES output to get left-aligned C[n]. + pshufb LSHIFT_MASK, AESDATA0 .else - aesdeclast %xmm1, %xmm0 + // Save a copy of the first AES output in %xmm6 for later. + movdqa AESDATA0, %xmm6 + + // Left-align the first AES output and XOR it with the + // already-left-aligned C[n]. This gives the left-aligned P[n]. + pshufb LSHIFT_MASK, AESDATA0 + pxor AESDATA1, AESDATA0 + + // Right-align C[n], then use RSHIFT_MASK (in %xmm0 as pblendvb's + // implicit operand) as a blend mask to select C[n] and the remaining + // bytes from the first AES output, with the result in AESDATA1. + pshufb RSHIFT_MASK, AESDATA1 + pblendvb %xmm6, AESDATA1 + + // AES-decrypt the result and XOR with the IV to get P[n-1] in AESDATA1. + _do_aes 0, 1 + pxor IV, AESDATA1 .endif - movdqu %xmm0, (OUT) + // Store the left-aligned C[n] or P[n], then C[n-1] or P[n-1]. + // Note that these stores may overlap. + movdqu AESDATA0, (DST,PN_LEN) + movdqu AESDATA1, (DST) + _epilogue +.endm -#ifdef __i386__ - pop %ebx -#endif +// void aes_cbc_cts_encrypt_aesni(u8 *dst, const u8 *src, long pn_len, +// const u8 iv[AES_BLOCK_SIZE], +// const struct aes_enckey *key); +// void aes_cbc_cts_decrypt_aesni(u8 *dst, const u8 *src, long pn_len, +// const u8 iv[AES_BLOCK_SIZE], +// const struct aes_key *key); +// +// Use the CS3 variant of ciphertext stealing to encrypt or decrypt the last two +// blocks in a message. The two blocks are located at src and consist of one +// full block of length 16 bytes and one possibly-partial block of length 1 <= +// pn_len <= 16 bytes. The output is written to dst, which may equal src. +SYM_FUNC_START(aes_cbc_cts_encrypt_aesni) + _aes_cbc_cts_crypt 1 +SYM_FUNC_END(aes_cbc_cts_encrypt_aesni) +SYM_FUNC_START(aes_cbc_cts_decrypt_aesni) + _aes_cbc_cts_crypt 0 +SYM_FUNC_END(aes_cbc_cts_decrypt_aesni) + +#ifdef __x86_64__ +// void aes_ctr64_crypt_aesni(u8 *dst, const u8 *src, s64 len, +// const u64 le_ctr[2], +// const struct aes_enckey *key); +SYM_FUNC_START(aes_ctr64_crypt_aesni) + // Arguments + .set DST, ARG0 + .set SRC, ARG1 + .set LEN, ARG2 + .set LEN32, ARG2_32 // Used for improved code density + .set LE_CTR_PTR, ARG3 // Used as temp reg after LE_CTR is loaded + .set KEY, ARG4 + + // Other local variables + .set AESDATA0, %xmm0 + .set AESDATA1, %xmm1 + .set AESDATA2, %xmm2 + .set AESDATA3, %xmm3 + .set LE_CTR, %xmm4 // Current 128-bit little endian counter + .set LE_CTR_INC, %xmm5 // Initialized to (u64[])[1, 0] + .set BSWAP_MASK, %xmm6 + .set RNDKEY, %xmm7 // Temporary register for _do_aes + .set RNDKEY_PTR, LE_CTR_PTR // Temporary register for _do_aes + .set NROUNDS, TMP_32 // Temporary register for _do_aes + + // Initialize LE_CTR, BSWAP_MASK, and LE_CTR_INC. + movdqu (LE_CTR_PTR), LE_CTR + movdqa RODATA(.Lbswap_mask), BSWAP_MASK + mov $1, TMP_32 + movd TMP_32, LE_CTR_INC + + // Encrypt and XOR four blocks (64 bytes) at a time. + sub $64, LEN + jl .Lctr_loop4_done +.p2align 5 +.Lctr_loop4: +.irp i, 0,1,2,3 + movdqa LE_CTR, AESDATA\i + pshufb BSWAP_MASK, AESDATA\i // => big endian counter + paddq LE_CTR_INC, LE_CTR +.endr + _do_aes 1, 0,1,2,3 + // AESDATA[0-3] now contain four keystream blocks. +.irp i, 0,1,2,3 + movdqu \i*16(SRC), RNDKEY // Use RNDKEY as temp register. + pxor RNDKEY, AESDATA\i + movdqu AESDATA\i, \i*16(DST) +.endr + add $64, SRC + add $64, DST + sub $64, LEN + jge .Lctr_loop4 +.Lctr_loop4_done: + add $64, LEN32 + jz .Lctr_done + + // 1 <= LEN <= 63 bytes remain. Prepare four more keystream blocks. +.irp i, 0,1,2,3 + movdqa LE_CTR, AESDATA\i + pshufb BSWAP_MASK, AESDATA\i // => big endian counter + .if \i != 3 + paddq LE_CTR_INC, LE_CTR + .endif +.endr + _do_aes 1, 0,1,2,3 + // AESDATA[0-3] now contain four keystream blocks. + + // XOR one block (16 bytes) at a time. + sub $16, LEN32 + jl .Lctr_xor_partial +.Lctr_xor1: + movdqu (SRC), RNDKEY // Use RNDKEY as temp register. + pxor RNDKEY, AESDATA0 + movdqu AESDATA0, (DST) + movdqa AESDATA1, AESDATA0 + movdqa AESDATA2, AESDATA1 + movdqa AESDATA3, AESDATA2 + add $16, SRC + add $16, DST + sub $16, LEN32 + jge .Lctr_xor1 + + // XOR the remaining LEN mod 16 bytes. +.Lctr_xor_partial: + test $8, LEN32 + jz 1f + movq AESDATA0, TMP + xor (SRC), TMP // XOR 8 bytes. + mov TMP, (DST) + add $8, SRC + add $8, DST + psrldq $8, AESDATA0 +1: + test $4, LEN32 + jz 2f + movd AESDATA0, TMP_32 + xor (SRC), TMP_32 // XOR 4 bytes. + mov TMP_32, (DST) + add $4, SRC + add $4, DST + psrldq $4, AESDATA0 +2: + test $2, LEN32 + jz 3f + movd AESDATA0, TMP_32 + xor (SRC), TMP_16 // XOR 2 bytes. + mov TMP_16, (DST) + add $2, SRC + add $2, DST + psrldq $2, AESDATA0 +3: + test $1, LEN32 + jz .Lctr_done + movd AESDATA0, TMP_32 + xor (SRC), TMP_8 // XOR 1 byte. + mov TMP_8, (DST) +.Lctr_done: RET +SYM_FUNC_END(aes_ctr64_crypt_aesni) +#endif // __x86_64__ + +// Given a 128-bit XTS tweak in the xmm register \tweak, compute the next tweak +// (by multiplying by the polynomial 'x') and write it back to \tweak. +.macro _next_tweak tweak, tmp + pshufd $0x13, \tweak, \tmp + paddq \tweak, \tweak + psrad $31, \tmp + pand GF_POLY, \tmp + pxor \tmp, \tweak .endm -// void aes_encrypt_aesni(const u32 rndkeys[], int nrounds, -// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); -SYM_FUNC_START(aes_encrypt_aesni) - _aes_crypt_aesni 1 -SYM_FUNC_END(aes_encrypt_aesni) +.macro _aes_xts_crypt enc + // Arguments + .set DST, ARG0 + .set SRC, ARG1 + .set NBLOCKS, ARG2 + .set NBLOCKS32, ARG2_32 // Used for improved code density + .set TWEAK_PTR, ARG3 + .set KEY, ARG4 -// void aes_decrypt_aesni(const u32 inv_rndkeys[], int nrounds, -// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); -SYM_FUNC_START(aes_decrypt_aesni) - _aes_crypt_aesni 0 -SYM_FUNC_END(aes_decrypt_aesni) + // Other local variables +#ifdef __x86_64__ + .set RNDKEY_PTR, %r9 // Temporary register for _do_aes +#else + .set RNDKEY_PTR, TWEAK_PTR // TWEAK_PTR is clobbered and reloaded later. +#endif + .set NROUNDS, TMP_32 // Temporary register for _do_aes + .set AESDATA0, %xmm0 + .set AESDATA1, %xmm1 + .set AESDATA2, %xmm2 + .set AESDATA3, %xmm3 + .set GF_POLY, %xmm4 + .set RNDKEY, %xmm5 // Temporary register for _do_aes + .set TWEAK, %xmm6 + .set SAVED_TWEAK0, %xmm7 +#ifdef __x86_64__ + .set SAVED_TWEAK1, %xmm8 + .set SAVED_TWEAK2, %xmm9 +#endif + + _prologue uses_arg3=2, uses_arg4=2 +#ifdef __i386__ + // Reserve 16-byte aligned space to spill two tweaks. + push %ebp + mov %esp, %ebp + and $~15, %esp + sub $32, %esp +#endif + + movdqu (TWEAK_PTR), TWEAK + movdqa RODATA(.Lxts_gf_poly), GF_POLY + + sub $4, NBLOCKS + jl .Lxts_loop4_done\@ +.p2align 5 +.Lxts_loop4\@: + // Load the next four source blocks into AESDATA[0-3] and XOR them with + // their tweaks, advancing the tweak three times in order to do so. + // Save the four tweaks for later; on 64-bit they all fit into + // registers, while on 32-bit two tweaks are spilled to the stack. +.irp i, 0,1,2,3 + movdqu \i*16(SRC), AESDATA\i + pxor TWEAK, AESDATA\i + .if \i != 3 +#ifdef __x86_64__ + movdqa TWEAK, SAVED_TWEAK\i +#else + .if \i == 0 + movdqa TWEAK, SAVED_TWEAK0 + .else + movdqa TWEAK, (\i-1)*16(%esp) + .endif +#endif + _next_tweak TWEAK, RNDKEY + .endif +.endr + + // Encrypt or decrypt the blocks. + _do_aes \enc, 0,1,2,3 + + // XOR the blocks with the saved tweaks. + pxor SAVED_TWEAK0, AESDATA0 +#ifdef __x86_64__ + pxor SAVED_TWEAK1, AESDATA1 + pxor SAVED_TWEAK2, AESDATA2 +#else + pxor (%esp), AESDATA1 + pxor 16(%esp), AESDATA2 +#endif + pxor TWEAK, AESDATA3 + + // Store the encrypted or decrypted blocks. +.irp i, 0,1,2,3 + movdqu AESDATA\i, \i*16(DST) +.endr + + _next_tweak TWEAK, RNDKEY + add $64, SRC + add $64, DST + sub $4, NBLOCKS + jge .Lxts_loop4\@ +.Lxts_loop4_done\@: + add $4, NBLOCKS32 + jz .Lxts_done\@ + +.Lxts_loop1\@: + movdqu (SRC), AESDATA0 + pxor TWEAK, AESDATA0 + _do_aes \enc, 0 + pxor TWEAK, AESDATA0 + movdqu AESDATA0, (DST) + _next_tweak TWEAK, RNDKEY + add $16, SRC + add $16, DST + dec NBLOCKS32 + jnz .Lxts_loop1\@ + +.Lxts_done\@: +#ifdef __i386__ + // Zeroize the stack buffer that tweaks were spilled to. + pxor AESDATA0, AESDATA0 + movdqa AESDATA0, (%esp) + movdqa AESDATA0, 16(%esp) + mov %ebp, %esp + pop %ebp +#endif + // Store the next tweak. On 32-bit, reload TWEAK_PTR from stack first. + _reload_arg3 + movdqu TWEAK, (TWEAK_PTR) + _epilogue +.endm + +// void aes_xts_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// u8 tweak[AES_BLOCK_SIZE], +// const struct aes_key *key); +// void aes_xts_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, +// u8 tweak[AES_BLOCK_SIZE], +// const struct aes_key *key); +// +// `tweak` must have already been encrypted by the tweak key; `key` is just the +// main key. To allow incremental computation, `tweak` is updated to contain +// the next tweak. +SYM_FUNC_START(aes_xts_encrypt_aesni) + _aes_xts_crypt 1 +SYM_FUNC_END(aes_xts_encrypt_aesni) +SYM_FUNC_START(aes_xts_decrypt_aesni) + _aes_xts_crypt 0 +SYM_FUNC_END(aes_xts_decrypt_aesni) diff --git a/lib/crypto/x86/aes-ctr-avx-x86_64.S b/lib/crypto/x86/aes-ctr-avx-x86_64.S new file mode 100644 index 000000000000..13b3e2cfae37 --- /dev/null +++ b/lib/crypto/x86/aes-ctr-avx-x86_64.S @@ -0,0 +1,570 @@ +/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */ +// +// Copyright 2025 Google LLC +// +// Author: Eric Biggers <ebiggers@google.com> +// +// This file is dual-licensed, meaning that you can use it under your choice of +// either of the following two licenses: +// +// Licensed under the Apache License 2.0 (the "License"). You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// or +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +//------------------------------------------------------------------------------ +// +// This file contains x86_64 assembly implementations of AES-CTR and AES-XCTR +// using the following sets of CPU features: +// - AES-NI && AVX +// - VAES && AVX2 +// - VAES && AVX512BW && AVX512VL && BMI2 +// +// See the function definitions at the bottom of the file for more information. + +#include <linux/linkage.h> + +// Offsets in struct aes_enckey +#define OFFSETOF_KEYLEN 0 +#define OFFSETOF_RNDKEYS 16 + +.section .rodata +.p2align 4 + +.Lbswap_mask: + .octa 0x000102030405060708090a0b0c0d0e0f + +.Lctr_pattern: + .quad 0, 0 +.Lone: + .quad 1, 0 +.Ltwo: + .quad 2, 0 + .quad 3, 0 + +.Lfour: + .quad 4, 0 + +.text + +// Move a vector between memory and a register. +.macro _vmovdqu src, dst +.if VL < 64 + vmovdqu \src, \dst +.else + vmovdqu8 \src, \dst +.endif +.endm + +// Move a vector between registers. +.macro _vmovdqa src, dst +.if VL < 64 + vmovdqa \src, \dst +.else + vmovdqa64 \src, \dst +.endif +.endm + +// Broadcast a 128-bit value from memory to all 128-bit lanes of a vector +// register. +.macro _vbroadcast128 src, dst +.if VL == 16 + vmovdqu \src, \dst +.elseif VL == 32 + vbroadcasti128 \src, \dst +.else + vbroadcasti32x4 \src, \dst +.endif +.endm + +// XOR two vectors together. +.macro _vpxor src1, src2, dst +.if VL < 64 + vpxor \src1, \src2, \dst +.else + vpxord \src1, \src2, \dst +.endif +.endm + +// Load 1 <= %ecx <= 15 bytes from the pointer \src into the xmm register \dst +// and zeroize any remaining bytes. Clobbers %rax, %rcx, and \tmp{64,32}. +.macro _load_partial_block src, dst, tmp64, tmp32 + sub $8, %ecx // LEN - 8 + jle .Lle8\@ + + // Load 9 <= LEN <= 15 bytes. + vmovq (\src), \dst // Load first 8 bytes + mov (\src, %rcx), %rax // Load last 8 bytes + neg %ecx + shl $3, %ecx + shr %cl, %rax // Discard overlapping bytes + vpinsrq $1, %rax, \dst, \dst + jmp .Ldone\@ + +.Lle8\@: + add $4, %ecx // LEN - 4 + jl .Llt4\@ + + // Load 4 <= LEN <= 8 bytes. + mov (\src), %eax // Load first 4 bytes + mov (\src, %rcx), \tmp32 // Load last 4 bytes + jmp .Lcombine\@ + +.Llt4\@: + // Load 1 <= LEN <= 3 bytes. + add $2, %ecx // LEN - 2 + movzbl (\src), %eax // Load first byte + jl .Lmovq\@ + movzwl (\src, %rcx), \tmp32 // Load last 2 bytes +.Lcombine\@: + shl $3, %ecx + shl %cl, \tmp64 + or \tmp64, %rax // Combine the two parts +.Lmovq\@: + vmovq %rax, \dst +.Ldone\@: +.endm + +// Store 1 <= %ecx <= 15 bytes from the xmm register \src to the pointer \dst. +// Clobbers %rax, %rcx, and \tmp{64,32}. +.macro _store_partial_block src, dst, tmp64, tmp32 + sub $8, %ecx // LEN - 8 + jl .Llt8\@ + + // Store 8 <= LEN <= 15 bytes. + vpextrq $1, \src, %rax + mov %ecx, \tmp32 + shl $3, %ecx + ror %cl, %rax + mov %rax, (\dst, \tmp64) // Store last LEN - 8 bytes + vmovq \src, (\dst) // Store first 8 bytes + jmp .Ldone\@ + +.Llt8\@: + add $4, %ecx // LEN - 4 + jl .Llt4\@ + + // Store 4 <= LEN <= 7 bytes. + vpextrd $1, \src, %eax + mov %ecx, \tmp32 + shl $3, %ecx + ror %cl, %eax + mov %eax, (\dst, \tmp64) // Store last LEN - 4 bytes + vmovd \src, (\dst) // Store first 4 bytes + jmp .Ldone\@ + +.Llt4\@: + // Store 1 <= LEN <= 3 bytes. + vpextrb $0, \src, 0(\dst) + cmp $-2, %ecx // LEN - 4 == -2, i.e. LEN == 2? + jl .Ldone\@ + vpextrb $1, \src, 1(\dst) + je .Ldone\@ + vpextrb $2, \src, 2(\dst) +.Ldone\@: +.endm + +// Prepare the next two vectors of AES inputs in AESDATA\i0 and AESDATA\i1, and +// XOR each with the zero-th round key. Also update LE_CTR if !\final. +.macro _prepare_2_ctr_vecs is_xctr, i0, i1, final=0 +.if \is_xctr + .if USE_AVX512 + vmovdqa64 LE_CTR, AESDATA\i0 + vpternlogd $0x96, XCTR_IV, RNDKEY0, AESDATA\i0 + .else + vpxor XCTR_IV, LE_CTR, AESDATA\i0 + vpxor RNDKEY0, AESDATA\i0, AESDATA\i0 + .endif + vpaddq LE_CTR_INC1, LE_CTR, AESDATA\i1 + + .if USE_AVX512 + vpternlogd $0x96, XCTR_IV, RNDKEY0, AESDATA\i1 + .else + vpxor XCTR_IV, AESDATA\i1, AESDATA\i1 + vpxor RNDKEY0, AESDATA\i1, AESDATA\i1 + .endif +.else + vpshufb BSWAP_MASK, LE_CTR, AESDATA\i0 + _vpxor RNDKEY0, AESDATA\i0, AESDATA\i0 + vpaddq LE_CTR_INC1, LE_CTR, AESDATA\i1 + vpshufb BSWAP_MASK, AESDATA\i1, AESDATA\i1 + _vpxor RNDKEY0, AESDATA\i1, AESDATA\i1 +.endif +.if !\final + vpaddq LE_CTR_INC2, LE_CTR, LE_CTR +.endif +.endm + +// Do all AES rounds on the data in the given AESDATA vectors, excluding the +// zero-th and last rounds. +.macro _aesenc_loop vecs:vararg + mov KEY, %rax +1: + _vbroadcast128 (%rax), RNDKEY +.irp i, \vecs + vaesenc RNDKEY, AESDATA\i, AESDATA\i +.endr + add $16, %rax + cmp %rax, RNDKEYLAST_PTR + jne 1b +.endm + +// Finalize the keystream blocks in the given AESDATA vectors by doing the last +// AES round, then XOR those keystream blocks with the corresponding data. +// Reduce latency by doing the XOR before the vaesenclast, utilizing the +// property vaesenclast(key, a) ^ b == vaesenclast(key ^ b, a). +.macro _aesenclast_and_xor vecs:vararg +.irp i, \vecs + _vpxor \i*VL(SRC), RNDKEYLAST, RNDKEY + vaesenclast RNDKEY, AESDATA\i, AESDATA\i +.endr +.irp i, \vecs + _vmovdqu AESDATA\i, \i*VL(DST) +.endr +.endm + +// XOR the keystream blocks in the specified AESDATA vectors with the +// corresponding data. +.macro _xor_data vecs:vararg +.irp i, \vecs + _vpxor \i*VL(SRC), AESDATA\i, AESDATA\i +.endr +.irp i, \vecs + _vmovdqu AESDATA\i, \i*VL(DST) +.endr +.endm + +.macro _aes_ctr_crypt is_xctr + + // Define register aliases V0-V15 that map to the xmm, ymm, or zmm + // registers according to the selected Vector Length (VL). +.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .if VL == 16 + .set V\i, %xmm\i + .elseif VL == 32 + .set V\i, %ymm\i + .elseif VL == 64 + .set V\i, %zmm\i + .else + .error "Unsupported Vector Length (VL)" + .endif +.endr + + // Function arguments + .set DST, %rdi // Pointer to next destination data + .set SRC, %rsi // Pointer to next source data + .set LEN, %rdx // Remaining length in bytes + .set LEN32, %edx // Used for improved code density +.if \is_xctr + .set XCTR_CTR, %rcx // u64 ctr; + .set XCTR_IV_PTR, %r8 // const u8 iv[AES_BLOCK_SIZE]; + .set KEY, %r9 // Initially points to the start of the + // aes_enckey, then is advanced to + // point to the index 1 round key + .set KEY32, %r9d // Available as temp register after all + // keystream blocks have been generated +.else + .set LE_CTR_PTR, %rcx // const u64 le_ctr[2]; + .set KEY, %r8 + .set KEY32, %r8d +.endif + // Note: the use of _load_partial_block and _store_partial_block at the + // end of the function assumes %rcx doesn't hold DST, SRC, LEN, or KEY. + + // Additional local variables + .set RNDKEYLAST_PTR, %r10 + .set AESDATA0, V0 + .set AESDATA0_XMM, %xmm0 + .set AESDATA1, V1 + .set AESDATA1_XMM, %xmm1 + .set AESDATA2, V2 + .set AESDATA3, V3 + .set AESDATA4, V4 + .set AESDATA5, V5 + .set AESDATA6, V6 + .set AESDATA7, V7 +.if \is_xctr + .set XCTR_IV, V8 +.else + .set BSWAP_MASK, V8 +.endif + .set LE_CTR, V9 + .set LE_CTR_XMM, %xmm9 + .set LE_CTR_INC1, V10 + .set LE_CTR_INC2, V11 + .set RNDKEY0, V12 + .set RNDKEYLAST, V13 + .set RNDKEY, V14 + + // Create the first vector of counters. +.if \is_xctr + .if VL == 16 + vmovq XCTR_CTR, LE_CTR + .elseif VL == 32 + vmovq XCTR_CTR, LE_CTR_XMM + inc XCTR_CTR + vmovq XCTR_CTR, AESDATA0_XMM + vinserti128 $1, AESDATA0_XMM, LE_CTR, LE_CTR + .else + vpbroadcastq XCTR_CTR, LE_CTR + vpsrldq $8, LE_CTR, LE_CTR + vpaddq .Lctr_pattern(%rip), LE_CTR, LE_CTR + .endif + _vbroadcast128 (XCTR_IV_PTR), XCTR_IV +.else + _vbroadcast128 (LE_CTR_PTR), LE_CTR + .if VL > 16 + vpaddq .Lctr_pattern(%rip), LE_CTR, LE_CTR + .endif + _vbroadcast128 .Lbswap_mask(%rip), BSWAP_MASK +.endif + +.if VL == 16 + _vbroadcast128 .Lone(%rip), LE_CTR_INC1 +.elseif VL == 32 + _vbroadcast128 .Ltwo(%rip), LE_CTR_INC1 +.else + _vbroadcast128 .Lfour(%rip), LE_CTR_INC1 +.endif + vpsllq $1, LE_CTR_INC1, LE_CTR_INC2 + + // Load the AES key length: 16 (AES-128), 24 (AES-192), or 32 (AES-256). + movl OFFSETOF_KEYLEN(KEY), %eax + + // Compute the pointer to the last round key. + lea OFFSETOF_RNDKEYS+6*16(KEY, %rax, 4), RNDKEYLAST_PTR + + // Load the zero-th and last round keys. + _vbroadcast128 OFFSETOF_RNDKEYS(KEY), RNDKEY0 + _vbroadcast128 (RNDKEYLAST_PTR), RNDKEYLAST + + // Make KEY point to the first round key. + add $OFFSETOF_RNDKEYS+16, KEY + + // This is the main loop, which encrypts 8 vectors of data at a time. + add $-8*VL, LEN + jl .Lloop_8x_done\@ +.Lloop_8x\@: + _prepare_2_ctr_vecs \is_xctr, 0, 1 + _prepare_2_ctr_vecs \is_xctr, 2, 3 + _prepare_2_ctr_vecs \is_xctr, 4, 5 + _prepare_2_ctr_vecs \is_xctr, 6, 7 + _aesenc_loop 0,1,2,3,4,5,6,7 + _aesenclast_and_xor 0,1,2,3,4,5,6,7 + sub $-8*VL, SRC + sub $-8*VL, DST + add $-8*VL, LEN + jge .Lloop_8x\@ +.Lloop_8x_done\@: + sub $-8*VL, LEN32 + jz .Ldone\@ + + // 1 <= LEN < 8*VL. Generate 2, 4, or 8 more vectors of keystream + // blocks, depending on the remaining LEN. + + _prepare_2_ctr_vecs \is_xctr, 0, 1 + _prepare_2_ctr_vecs \is_xctr, 2, 3 + cmp $4*VL, LEN32 + jle .Lenc_tail_atmost4vecs\@ + + // 4*VL < LEN < 8*VL. Generate 8 vectors of keystream blocks. Use the + // first 4 to XOR 4 full vectors of data. Then XOR the remaining data. + _prepare_2_ctr_vecs \is_xctr, 4, 5 + _prepare_2_ctr_vecs \is_xctr, 6, 7, final=1 + _aesenc_loop 0,1,2,3,4,5,6,7 + _aesenclast_and_xor 0,1,2,3 + vaesenclast RNDKEYLAST, AESDATA4, AESDATA0 + vaesenclast RNDKEYLAST, AESDATA5, AESDATA1 + vaesenclast RNDKEYLAST, AESDATA6, AESDATA2 + vaesenclast RNDKEYLAST, AESDATA7, AESDATA3 + sub $-4*VL, SRC + sub $-4*VL, DST + add $-4*VL, LEN32 + cmp $1*VL-1, LEN32 + jle .Lxor_tail_partial_vec_0\@ + _xor_data 0 + cmp $2*VL-1, LEN32 + jle .Lxor_tail_partial_vec_1\@ + _xor_data 1 + cmp $3*VL-1, LEN32 + jle .Lxor_tail_partial_vec_2\@ + _xor_data 2 + add $-3*VL, LEN32 + jz .Ldone\@ + sub $-3*VL, SRC + sub $-3*VL, DST + _vmovdqa AESDATA3, AESDATA0 + jmp .Lxor_tail_partial_vec_0\@ + +.Lenc_tail_atmost4vecs\@: + cmp $2*VL, LEN32 + jle .Lenc_tail_atmost2vecs\@ + + // 2*VL < LEN <= 4*VL. Generate 4 vectors of keystream blocks. Use the + // first 2 to XOR 2 full vectors of data. Then XOR the remaining data. + _aesenc_loop 0,1,2,3 + _aesenclast_and_xor 0,1 + vaesenclast RNDKEYLAST, AESDATA2, AESDATA0 + vaesenclast RNDKEYLAST, AESDATA3, AESDATA1 + sub $-2*VL, SRC + sub $-2*VL, DST + add $-2*VL, LEN32 + jmp .Lxor_tail_upto2vecs\@ + +.Lenc_tail_atmost2vecs\@: + // 1 <= LEN <= 2*VL. Generate 2 vectors of keystream blocks. Then XOR + // the remaining data. + _aesenc_loop 0,1 + vaesenclast RNDKEYLAST, AESDATA0, AESDATA0 + vaesenclast RNDKEYLAST, AESDATA1, AESDATA1 + +.Lxor_tail_upto2vecs\@: + cmp $1*VL-1, LEN32 + jle .Lxor_tail_partial_vec_0\@ + _xor_data 0 + cmp $2*VL-1, LEN32 + jle .Lxor_tail_partial_vec_1\@ + _xor_data 1 + jmp .Ldone\@ + +.Lxor_tail_partial_vec_1\@: + add $-1*VL, LEN32 + jz .Ldone\@ + sub $-1*VL, SRC + sub $-1*VL, DST + _vmovdqa AESDATA1, AESDATA0 + jmp .Lxor_tail_partial_vec_0\@ + +.Lxor_tail_partial_vec_2\@: + add $-2*VL, LEN32 + jz .Ldone\@ + sub $-2*VL, SRC + sub $-2*VL, DST + _vmovdqa AESDATA2, AESDATA0 + +.Lxor_tail_partial_vec_0\@: + // XOR the remaining 1 <= LEN < VL bytes. It's easy if masked + // loads/stores are available; otherwise it's a bit harder... +.if USE_AVX512 + mov $-1, %rax + bzhi LEN, %rax, %rax + kmovq %rax, %k1 + vmovdqu8 (SRC), AESDATA1{%k1}{z} + vpxord AESDATA1, AESDATA0, AESDATA0 + vmovdqu8 AESDATA0, (DST){%k1} +.else + .if VL == 32 + cmp $16, LEN32 + jl 1f + vpxor (SRC), AESDATA0_XMM, AESDATA1_XMM + vmovdqu AESDATA1_XMM, (DST) + add $16, SRC + add $16, DST + sub $16, LEN32 + jz .Ldone\@ + vextracti128 $1, AESDATA0, AESDATA0_XMM +1: + .endif + // Note: this assumes %rcx doesn't hold DST, SRC, LEN, or KEY. + mov LEN32, %ecx + _load_partial_block SRC, AESDATA1_XMM, KEY, KEY32 + vpxor AESDATA1_XMM, AESDATA0_XMM, AESDATA0_XMM + mov LEN32, %ecx + _store_partial_block AESDATA0_XMM, DST, KEY, KEY32 +.endif + +.Ldone\@: +.if VL > 16 + vzeroupper +.endif + RET +.endm + +// Below are the definitions of the functions generated by the above macro. +// They have the following prototypes: +// +// +// void aes_ctr64_crypt_##suffix(u8 *dst, const u8 *src, s64 len, +// const u64 le_ctr[2], +// const struct aes_enckey *key); +// +// void aes_xctr_crypt_##suffix(u8 *dst, const u8 *src, s64 len, u64 ctr, +// const u8 iv[AES_BLOCK_SIZE], +// const struct aes_enckey *key); +// +// Both functions generate |len| bytes of keystream, XOR it with the data from +// |src|, and write the result to |dst|. On non-final calls, |len| must be a +// multiple of 16. On the final call, |len| can be any value. +// +// aes_ctr64_crypt_* implement "regular" CTR, where the keystream is generated +// from a 128-bit big endian counter that increments by 1 for each AES block. +// HOWEVER, to keep the assembly code simple, some of the counter management is +// left to the caller. aes_ctr64_crypt_* take the counter in little endian +// form, only increment the low 64 bits internally, do the conversion to big +// endian internally, and don't write the updated counter back to memory. The +// caller is responsible for converting the starting IV to the little endian +// le_ctr, detecting the (very rare) case of a carry out of the low 64 bits +// being needed and splitting at that point with a carry done in between, and +// updating le_ctr after each part if the message is multi-part. +// +// aes_xctr_crypt_* implement XCTR as specified in "Length-preserving encryption +// with HCTR2" (https://eprint.iacr.org/2021/1441.pdf). XCTR is an +// easier-to-implement variant of CTR that uses little endian byte order and +// eliminates carries. |ctr| is the per-message block counter starting at 1. + +.set VL, 16 +.set USE_AVX512, 0 +SYM_FUNC_START(aes_ctr64_crypt_aesni_avx) + _aes_ctr_crypt 0 +SYM_FUNC_END(aes_ctr64_crypt_aesni_avx) +SYM_FUNC_START(aes_xctr_crypt_aesni_avx) + _aes_ctr_crypt 1 +SYM_FUNC_END(aes_xctr_crypt_aesni_avx) + +.set VL, 32 +.set USE_AVX512, 0 +SYM_FUNC_START(aes_ctr64_crypt_vaes_avx2) + _aes_ctr_crypt 0 +SYM_FUNC_END(aes_ctr64_crypt_vaes_avx2) +SYM_FUNC_START(aes_xctr_crypt_vaes_avx2) + _aes_ctr_crypt 1 +SYM_FUNC_END(aes_xctr_crypt_vaes_avx2) + +.set VL, 64 +.set USE_AVX512, 1 +SYM_FUNC_START(aes_ctr64_crypt_vaes_avx512) + _aes_ctr_crypt 0 +SYM_FUNC_END(aes_ctr64_crypt_vaes_avx512) +SYM_FUNC_START(aes_xctr_crypt_vaes_avx512) + _aes_ctr_crypt 1 +SYM_FUNC_END(aes_xctr_crypt_vaes_avx512) diff --git a/lib/crypto/x86/aes-xts-avx-x86_64.S b/lib/crypto/x86/aes-xts-avx-x86_64.S new file mode 100644 index 000000000000..2c13451ea343 --- /dev/null +++ b/lib/crypto/x86/aes-xts-avx-x86_64.S @@ -0,0 +1,818 @@ +/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */ +// +// AES-XTS for modern x86_64 CPUs +// +// Copyright 2024 Google LLC +// +// Author: Eric Biggers <ebiggers@google.com> +// +//------------------------------------------------------------------------------ +// +// This file is dual-licensed, meaning that you can use it under your choice of +// either of the following two licenses: +// +// Licensed under the Apache License 2.0 (the "License"). You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// or +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +/* + * This file implements AES-XTS for modern x86_64 CPUs. To handle the + * complexities of coding for x86 SIMD, e.g. where every vector length needs + * different code, it uses a macro to generate several implementations that + * share similar source code but are targeted at different CPUs, listed below: + * + * AES-NI && AVX + * - 128-bit vectors (1 AES block per vector) + * - VEX-coded instructions + * - xmm0-xmm15 + * - This is for older CPUs that lack VAES but do have AVX. + * + * VAES && VPCLMULQDQ && AVX2 + * - 256-bit vectors (2 AES blocks per vector) + * - VEX-coded instructions + * - ymm0-ymm15 + * - This is for CPUs that have VAES but either lack AVX512 (e.g. Intel's + * Alder Lake and AMD's Zen 3) or downclock too eagerly when using zmm + * registers (e.g. Intel's Ice Lake). + * + * VAES && VPCLMULQDQ && AVX512BW && AVX512VL && BMI2 + * - 512-bit vectors (4 AES blocks per vector) + * - EVEX-coded instructions + * - zmm0-zmm31 + * - This is for CPUs that have good AVX512 support. + * + * This file doesn't have an implementation for AES-NI alone (without AVX), as + * the lack of VEX would make all the assembly code different. + * + * When we use VAES, we also use VPCLMULQDQ to parallelize the computation of + * the XTS tweaks. This avoids a bottleneck. Currently there don't seem to be + * any CPUs that support VAES but not VPCLMULQDQ. If that changes, we might + * need to start also providing an implementation using VAES alone. + * + * These assembly functions don't handle ciphertext stealing, i.e, lengths that + * aren't a multiple of 16 bytes. That case is not actually reached in the + * current use cases of AES-XTS in the kernel and is just handled by the C code. + */ + +#include <linux/linkage.h> + +// Offsets in struct aes_key +#define OFFSETOF_KEYLEN 0 +#define OFFSETOF_RNDKEYS 16 +#define OFFSETOF_INVRNDKEYS 256 + +.section .rodata +.p2align 4 +.Lgf_poly: + // The low 64 bits of this value represent the polynomial x^7 + x^2 + x + // + 1. It is the value that must be XOR'd into the low 64 bits of the + // tweak each time a 1 is carried out of the high 64 bits. + // + // The high 64 bits of this value is just the internal carry bit that + // exists when there's a carry out of the low 64 bits of the tweak. + .quad 0x87, 1 + + // These are the shift amounts that are needed when multiplying by [x^0, + // x^1, x^2, x^3] to compute the first vector of tweaks when VL=64. + // + // The right shifts by 64 are expected to zeroize the destination. + // 'vpsrlvq' is indeed defined to do that; i.e. it doesn't truncate the + // amount to 64 & 63 = 0 like the 'shr' scalar shift instruction would. +.Lrshift_amounts: + .byte 64, 64, 63, 63, 62, 62, 61, 61 +.Llshift_amounts: + .byte 0, 0, 1, 1, 2, 2, 3, 3 + +.text + +.macro _define_Vi i +.if VL == 16 + .set V\i, %xmm\i +.elseif VL == 32 + .set V\i, %ymm\i +.elseif VL == 64 + .set V\i, %zmm\i +.else + .error "Unsupported Vector Length (VL)" +.endif +.endm + +.macro _define_aliases + // Define register aliases V0-V15, or V0-V31 if all 32 SIMD registers + // are available, that map to the xmm, ymm, or zmm registers according + // to the selected Vector Length (VL). +.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + _define_Vi \i +.endr +.if USE_AVX512 +.irp i, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 + _define_Vi \i +.endr +.endif + + // Function parameters + .set DST, %rdi // Pointer to next destination data + .set SRC, %rsi // Pointer to next source data + .set NBLOCKS, %rdx // Number of blocks remaining + .set NBLOCKS32, %edx // Used for improved code density + .set TWEAK, %rcx // Pointer to next tweak + .set KEY, %r8 // Initially points to struct aes_key, then is + // advanced to point to 7th-from-last round key + + // %rax holds the AES key length in bytes. + .set KEYLEN, %eax + .set KEYLEN64, %rax + + // %r9-r11 are available as temporaries. + + // V0-V3 hold the data blocks during the main loop, or temporary values + // otherwise. V4-V5 hold temporary values. + + // V6-V9 hold XTS tweaks. Each 128-bit lane holds one tweak. + .set TWEAK0_XMM, %xmm6 + .set TWEAK0, V6 + .set TWEAK1_XMM, %xmm7 + .set TWEAK1, V7 + .set TWEAK2, V8 + .set TWEAK3, V9 + + // V10-V13 are used for computing the next values of TWEAK[0-3]. + .set NEXT_TWEAK0, V10 + .set NEXT_TWEAK1, V11 + .set NEXT_TWEAK2, V12 + .set NEXT_TWEAK3, V13 + + // V14 holds the constant from .Lgf_poly, copied to all 128-bit lanes. + .set GF_POLY_XMM, %xmm14 + .set GF_POLY, V14 + + // V15 holds the key for AES "round 0", copied to all 128-bit lanes. + .set KEY0_XMM, %xmm15 + .set KEY0, V15 + + // If 32 SIMD registers are available, then V16-V29 hold the remaining + // AES round keys, copied to all 128-bit lanes. + // + // AES-128, AES-192, and AES-256 use different numbers of round keys. + // To allow handling all three variants efficiently, we align the round + // keys to the *end* of this register range. I.e., AES-128 uses + // KEY5-KEY14, AES-192 uses KEY3-KEY14, and AES-256 uses KEY1-KEY14. + // (All also use KEY0 for the XOR-only "round" at the beginning.) +.if USE_AVX512 + .set KEY1_XMM, %xmm16 + .set KEY1, V16 + .set KEY2_XMM, %xmm17 + .set KEY2, V17 + .set KEY3_XMM, %xmm18 + .set KEY3, V18 + .set KEY4_XMM, %xmm19 + .set KEY4, V19 + .set KEY5_XMM, %xmm20 + .set KEY5, V20 + .set KEY6_XMM, %xmm21 + .set KEY6, V21 + .set KEY7_XMM, %xmm22 + .set KEY7, V22 + .set KEY8_XMM, %xmm23 + .set KEY8, V23 + .set KEY9_XMM, %xmm24 + .set KEY9, V24 + .set KEY10_XMM, %xmm25 + .set KEY10, V25 + .set KEY11_XMM, %xmm26 + .set KEY11, V26 + .set KEY12_XMM, %xmm27 + .set KEY12, V27 + .set KEY13_XMM, %xmm28 + .set KEY13, V28 + .set KEY14_XMM, %xmm29 + .set KEY14, V29 +.endif + // V30-V31 are currently unused. +.endm + +// Move a vector between memory and a register. +.macro _vmovdqu src, dst +.if VL < 64 + vmovdqu \src, \dst +.else + vmovdqu8 \src, \dst +.endif +.endm + +// Broadcast a 128-bit value into a vector. +.macro _vbroadcast128 src, dst +.if VL == 16 + vmovdqu \src, \dst +.elseif VL == 32 + vbroadcasti128 \src, \dst +.else + vbroadcasti32x4 \src, \dst +.endif +.endm + +// XOR two vectors together. +.macro _vpxor src1, src2, dst +.if VL < 64 + vpxor \src1, \src2, \dst +.else + vpxord \src1, \src2, \dst +.endif +.endm + +// XOR three vectors together. +.macro _xor3 src1, src2, src3_and_dst +.if USE_AVX512 + // vpternlogd with immediate 0x96 is a three-argument XOR. + vpternlogd $0x96, \src1, \src2, \src3_and_dst +.else + vpxor \src1, \src3_and_dst, \src3_and_dst + vpxor \src2, \src3_and_dst, \src3_and_dst +.endif +.endm + +// Given a 128-bit XTS tweak in the xmm register \src, compute the next tweak +// (by multiplying by the polynomial 'x') and write it to \dst. +.macro _next_tweak src, tmp, dst + vpshufd $0x13, \src, \tmp + vpaddq \src, \src, \dst + vpsrad $31, \tmp, \tmp +.if USE_AVX512 + vpternlogd $0x78, GF_POLY_XMM, \tmp, \dst +.else + vpand GF_POLY_XMM, \tmp, \tmp + vpxor \tmp, \dst, \dst +.endif +.endm + +// Given the XTS tweak(s) in the vector \src, compute the next vector of +// tweak(s) (by multiplying by the polynomial 'x^(VL/16)') and write it to \dst. +// +// If VL > 16, then there are multiple tweaks, and we use vpclmulqdq to compute +// all tweaks in the vector in parallel. If VL=16, we just do the regular +// computation without vpclmulqdq, as it's the faster method for a single tweak. +.macro _next_tweakvec src, tmp1, tmp2, dst +.if VL == 16 + _next_tweak \src, \tmp1, \dst +.else + vpsrlq $64 - VL/16, \src, \tmp1 + vpclmulqdq $0x01, GF_POLY, \tmp1, \tmp2 + vpslldq $8, \tmp1, \tmp1 + vpsllq $VL/16, \src, \dst + _xor3 \tmp1, \tmp2, \dst +.endif +.endm + +// Given the first XTS tweak at (TWEAK), compute the first set of tweaks and +// store them in the vector registers TWEAK0-TWEAK3. Clobbers V0-V5. +.macro _compute_first_set_of_tweaks +.if VL == 16 + vmovdqu (TWEAK), TWEAK0_XMM + vmovdqu .Lgf_poly(%rip), GF_POLY + _next_tweak TWEAK0, %xmm0, TWEAK1 + _next_tweak TWEAK1, %xmm0, TWEAK2 + _next_tweak TWEAK2, %xmm0, TWEAK3 +.elseif VL == 32 + vmovdqu (TWEAK), TWEAK0_XMM + vbroadcasti128 .Lgf_poly(%rip), GF_POLY + + // Compute the first vector of tweaks. + _next_tweak TWEAK0_XMM, %xmm0, %xmm1 + vinserti128 $1, %xmm1, TWEAK0, TWEAK0 + + // Compute the next three vectors of tweaks: + // TWEAK1 = TWEAK0 * [x^2, x^2] + // TWEAK2 = TWEAK0 * [x^4, x^4] + // TWEAK3 = TWEAK0 * [x^6, x^6] + vpsrlq $64 - 2, TWEAK0, V0 + vpsrlq $64 - 4, TWEAK0, V2 + vpsrlq $64 - 6, TWEAK0, V4 + vpclmulqdq $0x01, GF_POLY, V0, V1 + vpclmulqdq $0x01, GF_POLY, V2, V3 + vpclmulqdq $0x01, GF_POLY, V4, V5 + vpslldq $8, V0, V0 + vpslldq $8, V2, V2 + vpslldq $8, V4, V4 + vpsllq $2, TWEAK0, TWEAK1 + vpsllq $4, TWEAK0, TWEAK2 + vpsllq $6, TWEAK0, TWEAK3 + vpxor V0, TWEAK1, TWEAK1 + vpxor V2, TWEAK2, TWEAK2 + vpxor V4, TWEAK3, TWEAK3 + vpxor V1, TWEAK1, TWEAK1 + vpxor V3, TWEAK2, TWEAK2 + vpxor V5, TWEAK3, TWEAK3 +.else + vbroadcasti32x4 (TWEAK), TWEAK0 + vbroadcasti32x4 .Lgf_poly(%rip), GF_POLY + + // Compute the first vector of tweaks: + // TWEAK0 = broadcast128(TWEAK) * [x^0, x^1, x^2, x^3] + vpmovzxbq .Lrshift_amounts(%rip), V4 + vpsrlvq V4, TWEAK0, V0 + vpclmulqdq $0x01, GF_POLY, V0, V1 + vpmovzxbq .Llshift_amounts(%rip), V4 + vpslldq $8, V0, V0 + vpsllvq V4, TWEAK0, TWEAK0 + vpternlogd $0x96, V0, V1, TWEAK0 + + // Compute the next three vectors of tweaks: + // TWEAK1 = TWEAK0 * [x^4, x^4, x^4, x^4] + // TWEAK2 = TWEAK0 * [x^8, x^8, x^8, x^8] + // TWEAK3 = TWEAK0 * [x^12, x^12, x^12, x^12] + // x^8 only needs byte-aligned shifts, so optimize accordingly. + vpsrlq $64 - 4, TWEAK0, V0 + vpsrldq $(64 - 8) / 8, TWEAK0, V2 + vpsrlq $64 - 12, TWEAK0, V4 + vpclmulqdq $0x01, GF_POLY, V0, V1 + vpclmulqdq $0x01, GF_POLY, V2, V3 + vpclmulqdq $0x01, GF_POLY, V4, V5 + vpslldq $8, V0, V0 + vpslldq $8, V4, V4 + vpsllq $4, TWEAK0, TWEAK1 + vpslldq $8 / 8, TWEAK0, TWEAK2 + vpsllq $12, TWEAK0, TWEAK3 + vpternlogd $0x96, V0, V1, TWEAK1 + vpxord V3, TWEAK2, TWEAK2 + vpternlogd $0x96, V4, V5, TWEAK3 +.endif +.endm + +// Do one step in computing the next set of tweaks using the method of just +// multiplying by x repeatedly (the same method _next_tweak uses). +.macro _tweak_step_mulx i +.if \i == 0 + .set PREV_TWEAK, TWEAK3 + .set NEXT_TWEAK, NEXT_TWEAK0 +.elseif \i == 5 + .set PREV_TWEAK, NEXT_TWEAK0 + .set NEXT_TWEAK, NEXT_TWEAK1 +.elseif \i == 10 + .set PREV_TWEAK, NEXT_TWEAK1 + .set NEXT_TWEAK, NEXT_TWEAK2 +.elseif \i == 15 + .set PREV_TWEAK, NEXT_TWEAK2 + .set NEXT_TWEAK, NEXT_TWEAK3 +.endif +.if \i >= 0 && \i < 20 && \i % 5 == 0 + vpshufd $0x13, PREV_TWEAK, V5 +.elseif \i >= 0 && \i < 20 && \i % 5 == 1 + vpaddq PREV_TWEAK, PREV_TWEAK, NEXT_TWEAK +.elseif \i >= 0 && \i < 20 && \i % 5 == 2 + vpsrad $31, V5, V5 +.elseif \i >= 0 && \i < 20 && \i % 5 == 3 + vpand GF_POLY, V5, V5 +.elseif \i >= 0 && \i < 20 && \i % 5 == 4 + vpxor V5, NEXT_TWEAK, NEXT_TWEAK +.elseif \i == 1000 + vmovdqa NEXT_TWEAK0, TWEAK0 + vmovdqa NEXT_TWEAK1, TWEAK1 + vmovdqa NEXT_TWEAK2, TWEAK2 + vmovdqa NEXT_TWEAK3, TWEAK3 +.endif +.endm + +// Do one step in computing the next set of tweaks using the VPCLMULQDQ method +// (the same method _next_tweakvec uses for VL > 16). This means multiplying +// each tweak by x^(4*VL/16) independently. +// +// Since 4*VL/16 is a multiple of 8 when VL > 16 (which it is here), the needed +// shift amounts are byte-aligned, which allows the use of vpsrldq and vpslldq +// to do 128-bit wide shifts. The 128-bit left shift (vpslldq) saves +// instructions directly. The 128-bit right shift (vpsrldq) performs better +// than a 64-bit right shift on Intel CPUs in the context where it is used here, +// because it runs on a different execution port from the AES instructions. +.macro _tweak_step_pclmul i +.if \i == 0 + vpsrldq $(128 - 4*VL/16) / 8, TWEAK0, NEXT_TWEAK0 +.elseif \i == 2 + vpsrldq $(128 - 4*VL/16) / 8, TWEAK1, NEXT_TWEAK1 +.elseif \i == 4 + vpsrldq $(128 - 4*VL/16) / 8, TWEAK2, NEXT_TWEAK2 +.elseif \i == 6 + vpsrldq $(128 - 4*VL/16) / 8, TWEAK3, NEXT_TWEAK3 +.elseif \i == 8 + vpclmulqdq $0x00, GF_POLY, NEXT_TWEAK0, NEXT_TWEAK0 +.elseif \i == 10 + vpclmulqdq $0x00, GF_POLY, NEXT_TWEAK1, NEXT_TWEAK1 +.elseif \i == 12 + vpclmulqdq $0x00, GF_POLY, NEXT_TWEAK2, NEXT_TWEAK2 +.elseif \i == 14 + vpclmulqdq $0x00, GF_POLY, NEXT_TWEAK3, NEXT_TWEAK3 +.elseif \i == 1000 + vpslldq $(4*VL/16) / 8, TWEAK0, TWEAK0 + vpslldq $(4*VL/16) / 8, TWEAK1, TWEAK1 + vpslldq $(4*VL/16) / 8, TWEAK2, TWEAK2 + vpslldq $(4*VL/16) / 8, TWEAK3, TWEAK3 + _vpxor NEXT_TWEAK0, TWEAK0, TWEAK0 + _vpxor NEXT_TWEAK1, TWEAK1, TWEAK1 + _vpxor NEXT_TWEAK2, TWEAK2, TWEAK2 + _vpxor NEXT_TWEAK3, TWEAK3, TWEAK3 +.endif +.endm + +// _tweak_step does one step of the computation of the next set of tweaks from +// TWEAK[0-3]. To complete all steps, this is invoked with increasing values of +// \i that include at least 0 through 19, then 1000 which signals the last step. +// +// This is used to interleave the computation of the next set of tweaks with the +// AES en/decryptions, which increases performance in some cases. Clobbers V5. +.macro _tweak_step i +.if VL == 16 + _tweak_step_mulx \i +.else + _tweak_step_pclmul \i +.endif +.endm + +.macro _setup_round_keys enc + + // Select either the encryption round keys or the decryption round keys. +.if \enc + .set OFFS, OFFSETOF_RNDKEYS +.else + .set OFFS, OFFSETOF_INVRNDKEYS +.endif + + // Load the round key for "round 0". + _vbroadcast128 OFFS(KEY), KEY0 + + // Increment KEY to make it so that 7*16(KEY) is the last round key. + // For AES-128, increment by 3*16, resulting in the 10 round keys (not + // counting the zero-th round key which was just loaded into KEY0) being + // -2*16(KEY) through 7*16(KEY). For AES-192, increment by 5*16 and use + // 12 round keys -4*16(KEY) through 7*16(KEY). For AES-256, increment + // by 7*16 and use 14 round keys -6*16(KEY) through 7*16(KEY). + // + // This rebasing provides two benefits. First, it makes the offset to + // any round key be in the range [-96, 112], fitting in a signed byte. + // This shortens VEX-encoded instructions that access the later round + // keys which otherwise would need 4-byte offsets. Second, it makes it + // easy to do AES-128 and AES-192 by skipping irrelevant rounds at the + // beginning. Skipping rounds at the end doesn't work as well because + // the last round needs different instructions. + // + // An alternative approach would be to roll up all the round loops. We + // don't do that because (a) it isn't compatible with caching the round + // keys in registers which we do when possible (see below), (b) we + // interleave the AES rounds with the XTS tweak computation, and (c) it + // seems unwise to rely *too* heavily on the CPU's branch predictor. + lea OFFS-16(KEY, KEYLEN64, 4), KEY + + // If all 32 SIMD registers are available, cache all the round keys. +.if USE_AVX512 + cmp $24, KEYLEN + jl .Laes128\@ + je .Laes192\@ + vbroadcasti32x4 -6*16(KEY), KEY1 + vbroadcasti32x4 -5*16(KEY), KEY2 +.Laes192\@: + vbroadcasti32x4 -4*16(KEY), KEY3 + vbroadcasti32x4 -3*16(KEY), KEY4 +.Laes128\@: + vbroadcasti32x4 -2*16(KEY), KEY5 + vbroadcasti32x4 -1*16(KEY), KEY6 + vbroadcasti32x4 0*16(KEY), KEY7 + vbroadcasti32x4 1*16(KEY), KEY8 + vbroadcasti32x4 2*16(KEY), KEY9 + vbroadcasti32x4 3*16(KEY), KEY10 + vbroadcasti32x4 4*16(KEY), KEY11 + vbroadcasti32x4 5*16(KEY), KEY12 + vbroadcasti32x4 6*16(KEY), KEY13 + vbroadcasti32x4 7*16(KEY), KEY14 +.endif +.endm + +// Do a single non-last round of AES encryption (if \enc==1) or decryption (if +// \enc==0) on the block(s) in \data using the round key(s) in \key. The +// register length determines the number of AES blocks en/decrypted. +.macro _vaes enc, key, data +.if \enc + vaesenc \key, \data, \data +.else + vaesdec \key, \data, \data +.endif +.endm + +// Same as _vaes, but does the last round. +.macro _vaeslast enc, key, data +.if \enc + vaesenclast \key, \data, \data +.else + vaesdeclast \key, \data, \data +.endif +.endm + +// Do a single non-last round of AES en/decryption on the block(s) in \data, +// using the same key for all block(s). The round key is loaded from the +// appropriate register or memory location for round \i. May clobber \tmp. +.macro _vaes_1x enc, i, xmm_suffix, data, tmp +.if USE_AVX512 + _vaes \enc, KEY\i\xmm_suffix, \data +.else +.ifnb \xmm_suffix + _vaes \enc, (\i-7)*16(KEY), \data +.else + _vbroadcast128 (\i-7)*16(KEY), \tmp + _vaes \enc, \tmp, \data +.endif +.endif +.endm + +// Do a single non-last round of AES en/decryption on the blocks in registers +// V0-V3, using the same key for all blocks. The round key is loaded from the +// appropriate register or memory location for round \i. In addition, does two +// steps of the computation of the next set of tweaks. May clobber V4 and V5. +.macro _vaes_4x enc, i +.if USE_AVX512 + _tweak_step (2*(\i-5)) + _vaes \enc, KEY\i, V0 + _vaes \enc, KEY\i, V1 + _tweak_step (2*(\i-5) + 1) + _vaes \enc, KEY\i, V2 + _vaes \enc, KEY\i, V3 +.else + _vbroadcast128 (\i-7)*16(KEY), V4 + _tweak_step (2*(\i-5)) + _vaes \enc, V4, V0 + _vaes \enc, V4, V1 + _tweak_step (2*(\i-5) + 1) + _vaes \enc, V4, V2 + _vaes \enc, V4, V3 +.endif +.endm + +// Do tweaked AES en/decryption (i.e., XOR with \tweak, then AES en/decrypt, +// then XOR with \tweak again) of the block(s) in \data. To process a single +// block, use xmm registers and set \xmm_suffix=_XMM. To process a vector of +// length VL, use V* registers and leave \xmm_suffix empty. Clobbers \tmp. +.macro _aes_crypt enc, xmm_suffix, tweak, data, tmp + _xor3 KEY0\xmm_suffix, \tweak, \data + cmp $24, KEYLEN + jl .Laes128\@ + je .Laes192\@ + _vaes_1x \enc, 1, \xmm_suffix, \data, tmp=\tmp + _vaes_1x \enc, 2, \xmm_suffix, \data, tmp=\tmp +.Laes192\@: + _vaes_1x \enc, 3, \xmm_suffix, \data, tmp=\tmp + _vaes_1x \enc, 4, \xmm_suffix, \data, tmp=\tmp +.Laes128\@: +.irp i, 5,6,7,8,9,10,11,12,13 + _vaes_1x \enc, \i, \xmm_suffix, \data, tmp=\tmp +.endr +.if USE_AVX512 + vpxord KEY14\xmm_suffix, \tweak, \tmp +.else +.ifnb \xmm_suffix + vpxor 7*16(KEY), \tweak, \tmp +.else + _vbroadcast128 7*16(KEY), \tmp + vpxor \tweak, \tmp, \tmp +.endif +.endif + _vaeslast \enc, \tmp, \data +.endm + +.macro _aes_xts_crypt enc + _define_aliases + + // Load the AES key length: 16 (AES-128), 24 (AES-192), or 32 (AES-256). + movl OFFSETOF_KEYLEN(KEY), KEYLEN + + // Setup the pointer to the round keys and cache as many as possible. + _setup_round_keys \enc + + // Compute the first set of tweaks TWEAK[0-3]. + _compute_first_set_of_tweaks + + sub $4*VL/16, NBLOCKS + jl .Lhandle_remainder\@ + +.Lmain_loop\@: + // This is the main loop, en/decrypting 4*VL bytes per iteration. + + // XOR each source block with its tweak and the zero-th round key. +.if USE_AVX512 + vmovdqu8 0*VL(SRC), V0 + vmovdqu8 1*VL(SRC), V1 + vmovdqu8 2*VL(SRC), V2 + vmovdqu8 3*VL(SRC), V3 + vpternlogd $0x96, TWEAK0, KEY0, V0 + vpternlogd $0x96, TWEAK1, KEY0, V1 + vpternlogd $0x96, TWEAK2, KEY0, V2 + vpternlogd $0x96, TWEAK3, KEY0, V3 +.else + vpxor 0*VL(SRC), KEY0, V0 + vpxor 1*VL(SRC), KEY0, V1 + vpxor 2*VL(SRC), KEY0, V2 + vpxor 3*VL(SRC), KEY0, V3 + vpxor TWEAK0, V0, V0 + vpxor TWEAK1, V1, V1 + vpxor TWEAK2, V2, V2 + vpxor TWEAK3, V3, V3 +.endif + cmp $24, KEYLEN + jl .Laes128\@ + je .Laes192\@ + // Do all the AES rounds on the data blocks, interleaved with + // the computation of the next set of tweaks. + _vaes_4x \enc, 1 + _vaes_4x \enc, 2 +.Laes192\@: + _vaes_4x \enc, 3 + _vaes_4x \enc, 4 +.Laes128\@: +.irp i, 5,6,7,8,9,10,11,12,13 + _vaes_4x \enc, \i +.endr + // Do the last AES round, then XOR the results with the tweaks again. + // Reduce latency by doing the XOR before the vaesenclast, utilizing the + // property vaesenclast(key, a) ^ b == vaesenclast(key ^ b, a) + // (and likewise for vaesdeclast). +.if USE_AVX512 + _tweak_step 18 + _tweak_step 19 + vpxord TWEAK0, KEY14, V4 + vpxord TWEAK1, KEY14, V5 + _vaeslast \enc, V4, V0 + _vaeslast \enc, V5, V1 + vpxord TWEAK2, KEY14, V4 + vpxord TWEAK3, KEY14, V5 + _vaeslast \enc, V4, V2 + _vaeslast \enc, V5, V3 +.else + _vbroadcast128 7*16(KEY), V4 + _tweak_step 18 // uses V5 + _tweak_step 19 // uses V5 + vpxor TWEAK0, V4, V5 + _vaeslast \enc, V5, V0 + vpxor TWEAK1, V4, V5 + _vaeslast \enc, V5, V1 + vpxor TWEAK2, V4, V5 + vpxor TWEAK3, V4, V4 + _vaeslast \enc, V5, V2 + _vaeslast \enc, V4, V3 +.endif + + // Store the destination blocks. + _vmovdqu V0, 0*VL(DST) + _vmovdqu V1, 1*VL(DST) + _vmovdqu V2, 2*VL(DST) + _vmovdqu V3, 3*VL(DST) + + // Finish computing the next set of tweaks. + _tweak_step 1000 + + sub $-4*VL, SRC // shorter than 'add 4*VL' when VL=32 + sub $-4*VL, DST + sub $4*VL/16, NBLOCKS + jge .Lmain_loop\@ + + // Check for the uncommon case where the data length isn't a multiple of + // 4*VL. Handle it out-of-line in order to optimize for the common + // case. In the common case, just fall through to the ret. + test $(4*VL/16)-1, NBLOCKS32 + jnz .Lhandle_remainder\@ +.Ldone\@: + // Store the next tweak back to *TWEAK to support continuation calls. + vmovdqu TWEAK0_XMM, (TWEAK) +.if VL > 16 + vzeroupper +.endif + RET + +.Lhandle_remainder\@: + + // En/decrypt any remaining blocks, one vector at a time. +.if VL > 16 + add $3*VL/16, NBLOCKS32 + jl .Lvec_at_a_time_done\@ +.Lvec_at_a_time\@: + _vmovdqu (SRC), V0 + _aes_crypt \enc, , TWEAK0, V0, tmp=V1 + _vmovdqu V0, (DST) + _next_tweakvec TWEAK0, V0, V1, TWEAK0 + add $VL, SRC + add $VL, DST + sub $VL/16, NBLOCKS32 + jge .Lvec_at_a_time\@ +.Lvec_at_a_time_done\@: + add $VL/16, NBLOCKS32 +.else + add $4*VL/16, NBLOCKS32 +.endif + + // En/decrypt any remaining blocks, one at a time. + jz .Ldone\@ +.Lblock_at_a_time\@: + vmovdqu (SRC), %xmm0 + _aes_crypt \enc, _XMM, TWEAK0_XMM, %xmm0, tmp=%xmm1 + vmovdqu %xmm0, (DST) + _next_tweak TWEAK0_XMM, %xmm0, TWEAK0_XMM + add $16, SRC + add $16, DST + dec NBLOCKS32 + jnz .Lblock_at_a_time\@ + jmp .Ldone\@ +.endm + +// void aes_xts_encrypt_iv(const struct aes_enckey *tweak_key, +// u8 iv[AES_BLOCK_SIZE]); +// +// Encrypt |iv| using the AES key |tweak_key| to get the first tweak. Assumes +// that the CPU supports AES-NI and AVX, but not necessarily VAES or AVX512. +SYM_FUNC_START(aes_xts_encrypt_iv) + .set TWEAK_KEY, %rdi + .set IV, %rsi + .set KEYLEN, %eax + .set KEYLEN64, %rax + + vmovdqu (IV), %xmm0 + vpxor OFFSETOF_RNDKEYS(TWEAK_KEY), %xmm0, %xmm0 + movl OFFSETOF_KEYLEN(TWEAK_KEY), KEYLEN + lea OFFSETOF_RNDKEYS-16(TWEAK_KEY, KEYLEN64, 4), TWEAK_KEY + cmp $24, KEYLEN + jl .Lencrypt_iv_aes128 + je .Lencrypt_iv_aes192 + vaesenc -6*16(TWEAK_KEY), %xmm0, %xmm0 + vaesenc -5*16(TWEAK_KEY), %xmm0, %xmm0 +.Lencrypt_iv_aes192: + vaesenc -4*16(TWEAK_KEY), %xmm0, %xmm0 + vaesenc -3*16(TWEAK_KEY), %xmm0, %xmm0 +.Lencrypt_iv_aes128: +.irp i, -2,-1,0,1,2,3,4,5,6 + vaesenc \i*16(TWEAK_KEY), %xmm0, %xmm0 +.endr + vaesenclast 7*16(TWEAK_KEY), %xmm0, %xmm0 + vmovdqu %xmm0, (IV) + RET +SYM_FUNC_END(aes_xts_encrypt_iv) + +// Below are the actual AES-XTS encryption and decryption functions, +// instantiated from the above macro. They all have the following prototype: +// +// void aes_xts_{en,de}crypt_{cpufeature}(u8 *dst, const u8 *src, long nblocks, +// u8 tweak[AES_BLOCK_SIZE], +// const struct aes_key *key); +// +// `tweak` must have already been encrypted by the tweak key; `key` is just the +// main key. `tweak` is updated to contain the next tweak, allowing for +// incremental computation. + +.set VL, 16 +.set USE_AVX512, 0 +SYM_FUNC_START(aes_xts_encrypt_aesni_avx) + _aes_xts_crypt 1 +SYM_FUNC_END(aes_xts_encrypt_aesni_avx) +SYM_FUNC_START(aes_xts_decrypt_aesni_avx) + _aes_xts_crypt 0 +SYM_FUNC_END(aes_xts_decrypt_aesni_avx) + +.set VL, 32 +.set USE_AVX512, 0 +SYM_FUNC_START(aes_xts_encrypt_vaes_avx2) + _aes_xts_crypt 1 +SYM_FUNC_END(aes_xts_encrypt_vaes_avx2) +SYM_FUNC_START(aes_xts_decrypt_vaes_avx2) + _aes_xts_crypt 0 +SYM_FUNC_END(aes_xts_decrypt_vaes_avx2) + +.set VL, 64 +.set USE_AVX512, 1 +SYM_FUNC_START(aes_xts_encrypt_vaes_avx512) + _aes_xts_crypt 1 +SYM_FUNC_END(aes_xts_encrypt_vaes_avx512) +SYM_FUNC_START(aes_xts_decrypt_vaes_avx512) + _aes_xts_crypt 0 +SYM_FUNC_END(aes_xts_decrypt_vaes_avx512) diff --git a/lib/crypto/x86/aes.h b/lib/crypto/x86/aes.h index b047dee94f57..b555290ab075 100644 --- a/lib/crypto/x86/aes.h +++ b/lib/crypto/x86/aes.h @@ -7,16 +7,28 @@ #include <asm/fpu/api.h> -static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aesni); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aesni_avx); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_vaes_avx2); +static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_vaes_avx512); + +/* The assembly code assumes the following offsets. */ +static_assert(offsetof(struct aes_enckey, len) == 0); +static_assert(offsetof(struct aes_enckey, nrounds) == 4); +static_assert(offsetof(struct aes_enckey, k.rndkeys) == 16); +static_assert(offsetof(struct aes_key, len) == 0); +static_assert(offsetof(struct aes_key, nrounds) == 4); +static_assert(offsetof(struct aes_key, k.rndkeys) == 16); +static_assert(offsetof(struct aes_key, inv_k.inv_rndkeys) == 256); void aes128_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys, const u8 in_key[AES_KEYSIZE_128]); void aes256_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys, const u8 in_key[AES_KEYSIZE_256]); -void aes_encrypt_aesni(const u32 rndkeys[], int nrounds, - u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); -void aes_decrypt_aesni(const u32 inv_rndkeys[], int nrounds, - u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]); +void aes_encrypt_aesni(u8 dst[AES_BLOCK_SIZE], const u8 src[AES_BLOCK_SIZE], + const struct aes_enckey *key); +void aes_decrypt_aesni(u8 dst[AES_BLOCK_SIZE], const u8 src[AES_BLOCK_SIZE], + const struct aes_key *key); /* * Expand an AES key using AES-NI if supported and usable or generic code @@ -36,7 +48,7 @@ static void aes_preparekey_arch(union aes_enckey_arch *k, u32 *rndkeys = k->rndkeys; u32 *inv_rndkeys = inv_k ? inv_k->inv_rndkeys : NULL; - if (static_branch_likely(&have_aes) && key_len != AES_KEYSIZE_192 && + if (static_branch_likely(&have_aesni) && key_len != AES_KEYSIZE_192 && irq_fpu_usable()) { kernel_fpu_begin(); if (key_len == AES_KEYSIZE_128) @@ -53,9 +65,9 @@ static void aes_encrypt_arch(const struct aes_enckey *key, u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]) { - if (static_branch_likely(&have_aes) && irq_fpu_usable()) { + if (static_branch_likely(&have_aesni) && irq_fpu_usable()) { kernel_fpu_begin(); - aes_encrypt_aesni(key->k.rndkeys, key->nrounds, out, in); + aes_encrypt_aesni(out, in, key); kernel_fpu_end(); } else { aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in); @@ -66,10 +78,9 @@ static void aes_decrypt_arch(const struct aes_key *key, u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]) { - if (static_branch_likely(&have_aes) && irq_fpu_usable()) { + if (static_branch_likely(&have_aesni) && irq_fpu_usable()) { kernel_fpu_begin(); - aes_decrypt_aesni(key->inv_k.inv_rndkeys, key->nrounds, - out, in); + aes_decrypt_aesni(out, in, key); kernel_fpu_end(); } else { aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds, @@ -77,9 +88,353 @@ static void aes_decrypt_arch(const struct aes_key *key, } } +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_ECB) +void aes_ecb_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, + const struct aes_enckey *key); +void aes_ecb_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, + const struct aes_key *key); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_ecb_encrypt_arch aes_ecb_encrypt_arch +static bool aes_ecb_encrypt_arch(u8 *dst, const u8 *src, size_t len, + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + kernel_fpu_begin(); + aes_ecb_encrypt_aesni(dst, src, len / AES_BLOCK_SIZE, key); + kernel_fpu_end(); + return true; +} + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_ecb_decrypt_arch aes_ecb_decrypt_arch +static bool aes_ecb_decrypt_arch(u8 *dst, const u8 *src, size_t len, + const struct aes_key *key) +{ + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + kernel_fpu_begin(); + aes_ecb_decrypt_aesni(dst, src, len / AES_BLOCK_SIZE, key); + kernel_fpu_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_ECB */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC) +void aes_cbc_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, + u8 iv[AES_BLOCK_SIZE], const struct aes_enckey *key); +void aes_cbc_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, + u8 iv[AES_BLOCK_SIZE], const struct aes_key *key); +void aes_cbc_cts_encrypt_aesni(u8 *dst, const u8 *src, long pn_len, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key); +void aes_cbc_cts_decrypt_aesni(u8 *dst, const u8 *src, long pn_len, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_key *key); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_cbc_encrypt_arch aes_cbc_encrypt_arch +static bool aes_cbc_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + kernel_fpu_begin(); + aes_cbc_encrypt_aesni(dst, src, len / AES_BLOCK_SIZE, iv, key); + kernel_fpu_end(); + return true; +} + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +#define aes_cbc_decrypt_arch aes_cbc_decrypt_arch +static bool aes_cbc_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_key *key) +{ + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + kernel_fpu_begin(); + aes_cbc_decrypt_aesni(dst, src, len / AES_BLOCK_SIZE, iv, key); + kernel_fpu_end(); + return true; +} + +/* len can be any value greater than AES_BLOCK_SIZE here. */ +#define aes_cbc_cts_encrypt_arch aes_cbc_cts_encrypt_arch +static bool aes_cbc_cts_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key) +{ + const size_t cbc_blocks = (len - AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE; + const size_t pn_len = ((len - 1) % AES_BLOCK_SIZE) + 1; + + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + + kernel_fpu_begin(); + if (cbc_blocks) { + aes_cbc_encrypt_aesni(dst, src, cbc_blocks, iv, key); + dst += cbc_blocks * AES_BLOCK_SIZE; + src += cbc_blocks * AES_BLOCK_SIZE; + } + /* Encrypt the last 17 to 32 bytes. */ + aes_cbc_cts_encrypt_aesni(dst, src, pn_len, iv, key); + kernel_fpu_end(); + return true; +} + +/* len can be any value greater than AES_BLOCK_SIZE here. */ +#define aes_cbc_cts_decrypt_arch aes_cbc_cts_decrypt_arch +static bool aes_cbc_cts_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 iv[AES_BLOCK_SIZE], + const struct aes_key *key) +{ + const size_t cbc_blocks = (len - AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE; + const size_t pn_len = ((len - 1) % AES_BLOCK_SIZE) + 1; + + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + + kernel_fpu_begin(); + if (cbc_blocks) { + aes_cbc_decrypt_aesni(dst, src, cbc_blocks, iv, key); + dst += cbc_blocks * AES_BLOCK_SIZE; + src += cbc_blocks * AES_BLOCK_SIZE; + } + /* Decrypt the last 17 to 32 bytes. */ + aes_cbc_cts_decrypt_aesni(dst, src, pn_len, iv, key); + kernel_fpu_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_CBC */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CTR) && IS_ENABLED(CONFIG_X86_64) +void aes_ctr64_crypt_aesni(u8 *dst, const u8 *src, s64 len, const u64 le_ctr[2], + const struct aes_enckey *key); +void aes_ctr64_crypt_aesni_avx(u8 *dst, const u8 *src, s64 len, + const u64 le_ctr[2], + const struct aes_enckey *key); +void aes_ctr64_crypt_vaes_avx2(u8 *dst, const u8 *src, s64 len, + const u64 le_ctr[2], + const struct aes_enckey *key); +void aes_ctr64_crypt_vaes_avx512(u8 *dst, const u8 *src, s64 len, + const u64 le_ctr[2], + const struct aes_enckey *key); +void aes_xctr_crypt_aesni_avx(u8 *dst, const u8 *src, s64 len, u64 ctr, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key); +void aes_xctr_crypt_vaes_avx2(u8 *dst, const u8 *src, s64 len, u64 ctr, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key); +void aes_xctr_crypt_vaes_avx512(u8 *dst, const u8 *src, s64 len, u64 ctr, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key); + +static void aes_ctr64_x86(u8 *dst, const u8 *src, size_t len, + const u64 le_ctr[2], const struct aes_enckey *key) +{ + if (static_branch_likely(&have_vaes_avx512)) + aes_ctr64_crypt_vaes_avx512(dst, src, len, le_ctr, key); + else if (static_branch_likely(&have_vaes_avx2)) + aes_ctr64_crypt_vaes_avx2(dst, src, len, le_ctr, key); + else if (static_branch_likely(&have_aesni_avx)) + aes_ctr64_crypt_aesni_avx(dst, src, len, le_ctr, key); + else + aes_ctr64_crypt_aesni(dst, src, len, le_ctr, key); +} + +#define aes_ctr_arch aes_ctr_arch +static bool aes_ctr_arch(u8 *dst, const u8 *src, size_t len, + u8 ctr[AES_BLOCK_SIZE], const struct aes_enckey *key) +{ + u64 le_ctr[2]; + u64 ctr64; + size_t nblocks; + size_t part1_len; + + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + + ctr64 = le_ctr[0] = get_unaligned_be64(&ctr[8]); + le_ctr[1] = get_unaligned_be64(&ctr[0]); + + kernel_fpu_begin(); + + nblocks = DIV_ROUND_UP(len, AES_BLOCK_SIZE); + ctr64 += nblocks; + + if (likely(ctr64 >= nblocks)) { + /* The low 64 bits of the counter won't overflow. */ + aes_ctr64_x86(dst, src, len, le_ctr, key); + } else { + /* + * The low 64 bits of the counter will overflow. The + * assembly doesn't handle this case, so split the + * operation into two at the point where the overflow + * will occur. After the first part, add the carry bit. + */ + part1_len = min(len, (nblocks - ctr64) * AES_BLOCK_SIZE); + aes_ctr64_x86(dst, src, part1_len, le_ctr, key); + le_ctr[0] = 0; + le_ctr[1]++; + aes_ctr64_x86(dst + part1_len, src + part1_len, len - part1_len, + le_ctr, key); + } + kernel_fpu_end(); + put_unaligned_be64(ctr64, &ctr[8]); + put_unaligned_be64(le_ctr[1], &ctr[0]); + return true; +} + +#define aes_xctr_arch aes_xctr_arch +static bool aes_xctr_arch(u8 *dst, const u8 *src, size_t len, u64 ctr, + const u8 iv[AES_BLOCK_SIZE], + const struct aes_enckey *key) +{ + if (!static_branch_likely(&have_aesni_avx) || + unlikely(!irq_fpu_usable())) + return false; + kernel_fpu_begin(); + if (static_branch_likely(&have_vaes_avx512)) + aes_xctr_crypt_vaes_avx512(dst, src, len, ctr, iv, key); + else if (static_branch_likely(&have_vaes_avx2)) + aes_xctr_crypt_vaes_avx2(dst, src, len, ctr, iv, key); + else + aes_xctr_crypt_aesni_avx(dst, src, len, ctr, iv, key); + kernel_fpu_end(); + return true; +} +#endif /* CONFIG_CRYPTO_LIB_AES_CTR && CONFIG_X86_64 */ + +#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS) +void aes_xts_encrypt_aesni(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], const struct aes_key *key); +void aes_xts_decrypt_aesni(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], const struct aes_key *key); +void aes_xts_encrypt_iv(const struct aes_enckey *tweak_key, + u8 iv[AES_BLOCK_SIZE]); +void aes_xts_encrypt_aesni_avx(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_decrypt_aesni_avx(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_encrypt_vaes_avx2(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_decrypt_vaes_avx2(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_encrypt_vaes_avx512(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); +void aes_xts_decrypt_vaes_avx512(u8 *dst, const u8 *src, long nblocks, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_key *key); + +/* len is always a positive multiple of AES_BLOCK_SIZE here. */ +static __always_inline bool +aes_xts_crypt_x86(u8 *dst, const u8 *src, size_t len, u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont, bool enc) +{ + const long nblocks = len / AES_BLOCK_SIZE; + + if (!static_branch_likely(&have_aesni) || unlikely(!irq_fpu_usable())) + return false; + + kernel_fpu_begin(); + if (IS_ENABLED(CONFIG_X86_64) && + static_branch_likely(&have_vaes_avx512)) { + if (!cont) + aes_xts_encrypt_iv(&key->tweak_key, tweak); + if (enc) + aes_xts_encrypt_vaes_avx512(dst, src, nblocks, tweak, + &key->main_key); + else + aes_xts_decrypt_vaes_avx512(dst, src, nblocks, tweak, + &key->main_key); + } else if (IS_ENABLED(CONFIG_X86_64) && + static_branch_likely(&have_vaes_avx2)) { + if (!cont) + aes_xts_encrypt_iv(&key->tweak_key, tweak); + if (enc) + aes_xts_encrypt_vaes_avx2(dst, src, nblocks, tweak, + &key->main_key); + else + aes_xts_decrypt_vaes_avx2(dst, src, nblocks, tweak, + &key->main_key); + } else if (IS_ENABLED(CONFIG_X86_64) && + static_branch_likely(&have_aesni_avx)) { + if (!cont) + aes_xts_encrypt_iv(&key->tweak_key, tweak); + if (enc) + aes_xts_encrypt_aesni_avx(dst, src, nblocks, tweak, + &key->main_key); + else + aes_xts_decrypt_aesni_avx(dst, src, nblocks, tweak, + &key->main_key); + } else { + if (!cont) + aes_encrypt_aesni(tweak, tweak, &key->tweak_key); + if (enc) + aes_xts_encrypt_aesni(dst, src, nblocks, tweak, + &key->main_key); + else + aes_xts_decrypt_aesni(dst, src, nblocks, tweak, + &key->main_key); + } + kernel_fpu_end(); + return true; +} + +#define aes_xts_encrypt_arch aes_xts_encrypt_arch +static bool aes_xts_encrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_x86(dst, src, len, tweak, key, cont, true); +} + +#define aes_xts_decrypt_arch aes_xts_decrypt_arch +static bool aes_xts_decrypt_arch(u8 *dst, const u8 *src, size_t len, + u8 tweak[AES_BLOCK_SIZE], + const struct aes_xts_key *key, bool cont) +{ + return aes_xts_crypt_x86(dst, src, len, tweak, key, cont, false); +} +#endif /* CONFIG_CRYPTO_LIB_AES_XTS */ + #define aes_mod_init_arch aes_mod_init_arch static void aes_mod_init_arch(void) { - if (boot_cpu_has(X86_FEATURE_AES)) - static_branch_enable(&have_aes); + /* Everything below requires AES-NI. */ + if (!boot_cpu_has(X86_FEATURE_AES)) + return; + static_branch_enable(&have_aesni); + + /* Everything below requires AVX and is also 64-bit only. */ + if (!boot_cpu_has(X86_FEATURE_AVX) || !IS_ENABLED(CONFIG_X86_64)) + return; + static_branch_enable(&have_aesni_avx); + + /* + * Everything below requires VAES, and also sometimes AVX2, VPCLMULQDQ, + * and PCLMULQDQ. Use a single static key for all of them, since in + * practice every CPU with VAES also has the others. + */ + if (!boot_cpu_has(X86_FEATURE_VAES) || + !boot_cpu_has(X86_FEATURE_AVX2) || + !boot_cpu_has(X86_FEATURE_VPCLMULQDQ) || + !boot_cpu_has(X86_FEATURE_PCLMULQDQ)) + return; + static_branch_enable(&have_vaes_avx2); + + if (!boot_cpu_has(X86_FEATURE_AVX512BW) || + !boot_cpu_has(X86_FEATURE_AVX512VL) || + !boot_cpu_has(X86_FEATURE_BMI2) || + boot_cpu_has(X86_FEATURE_PREFER_YMM)) + return; + static_branch_enable(&have_vaes_avx512); } diff --git a/lib/crypto/x86/chacha.h b/lib/crypto/x86/chacha.h index c79562aac56b..e97f1f252bcc 100644 --- a/lib/crypto/x86/chacha.h +++ b/lib/crypto/x86/chacha.h @@ -11,46 +11,46 @@ #include <linux/sizes.h> asmlinkage void chacha_block_xor_ssse3(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_4block_xor_ssse3(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void hchacha_block_ssse3(const struct chacha_state *state, u32 out[HCHACHA_OUT_WORDS], int nrounds); asmlinkage void chacha_2block_xor_avx2(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_4block_xor_avx2(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_8block_xor_avx2(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_2block_xor_avx512vl(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_4block_xor_avx512vl(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); asmlinkage void chacha_8block_xor_avx512vl(const struct chacha_state *state, - u8 *dst, const u8 *src, - unsigned int len, int nrounds); + u8 *dst, const u8 *src, size_t len, + int nrounds); static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_simd); static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx2); static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx512vl); -static unsigned int chacha_advance(unsigned int len, unsigned int maxblocks) +static size_t chacha_advance(size_t len, size_t maxblocks) { len = min(len, maxblocks * CHACHA_BLOCK_SIZE); return round_up(len, CHACHA_BLOCK_SIZE) / CHACHA_BLOCK_SIZE; } static void chacha_dosimd(struct chacha_state *state, u8 *dst, const u8 *src, - unsigned int bytes, int nrounds) + size_t bytes, int nrounds) { if (static_branch_likely(&chacha_use_avx512vl)) { while (bytes >= CHACHA_BLOCK_SIZE * 8) { @@ -137,14 +137,14 @@ static void hchacha_block_arch(const struct chacha_state *state, } static void chacha_crypt_arch(struct chacha_state *state, u8 *dst, - const u8 *src, unsigned int bytes, int nrounds) + const u8 *src, size_t bytes, int nrounds) { if (!static_branch_likely(&chacha_use_simd) || bytes <= CHACHA_BLOCK_SIZE) return chacha_crypt_generic(state, dst, src, bytes, nrounds); do { - unsigned int todo = min_t(unsigned int, bytes, SZ_4K); + size_t todo = min(bytes, SZ_4K); kernel_fpu_begin(); chacha_dosimd(state, dst, src, todo, nrounds); diff --git a/lib/crypto/x86/poly1305.h b/lib/crypto/x86/poly1305.h index b061b9926fa5..a2034809b97b 100644 --- a/lib/crypto/x86/poly1305.h +++ b/lib/crypto/x86/poly1305.h @@ -90,7 +90,7 @@ static void poly1305_block_init(struct poly1305_block_state *state, } static void poly1305_blocks(struct poly1305_block_state *state, const u8 *inp, - unsigned int len, u32 padbit) + size_t len, u32 padbit) { struct poly1305_arch_internal *ctx = container_of(&state->h.h, struct poly1305_arch_internal, h); @@ -115,7 +115,7 @@ static void poly1305_blocks(struct poly1305_block_state *state, const u8 *inp, } do { - const unsigned int bytes = min(len, SZ_4K); + const size_t bytes = min(len, SZ_4K); kernel_fpu_begin(); if (static_branch_likely(&poly1305_use_avx512)) diff --git a/lib/crypto/x86/sha1-avx2-asm.S b/lib/crypto/x86/sha1-avx2-asm.S index 91b2dc6db179..ca64d7104a47 100644 --- a/lib/crypto/x86/sha1-avx2-asm.S +++ b/lib/crypto/x86/sha1-avx2-asm.S @@ -622,6 +622,9 @@ .macro SHA1_VECTOR_ASM name SYM_FUNC_START(\name) + push %rbp + mov %rsp, %rbp + push %rbx push %r12 push %r13 @@ -631,8 +634,6 @@ RESERVE_STACK = (W_SIZE*4 + 8+24) /* Align stack */ - push %rbp - mov %rsp, %rbp and $~(0x20-1), %rsp sub $RESERVE_STACK, %rsp @@ -651,14 +652,13 @@ avx2_zeroupper - mov %rbp, %rsp - pop %rbp - + lea -40(%rbp), %rsp pop %r15 pop %r14 pop %r13 pop %r12 pop %rbx + pop %rbp RET diff --git a/lib/crypto/x86/sha1-ssse3-and-avx.S b/lib/crypto/x86/sha1-ssse3-and-avx.S index 78b48cb09c5b..fe0faaf494c7 100644 --- a/lib/crypto/x86/sha1-ssse3-and-avx.S +++ b/lib/crypto/x86/sha1-ssse3-and-avx.S @@ -69,11 +69,12 @@ .macro SHA1_VECTOR_ASM name SYM_FUNC_START(\name) - push %rbx - push %r12 push %rbp mov %rsp, %rbp + push %rbx + push %r12 + sub $64, %rsp # allocate workspace and $~15, %rsp # align stack @@ -95,10 +96,10 @@ xor %eax, %eax rep stosq - mov %rbp, %rsp # deallocate workspace - pop %rbp + lea -16(%rbp), %rsp # deallocate workspace pop %r12 pop %rbx + pop %rbp RET SYM_FUNC_END(\name) diff --git a/lib/crypto/x86/sha256-avx-asm.S b/lib/crypto/x86/sha256-avx-asm.S index c1aceb3ba3a3..efb8dff5e8a9 100644 --- a/lib/crypto/x86/sha256-avx-asm.S +++ b/lib/crypto/x86/sha256-avx-asm.S @@ -345,13 +345,13 @@ a = TMP_ ######################################################################## .text SYM_FUNC_START(sha256_transform_avx) + pushq %rbp + movq %rsp, %rbp pushq %rbx pushq %r12 pushq %r13 pushq %r14 pushq %r15 - pushq %rbp - movq %rsp, %rbp subq $STACK_SIZE, %rsp # allocate stack space and $~15, %rsp # align stack pointer @@ -445,13 +445,13 @@ SYM_FUNC_START(sha256_transform_avx) cmp _INP_END(%rsp), INP jne .Lloop0 - mov %rbp, %rsp - popq %rbp + lea -40(%rbp), %rsp popq %r15 popq %r14 popq %r13 - popq %r12 + popq %r12 popq %rbx + popq %rbp RET SYM_FUNC_END(sha256_transform_avx) diff --git a/lib/crypto/x86/sha256-avx2-asm.S b/lib/crypto/x86/sha256-avx2-asm.S index eb8836fb9695..a719c2173b61 100644 --- a/lib/crypto/x86/sha256-avx2-asm.S +++ b/lib/crypto/x86/sha256-avx2-asm.S @@ -522,15 +522,14 @@ STACK_SIZE = _CTX + _CTX_SIZE ######################################################################## .text SYM_FUNC_START(sha256_transform_rorx) + pushq %rbp + mov %rsp, %rbp pushq %rbx pushq %r12 pushq %r13 pushq %r14 pushq %r15 - push %rbp - mov %rsp, %rbp - subq $STACK_SIZE, %rsp and $-32, %rsp # align rsp to 32 byte boundary @@ -704,14 +703,13 @@ SYM_FUNC_START(sha256_transform_rorx) .Ldone_hash: - mov %rbp, %rsp - pop %rbp - + lea -40(%rbp), %rsp popq %r15 popq %r14 popq %r13 popq %r12 popq %rbx + popq %rbp vzeroupper RET SYM_FUNC_END(sha256_transform_rorx) diff --git a/lib/crypto/x86/sha256-ni-asm.S b/lib/crypto/x86/sha256-ni-asm.S index de5f707e7ef7..e47263273f43 100644 --- a/lib/crypto/x86/sha256-ni-asm.S +++ b/lib/crypto/x86/sha256-ni-asm.S @@ -276,10 +276,11 @@ SYM_FUNC_END(sha256_ni_transform) // to taking better advantage of the CPU's SHA-256 and SIMD throughput. // SYM_FUNC_START(sha256_ni_finup2x) - // Allocate 128 bytes of stack space, 16-byte aligned. - push %rbx push %rbp mov %rsp, %rbp + push %rbx + + // Allocate 128 bytes of stack space, 16-byte aligned. sub $128, %rsp and $~15, %rsp @@ -527,9 +528,9 @@ SYM_FUNC_START(sha256_ni_finup2x) movdqu STATE1_A, 0*16(OUT1) movdqu STATE1_B, 0*16(OUT2) - mov %rbp, %rsp - pop %rbp + lea -8(%rbp), %rsp pop %rbx + pop %rbp RET SYM_FUNC_END(sha256_ni_finup2x) diff --git a/lib/crypto/x86/sha256-ssse3-asm.S b/lib/crypto/x86/sha256-ssse3-asm.S index 383b8eec7ebe..cc91b3e15a83 100644 --- a/lib/crypto/x86/sha256-ssse3-asm.S +++ b/lib/crypto/x86/sha256-ssse3-asm.S @@ -352,13 +352,13 @@ a = TMP_ ######################################################################## .text SYM_FUNC_START(sha256_transform_ssse3) + pushq %rbp + mov %rsp, %rbp pushq %rbx pushq %r12 pushq %r13 pushq %r14 pushq %r15 - pushq %rbp - mov %rsp, %rbp subq $STACK_SIZE, %rsp and $~15, %rsp @@ -456,13 +456,13 @@ SYM_FUNC_START(sha256_transform_ssse3) cmp _INP_END(%rsp), INP jne .Lloop0 - mov %rbp, %rsp - popq %rbp + lea -40(%rbp), %rsp popq %r15 popq %r14 popq %r13 popq %r12 popq %rbx + popq %rbp RET SYM_FUNC_END(sha256_transform_ssse3) diff --git a/lib/crypto/x86/sha512-avx-asm.S b/lib/crypto/x86/sha512-avx-asm.S index 7732aa8fd850..a17dfedc1c51 100644 --- a/lib/crypto/x86/sha512-avx-asm.S +++ b/lib/crypto/x86/sha512-avx-asm.S @@ -276,6 +276,9 @@ frame_size = frame_WK + WK_SIZE ######################################################################## SYM_FUNC_START(sha512_transform_avx) + push %rbp + mov %rsp, %rbp + # Save GPRs push %rbx push %r12 @@ -284,8 +287,6 @@ SYM_FUNC_START(sha512_transform_avx) push %r15 # Allocate Stack Space - push %rbp - mov %rsp, %rbp sub $frame_size, %rsp and $~(0x20 - 1), %rsp @@ -348,9 +349,8 @@ SYM_FUNC_START(sha512_transform_avx) dec msglen jnz .Lupdateblock - # Restore Stack Pointer - mov %rbp, %rsp - pop %rbp + # Deallocate Stack Space + lea -40(%rbp), %rsp # Restore GPRs pop %r15 @@ -358,6 +358,7 @@ SYM_FUNC_START(sha512_transform_avx) pop %r13 pop %r12 pop %rbx + pop %rbp RET SYM_FUNC_END(sha512_transform_avx) diff --git a/lib/crypto/x86/sha512-avx2-asm.S b/lib/crypto/x86/sha512-avx2-asm.S index 22bdbfd899d0..2256d51297e1 100644 --- a/lib/crypto/x86/sha512-avx2-asm.S +++ b/lib/crypto/x86/sha512-avx2-asm.S @@ -568,6 +568,9 @@ frame_size = frame_CTX + CTX_SIZE ######################################################################## SYM_FUNC_START(sha512_transform_rorx) + push %rbp + mov %rsp, %rbp + # Save GPRs push %rbx push %r12 @@ -576,8 +579,6 @@ SYM_FUNC_START(sha512_transform_rorx) push %r15 # Allocate Stack Space - push %rbp - mov %rsp, %rbp sub $frame_size, %rsp and $~(0x20 - 1), %rsp @@ -667,9 +668,8 @@ SYM_FUNC_START(sha512_transform_rorx) cmp frame_INPEND(%rsp), INP jne .Lloop0 - # Restore Stack Pointer - mov %rbp, %rsp - pop %rbp + # Deallocate Stack Space + lea -40(%rbp), %rsp # Restore GPRs pop %r15 @@ -677,6 +677,7 @@ SYM_FUNC_START(sha512_transform_rorx) pop %r13 pop %r12 pop %rbx + pop %rbp vzeroupper RET diff --git a/lib/crypto/x86/sha512-ssse3-asm.S b/lib/crypto/x86/sha512-ssse3-asm.S index 4cae7445b2a8..1a37b7a735cf 100644 --- a/lib/crypto/x86/sha512-ssse3-asm.S +++ b/lib/crypto/x86/sha512-ssse3-asm.S @@ -275,6 +275,9 @@ frame_size = frame_WK + WK_SIZE ######################################################################## SYM_FUNC_START(sha512_transform_ssse3) + push %rbp + mov %rsp, %rbp + # Save GPRs push %rbx push %r12 @@ -283,8 +286,6 @@ SYM_FUNC_START(sha512_transform_ssse3) push %r15 # Allocate Stack Space - push %rbp - mov %rsp, %rbp sub $frame_size, %rsp and $~(0x20 - 1), %rsp @@ -347,9 +348,8 @@ SYM_FUNC_START(sha512_transform_ssse3) dec msglen jnz .Lupdateblock - # Restore Stack Pointer - mov %rbp, %rsp - pop %rbp + # Deallocate Stack Space + lea -40(%rbp), %rsp # Restore GPRs pop %r15 @@ -357,6 +357,7 @@ SYM_FUNC_START(sha512_transform_ssse3) pop %r13 pop %r12 pop %rbx + pop %rbp RET SYM_FUNC_END(sha512_transform_ssse3) diff --git a/lib/tests/Makefile b/lib/tests/Makefile index 3cac3b63a752..1a3d39db268f 100644 --- a/lib/tests/Makefile +++ b/lib/tests/Makefile @@ -46,7 +46,6 @@ obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o obj-$(CONFIG_RANDSTRUCT_KUNIT_TEST) += randstruct_kunit.o obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o obj-$(CONFIG_SEQ_BUF_KUNIT_TEST) += seq_buf_kunit.o -obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o obj-$(CONFIG_TEST_SORT) += test_sort.o CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable) |
