diff options
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/crypto/gen-fips-testvecs.py | 10 | ||||
| -rwxr-xr-x | scripts/crypto/gen-hash-testvecs.py | 97 |
2 files changed, 103 insertions, 4 deletions
diff --git a/scripts/crypto/gen-fips-testvecs.py b/scripts/crypto/gen-fips-testvecs.py index db873f88619a..9f18bcb97412 100755 --- a/scripts/crypto/gen-fips-testvecs.py +++ b/scripts/crypto/gen-fips-testvecs.py @@ -3,8 +3,12 @@ # # Script that generates lib/crypto/fips.h # +# Requires that python-cryptography be installed. +# # Copyright 2025 Google LLC +import cryptography.hazmat.primitives.ciphers +import cryptography.hazmat.primitives.cmac import hashlib import hmac @@ -34,3 +38,9 @@ for alg in 'sha1', 'sha256', 'sha512': 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()) diff --git a/scripts/crypto/gen-hash-testvecs.py b/scripts/crypto/gen-hash-testvecs.py index 8eeb650fcada..f356f87e1c77 100755 --- a/scripts/crypto/gen-hash-testvecs.py +++ b/scripts/crypto/gen-hash-testvecs.py @@ -3,8 +3,12 @@ # # Script that generates test vectors for the given hash function. # +# Requires that python-cryptography be installed. +# # Copyright 2025 Google LLC +import cryptography.hazmat.primitives.ciphers +import cryptography.hazmat.primitives.cmac import hashlib import hmac import sys @@ -24,6 +28,20 @@ def rand_bytes(length): out.append((seed >> 16) % 256) return bytes(out) +AES_256_KEY_SIZE = 32 + +# AES-CMAC. Just wraps the implementation from python-cryptography. +class AesCmac: + def __init__(self, key): + aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(key) + self.cmac = cryptography.hazmat.primitives.cmac.CMAC(aes) + + def update(self, data): + self.cmac.update(data) + + def digest(self): + return self.cmac.finalize() + POLY1305_KEY_SIZE = 32 # A straightforward, unoptimized implementation of Poly1305. @@ -50,6 +68,52 @@ class Poly1305: m = (self.h + self.s) % 2**128 return m.to_bytes(16, byteorder='little') +GHASH_POLY = sum((1 << i) for i in [128, 7, 2, 1, 0]) +GHASH_BLOCK_SIZE = 16 + +# A straightforward, unoptimized implementation of GHASH. +class Ghash: + + @staticmethod + def reflect_bits_in_bytes(v): + res = 0 + for offs in range(0, 128, 8): + for bit in range(8): + if (v & (1 << (offs + bit))) != 0: + res ^= 1 << (offs + 7 - bit) + return res + + @staticmethod + def bytes_to_poly(data): + return Ghash.reflect_bits_in_bytes(int.from_bytes(data, byteorder='little')) + + @staticmethod + def poly_to_bytes(poly): + return Ghash.reflect_bits_in_bytes(poly).to_bytes(16, byteorder='little') + + def __init__(self, key): + assert len(key) == 16 + self.h = Ghash.bytes_to_poly(key) + self.acc = 0 + + # Note: this supports partial blocks only at the end. + def update(self, data): + for i in range(0, len(data), 16): + # acc += block + self.acc ^= Ghash.bytes_to_poly(data[i:i+16]) + # acc = (acc * h) mod GHASH_POLY + product = 0 + for j in range(127, -1, -1): + if (self.h & (1 << j)) != 0: + product ^= self.acc << j + if (product & (1 << (128 + j))) != 0: + product ^= GHASH_POLY << j + self.acc = product + return self + + def digest(self): + return Ghash.poly_to_bytes(self.acc) + POLYVAL_POLY = sum((1 << i) for i in [128, 127, 126, 121, 0]) POLYVAL_BLOCK_SIZE = 16 @@ -80,9 +144,14 @@ class Polyval: return self.acc.to_bytes(16, byteorder='little') def hash_init(alg): + # The keyed hash functions are assigned a fixed random key here, to present + # them as unkeyed hash functions. This allows all the test cases for + # unkeyed hash functions to work on them. + if alg == 'aes-cmac': + return AesCmac(rand_bytes(AES_256_KEY_SIZE)) + if alg == 'ghash': + return Ghash(rand_bytes(GHASH_BLOCK_SIZE)) if alg == 'poly1305': - # Use a fixed random key here, to present Poly1305 as an unkeyed hash. - # This allows all the test cases for unkeyed hashes to work on Poly1305. return Poly1305(rand_bytes(POLY1305_KEY_SIZE)) if alg == 'polyval': return Polyval(rand_bytes(POLYVAL_BLOCK_SIZE)) @@ -116,6 +185,8 @@ def print_c_struct_u8_array_field(name, value): print('\t\t},') def alg_digest_size_const(alg): + if alg == 'aes-cmac': + return 'AES_BLOCK_SIZE' if alg.startswith('blake2'): return f'{alg.upper()}_HASH_SIZE' return f"{alg.upper().replace('-', '_')}_DIGEST_SIZE" @@ -234,6 +305,15 @@ def gen_additional_poly1305_testvecs(): 'poly1305_allones_macofmacs[POLY1305_DIGEST_SIZE]', Poly1305(key).update(data).digest()) +def gen_additional_ghash_testvecs(): + key = b'\xff' * GHASH_BLOCK_SIZE + hashes = b'' + for data_len in range(0, 4097, 16): + hashes += Ghash(key).update(b'\xff' * data_len).digest() + print_static_u8_array_definition( + 'ghash_allones_hashofhashes[GHASH_DIGEST_SIZE]', + Ghash(key).update(hashes).digest()) + def gen_additional_polyval_testvecs(): key = b'\xff' * POLYVAL_BLOCK_SIZE hashes = b'' @@ -245,16 +325,22 @@ def gen_additional_polyval_testvecs(): if len(sys.argv) != 2: sys.stderr.write('Usage: gen-hash-testvecs.py ALGORITHM\n') - sys.stderr.write('ALGORITHM may be any supported by Python hashlib; or poly1305, polyval, or sha3.\n') + sys.stderr.write('ALGORITHM may be any supported by Python hashlib;\n') + sys.stderr.write(' or aes-cmac, ghash, nh, poly1305, polyval, or sha3.\n') sys.stderr.write('Example: gen-hash-testvecs.py sha512\n') sys.exit(1) alg = sys.argv[1] print('/* SPDX-License-Identifier: GPL-2.0-or-later */') print(f'/* This file was generated by: {sys.argv[0]} {" ".join(sys.argv[1:])} */') -if alg.startswith('blake2'): +if alg == 'aes-cmac': + gen_unkeyed_testvecs(alg) +elif alg.startswith('blake2'): gen_unkeyed_testvecs(alg) gen_additional_blake2_testvecs(alg) +elif alg == 'ghash': + gen_unkeyed_testvecs(alg) + gen_additional_ghash_testvecs() elif alg == 'nh': gen_nh_testvecs() elif alg == 'poly1305': @@ -270,6 +356,9 @@ elif alg == 'sha3': print() print('/* SHAKE test vectors */') gen_additional_sha3_testvecs() +elif alg == 'sm3': + gen_unkeyed_testvecs(alg) + # Kernel doesn't implement HMAC-SM3 library functions yet. else: gen_unkeyed_testvecs(alg) gen_hmac_testvecs(alg) |
