diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-17 19:29:41 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-17 19:29:41 -0700 |
| commit | fc8c78bce3335860ff4ae9fcfd3b2eb1f674efbb (patch) | |
| tree | 5997e1747226eb6d6bb16b78ea64d4a0c7f739c6 /scripts | |
| parent | d47db9bf50d28647689e6743ee93c45cb755ffc3 (diff) | |
| parent | 561131a27f5533e6e63520b4bc43d9c832a27c09 (diff) | |
Merge tag 'libcrypto-tests-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux
Pull crypto library test updates from Eric Biggers:
- Add comprehensive KUnit test suites for the new AES-GCM and AES-CCM
library APIs
- Add FIPS self-tests for all the AES encryption modes. This is needed
for parity with the traditional crypto API
- Fix a couple more issues in the IRQ test helper
* tag 'libcrypto-tests-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux:
lib/crypto: aes-cmac: Use __cleanup() instead of memzero_explicit()
kunit: irq: Unregister on-stack timer and work from debugobjects
kunit: irq: Continue increasing hrtimer interval for longer
lib/crypto: tests: Add KUnit test suite for AES-GCM
lib/crypto: tests: Add KUnit test suite for AES-CCM
lib/crypto: tests: Add aead-test-template.h
lib/crypto: tests: Use per-test-case buffers in hash tests
lib/crypto: tests: Create test-utils.h
lib/crypto: aes: Add FIPS self-tests for GCM and CCM
lib/crypto: aes: Add FIPS self-tests for unauthenticated modes
lib/crypto: fips: Split fips.h into fips-aes.h and fips-sha.h
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/crypto/gen-aead-testvecs.py | 69 | ||||
| -rwxr-xr-x | scripts/crypto/gen-fips-testvecs.py | 164 |
2 files changed, 202 insertions, 31 deletions
diff --git a/scripts/crypto/gen-aead-testvecs.py b/scripts/crypto/gen-aead-testvecs.py new file mode 100755 index 000000000000..d77d646f75b5 --- /dev/null +++ b/scripts/crypto/gen-aead-testvecs.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Script that generates known-good data used in the AEAD tests. +# +# Requires that python-cryptography be installed. +# +# Copyright 2026 Google LLC + +import hashlib +import sys +import cryptography.hazmat.primitives.ciphers.aead + + +# Deterministically generate 'length' random bytes. +def rand_bytes(length): + seed = length + out = [] + for _ in range(length): + seed = (seed * 25214903917 + 11) % 2**48 + out.append((seed >> 16) % 256) + return bytes(out) + + +# Deterministically generate many different AEAD inputs using exactly the same +# method that the test uses; encrypt them using an independent implementation of +# the algorithm; compute the checksum of all the resulting (ciphertext, authtag) +# pairs concatenated to each other; and print the checksum as a C struct. +def gen_monte_carlo_checksum(alg): + blake2s = hashlib.blake2s() + for data_len in range(1025): + ad_len = data_len % 293 + pt = rand_bytes(data_len) + ad = rand_bytes(ad_len) + if alg == "aes-ccm": + key_len = [16, 24, 32][data_len % 3] + key = rand_bytes(key_len) + nonce = rand_bytes([7, 8, 9, 10, 11, 12, 13][data_len % 7]) + tag_len = [4, 6, 8, 10, 12, 14, 16][data_len % 7] + ccm = cryptography.hazmat.primitives.ciphers.aead.AESCCM( + key, tag_length=tag_len + ) + ct_and_tag = ccm.encrypt(nonce, pt, ad) + elif alg == "aes-gcm": + key_len = [16, 24, 32][data_len % 3] + key = rand_bytes(key_len) + nonce = rand_bytes(12) + tag_len = [4, 8, 12, 13, 14, 15, 16][data_len % 7] + gcm = cryptography.hazmat.primitives.ciphers.aead.AESGCM(key) + # python-cryptography supports only 16-byte GCM tags. However, in + # GCM, shorter tags are simply truncated. Do that below. + ct_and_tag = gcm.encrypt(nonce, pt, ad)[: data_len + tag_len] + + blake2s.update(ct_and_tag) + + name = f"{alg.replace('-', '_')}_monte_carlo_checksum" + value = blake2s.digest() + print(f"static const u8 {name}[BLAKE2S_HASH_SIZE] = {{") + for i in range(0, len(value), 11): + line = "\t" + "".join(f"0x{b:02x}, " for b in value[i : i + 11]) + print(f"{line.rstrip()}") + print("};") + + +if len(sys.argv) != 2 or sys.argv[1] not in ("aes-ccm", "aes-gcm"): + sys.stderr.write("Usage: gen-aead-testvecs.py [aes-ccm|aes-gcm]\n") + sys.exit(1) + +gen_monte_carlo_checksum(sys.argv[1]) diff --git a/scripts/crypto/gen-fips-testvecs.py b/scripts/crypto/gen-fips-testvecs.py index 9f18bcb97412..b8c8a78cb8a8 100755 --- a/scripts/crypto/gen-fips-testvecs.py +++ b/scripts/crypto/gen-fips-testvecs.py @@ -1,46 +1,148 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-or-later # -# Script that generates lib/crypto/fips.h +# Script that generates lib/crypto/fips-aes.h and lib/crypto/fips-sha.h # # Requires that python-cryptography be installed. # # Copyright 2025 Google LLC import cryptography.hazmat.primitives.ciphers +import cryptography.hazmat.primitives.ciphers.aead import cryptography.hazmat.primitives.cmac import hashlib import hmac -fips_test_data = b"fips test data\0\0" -fips_test_key = b"fips test key\0\0\0" -def print_static_u8_array_definition(name, value): - print('') - print(f'static const u8 {name}[] __initconst __maybe_unused = {{') +def print_static_u8_array_definition(file, name, value): + print("", file=file) + print(f"static const u8 {name}[] __initconst __maybe_unused = {{", file=file) for i in range(0, len(value), 8): - line = '\t' + ''.join(f'0x{b:02x}, ' for b in value[i:i+8]) - print(f'{line.rstrip()}') - print('};') - -print('/* SPDX-License-Identifier: GPL-2.0-or-later */') -print(f'/* This file was generated by: gen-fips-testvecs.py */') -print() -print('#include <linux/fips.h>') - -print_static_u8_array_definition("fips_test_data", fips_test_data) -print_static_u8_array_definition("fips_test_key", fips_test_key) - -for alg in 'sha1', 'sha256', 'sha512': - ctx = hmac.new(fips_test_key, digestmod=alg) - ctx.update(fips_test_data) - print_static_u8_array_definition(f'fips_test_hmac_{alg}_value', ctx.digest()) - -print_static_u8_array_definition(f'fips_test_sha3_256_value', - hashlib.sha3_256(fips_test_data).digest()) - -aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_key) -aes_cmac = cryptography.hazmat.primitives.cmac.CMAC(aes) -aes_cmac.update(fips_test_data) -print_static_u8_array_definition('fips_test_aes_cmac_value', - aes_cmac.finalize()) + line = "\t" + "".join(f"0x{b:02x}, " for b in value[i : i + 8]) + print(f"{line.rstrip()}", file=file) + print("};", file=file) + + +def print_header(file): + print("/* SPDX-License-Identifier: GPL-2.0-or-later */", file=file) + print("/* This file was generated by: gen-fips-testvecs.py */", file=file) + print("/* clang-format off */", file=file) + print("", file=file) + print("#include <linux/fips.h>", file=file) + + +def gen_aes_test_data(file): + fips_test_data = b"fips test data\0\0" + fips_test_ad = b"fips test ad\0\0\0\0" + fips_test_iv = b"fips test iv\0\0\0\0" + fips_test_key = b"fips test key\0\0\0" + fips_test_xts_key = b"key1" + (b"\0" * 12) + b"key2" + (b"\0" * 12) + + print_header(file) + print_static_u8_array_definition(file, "fips_test_data", fips_test_data) + print_static_u8_array_definition(file, "fips_test_ad", fips_test_ad) + print_static_u8_array_definition(file, "fips_test_iv", fips_test_iv) + print_static_u8_array_definition(file, "fips_test_key", fips_test_key) + print_static_u8_array_definition(file, "fips_test_xts_key", fips_test_xts_key) + + aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_key) + + # AES-CMAC + aes_cmac = cryptography.hazmat.primitives.cmac.CMAC(aes) + aes_cmac.update(fips_test_data) + print_static_u8_array_definition( + file, "fips_test_aes_cmac_value", aes_cmac.finalize() + ) + + # AES-ECB + cipher = cryptography.hazmat.primitives.ciphers.Cipher( + aes, cryptography.hazmat.primitives.ciphers.modes.ECB() + ) + encryptor = cipher.encryptor() + ctext = encryptor.update(fips_test_data) + encryptor.finalize() + print_static_u8_array_definition(file, "fips_test_aes_ecb_ctext", ctext) + + # AES-CBC + cipher = cryptography.hazmat.primitives.ciphers.Cipher( + aes, cryptography.hazmat.primitives.ciphers.modes.CBC(fips_test_iv) + ) + encryptor = cipher.encryptor() + ctext = encryptor.update(fips_test_data) + encryptor.finalize() + print_static_u8_array_definition(file, "fips_test_aes_cbc_ctext", ctext) + + # AES-CBC-CTS + cipher = cryptography.hazmat.primitives.ciphers.Cipher( + aes, cryptography.hazmat.primitives.ciphers.modes.CBC(fips_test_iv) + ) + encryptor = cipher.encryptor() + ctext = encryptor.update(fips_test_data * 2) + encryptor.finalize() + ctext = ctext[16:32] + ctext[0:16] + print_static_u8_array_definition(file, "fips_test_aes_cbc_cts_ctext", ctext) + + # AES-CTR + cipher = cryptography.hazmat.primitives.ciphers.Cipher( + aes, cryptography.hazmat.primitives.ciphers.modes.CTR(fips_test_iv) + ) + encryptor = cipher.encryptor() + ctext = encryptor.update(fips_test_data) + encryptor.finalize() + print_static_u8_array_definition(file, "fips_test_aes_ctr_ctext", ctext) + + # AES-XTS + cipher = cryptography.hazmat.primitives.ciphers.Cipher( + cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_xts_key), + cryptography.hazmat.primitives.ciphers.modes.XTS(fips_test_iv), + ) + encryptor = cipher.encryptor() + ctext = encryptor.update(fips_test_data) + encryptor.finalize() + print_static_u8_array_definition(file, "fips_test_aes_xts_ctext", ctext) + + # AES-GCM + cipher = cryptography.hazmat.primitives.ciphers.aead.AESGCM(fips_test_key) + ct_and_tag = cipher.encrypt( + nonce=fips_test_iv[:12], data=fips_test_data, associated_data=fips_test_ad + ) + print_static_u8_array_definition( + file, "fips_test_aes_gcm_ctext_and_tag", ct_and_tag + ) + + # AES-CCM + cipher = cryptography.hazmat.primitives.ciphers.aead.AESCCM( + fips_test_key, tag_length=16 + ) + ct_and_tag = cipher.encrypt( + nonce=fips_test_iv[:13], data=fips_test_data, associated_data=fips_test_ad + ) + print_static_u8_array_definition( + file, "fips_test_aes_ccm_ctext_and_tag", ct_and_tag + ) + + +def gen_sha_test_data(file): + fips_test_data = b"fips test data\0\0" + fips_test_key = b"fips test key\0\0\0" + + print_header(file) + print_static_u8_array_definition(file, "fips_test_data", fips_test_data) + print_static_u8_array_definition(file, "fips_test_key", fips_test_key) + + for alg in "sha1", "sha256", "sha512": + ctx = hmac.new(fips_test_key, digestmod=alg) + ctx.update(fips_test_data) + print_static_u8_array_definition( + file, f"fips_test_hmac_{alg}_value", ctx.digest() + ) + + print_static_u8_array_definition( + file, "fips_test_sha3_256_value", hashlib.sha3_256(fips_test_data).digest() + ) + + +filename = "lib/crypto/fips-aes.h" +with open(filename, "w") as file: + print(f"Generating {filename}") + gen_aes_test_data(file) + +filename = "lib/crypto/fips-sha.h" +with open(filename, "w") as file: + print(f"Generating {filename}") + gen_sha_test_data(file) |
