diff --git a/META.yml b/META.yml index e3cb4be..845ee4f 100644 --- a/META.yml +++ b/META.yml @@ -11,6 +11,7 @@ implementations: length-secret-key: 1632 length-shared-secret: 32 nistkat-sha256: 4b88ac7643ff60209af1175e025f354272e88df827a0ce1c056e403629b88e04 + nistkat-shake256-256: 4b075815c72f4984e2290a2ebb62f6aa2c42bb386b9a210a78bf6ac73ee02cb8 - name: mlkem768 claimed-nist-level: 3 claimed-security: IND-CCA2 @@ -19,6 +20,7 @@ implementations: length-secret-key: 2400 length-shared-secret: 32 nistkat-sha256: 21b4a1e1ea34a13c26a9da5eeb9325afb5ca11596ca6f3704c3f2637e3ea7524 + nistkat-shake256-256: 3acd660b1b60808c1b8b02f499ffdc4bdacaaf35ec02a267b7a8e40dd4b26457 - name: mlkem1024 claimed-nist-level: 5 claimed-security: IND-CCA2 @@ -27,3 +29,4 @@ implementations: length-secret-key: 3168 length-shared-secret: 32 nistkat-sha256: 6471398b0a728ee1ef39e93bb89b526fbf59587a3662edadbcfc6c88a512cd71 + nistkat-shake256-256: e619f782857675c7d273139a48f8081652cc9c583c92aa4e627a2f36a7d943d1 diff --git a/mk/mps2-an386.mk b/mk/mps2-an386.mk index 5bb264f..6f0cb36 100644 --- a/mk/mps2-an386.mk +++ b/mk/mps2-an386.mk @@ -47,6 +47,7 @@ else LIBHAL_SRC += \ test/common/nistkatrng.c \ test/common/aes.c + CPPFLAGS += -Itest/common endif endif diff --git a/scripts/tests b/scripts/tests index b345f11..4b721f8 100755 --- a/scripts/tests +++ b/scripts/tests @@ -1,5 +1,6 @@ #!/usr/bin/env python # SPDX-License-Identifier: Apache-2.0 +import sys import serial import hashlib import platform @@ -253,7 +254,7 @@ def nistkat(platform_cfg, verbose, emulate): "--arg", "scheme", scheme, - '.implementations.[] | select(.name == $scheme) | ."nistkat-sha256"', + '.implementations.[] | select(.name == $scheme) | ."nistkat-shake256-256"', "./META.yml", ], capture_output=True, @@ -269,7 +270,7 @@ def nistkat(platform_cfg, verbose, emulate): platform_cfg, 0, scheme_hash, - lambda output: hashlib.sha256(output).hexdigest(), + lambda output: str(output, encoding="utf-8").strip().lower(), verbose, ) except asyncio.CancelledError: diff --git a/test/common/nistkatrng.c b/test/common/nistkatrng.c index f38a549..c57cade 100644 --- a/test/common/nistkatrng.c +++ b/test/common/nistkatrng.c @@ -1,98 +1,88 @@ -// SPDX-License-Identifier: CC0-1.0 +// SPDX-License-Identifier: Apache-2.0 #include #include #include "aes.h" #include "randombytes.h" +#include "nistkatrng.h" typedef struct { - uint8_t Key[32]; - uint8_t V[16]; - int reseed_counter; -} AES256_CTR_DRBG_struct; - -static AES256_CTR_DRBG_struct DRBG_ctx; -static void AES256_CTR_DRBG_Update(const uint8_t *provided_data, uint8_t *Key, uint8_t *V); - -// Use whatever AES implementation you have. This uses AES from openSSL library -// key - 256-bit AES key -// ctr - a 128-bit plaintext value -// buffer - a 128-bit ciphertext value -static void AES256_ECB(uint8_t *key, uint8_t *ctr, uint8_t *buffer) { - aes256ctx ctx; - aes256_ecb_keyexp(&ctx, key); - aes256_ecb(buffer, ctr, 1, &ctx); - aes256_ctx_release(&ctx); + unsigned char key[AES256_KEYBYTES]; + unsigned char ctr[AES_BLOCKBYTES]; +} nistkatctx; + +static nistkatctx ctx; + +static void _aes256_ecb(unsigned char key[AES256_KEYBYTES], unsigned char ctr[AES_BLOCKBYTES], unsigned char buffer[AES_BLOCKBYTES]) { + aes256ctx aesctx; + aes256_ecb_keyexp(&aesctx, key); + aes256_ecb(buffer, ctr, 1, &aesctx); + aes256_ctx_release(&aesctx); } -void nist_kat_init(uint8_t *entropy_input, const uint8_t *personalization_string, int security_strength); -void nist_kat_init(uint8_t *entropy_input, const uint8_t *personalization_string, int security_strength) { - uint8_t seed_material[48]; +static void aes256_block_update(uint8_t block[AES_BLOCKBYTES]) { + for (int j = AES_BLOCKBYTES - 1; j >= 0; j--) { + ctx.ctr[j]++; - assert(security_strength == 256); - memcpy(seed_material, entropy_input, 48); - if (personalization_string) { - for (int i = 0; i < 48; i++) { - seed_material[i] ^= personalization_string[i]; + if (ctx.ctr[j] != 0x00) { + break; } } - memset(DRBG_ctx.Key, 0x00, 32); - memset(DRBG_ctx.V, 0x00, 16); - AES256_CTR_DRBG_Update(seed_material, DRBG_ctx.Key, DRBG_ctx.V); - DRBG_ctx.reseed_counter = 1; + + _aes256_ecb(ctx.key, ctx.ctr, block); } -int randombytes(uint8_t *buf, size_t n) { - uint8_t block[16]; - int i = 0; - - while (n > 0) { - //increment V - for (int j = 15; j >= 0; j--) { - if (DRBG_ctx.V[j] == 0xff) { - DRBG_ctx.V[j] = 0x00; - } else { - DRBG_ctx.V[j]++; - break; - } - } - AES256_ECB(DRBG_ctx.Key, DRBG_ctx.V, block); - if (n > 15) { - memcpy(buf + i, block, 16); - i += 16; - n -= 16; - } else { - memcpy(buf + i, block, n); - n = 0; +static void nistkat_update(const unsigned char *provided_data, unsigned char *key, unsigned char *ctr) { + int len = AES256_KEYBYTES + AES_BLOCKBYTES; + uint8_t tmp[len]; + + for (int i = 0; i < len / AES_BLOCKBYTES; i++) { + aes256_block_update(tmp + AES_BLOCKBYTES * i); + } + + if (provided_data) { + for (int i = 0; i < len; i++) { + tmp[i] ^= provided_data[i]; } } - AES256_CTR_DRBG_Update(NULL, DRBG_ctx.Key, DRBG_ctx.V); - DRBG_ctx.reseed_counter++; - return 0; + + memcpy(key, tmp, AES256_KEYBYTES); + memcpy(ctr, tmp + AES256_KEYBYTES, AES_BLOCKBYTES); } -static void AES256_CTR_DRBG_Update(const uint8_t *provided_data, uint8_t *Key, uint8_t *V) { - uint8_t temp[48]; - - for (int i = 0; i < 3; i++) { - //increment V - for (int j = 15; j >= 0; j--) { - if (V[j] == 0xff) { - V[j] = 0x00; - } else { - V[j]++; - break; - } +void randombytes_init(unsigned char entropy_input[AES256_KEYBYTES + AES_BLOCKBYTES], const unsigned char personalization_string[AES256_KEYBYTES + AES_BLOCKBYTES], int security_strength) { + int len = AES256_KEYBYTES + AES_BLOCKBYTES; + uint8_t seed_material[len]; + (void) security_strength; + + memcpy(seed_material, entropy_input, len); + if (personalization_string) { + for (int i = 0; i < len; i++) { + seed_material[i] ^= personalization_string[i]; } + } + memset(ctx.key, 0x00, AES256_KEYBYTES); + memset(ctx.ctr, 0x00, AES_BLOCKBYTES); + nistkat_update(seed_material, ctx.key, ctx.ctr); +} + +int randombytes(uint8_t *buf, size_t n) { + uint8_t block[AES_BLOCKBYTES]; + + size_t nb = n / AES_BLOCKBYTES; + size_t tail = n % AES_BLOCKBYTES; - AES256_ECB(Key, V, temp + 16 * i); + for (size_t i = 0; i < nb; i++) { + aes256_block_update(block); + memcpy(buf + i * AES_BLOCKBYTES, block, AES_BLOCKBYTES); } - if (provided_data != NULL) { - for (int i = 0; i < 48; i++) { - temp[i] ^= provided_data[i]; - } + + if (tail > 0) { + aes256_block_update(block); + memcpy(buf + nb * AES_BLOCKBYTES, block, tail); } - memcpy(Key, temp, 32); - memcpy(V, temp + 32, 16); + + nistkat_update(NULL, ctx.key, ctx.ctr); + return 0; } diff --git a/test/common/nistkatrng.h b/test/common/nistkatrng.h new file mode 100644 index 0000000..1e3be2a --- /dev/null +++ b/test/common/nistkatrng.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 + +#ifndef NISTKATRNG_H +#define NISTKATRNG_H + +#include "aes.h" + +void randombytes_init(unsigned char entropy_input[AES256_KEYBYTES + AES_BLOCKBYTES], const unsigned char personalization_string[AES256_KEYBYTES + AES_BLOCKBYTES], int security_strength); + +#endif diff --git a/test/nistkat.c b/test/nistkat.c index 74723ab..04a6038 100644 --- a/test/nistkat.c +++ b/test/nistkat.c @@ -12,6 +12,8 @@ #include "kem.h" #include "hal.h" #include "randombytes.h" +#include "nistkatrng.h" +#include "fips202.h" // NOTE: used Kyber in the nistkat rsp file for now to avoid changing the checksum #if (MLKEM_K == 2) @@ -22,33 +24,44 @@ #define OLD_CRYPTO_ALGNAME "Kyber1024" #endif -void nist_kat_init(unsigned char *entropy_input, unsigned char *personalization_string, int security_strength); - -static void hal_send_Bstr(const char *S, const uint8_t *A, size_t L) { - size_t i; - char buf[16384]; +size_t format_bstr(char *buf, const char *S, const uint8_t *A, size_t L) { + size_t len = strlen(S); memcpy(buf, S, strlen(S)); - for (i = 0; i < L; i++) { - snprintf(buf + strlen(S) + 2 * i, 3, "%02X", A[i]); - } - if (L == 0) { - snprintf(buf + strlen(S) + 2 * L, 3, "00"); + + for (size_t i = 0; i < L; i++) { + len += snprintf(buf + strlen(S) + 2 * i, 3, "%02X", A[i]); } + return len; +} + +void inc_hash_bstr(shake256incctx *state, const char *S, const uint8_t *A, size_t L) { + size_t len; + char buf[strlen(S) + 2 * L + 1]; + + len = format_bstr(buf, S, A, L); + len += snprintf(buf + strlen(S) + 2 * L, 2, "\n"); + + shake256_inc_absorb(state, (unsigned char *)buf, len); +} + +void hal_send_bstr(const char *S, const uint8_t *A, size_t L) { + char buf[strlen(S) + 2 * L + 1]; + format_bstr(buf, S, A, L); hal_send_str(buf); } -int hal_send_format(const char *S, ...) { - int result; +size_t inc_hash_format(shake256incctx *state, const char *S, ...) { + size_t len; char buf[1024]; va_list args; va_start(args, S); - result = vsnprintf(buf, 1024, S, args); + len = vsnprintf(buf, 1024, S, args); va_end(args); - hal_send_str(buf); + shake256_inc_absorb(state, (unsigned char *)buf, len); - return result; + return len; } int main(void) { @@ -60,6 +73,8 @@ int main(void) { uint8_t ciphertext[CRYPTO_CIPHERTEXTBYTES]; uint8_t shared_secret_e[CRYPTO_BYTES]; uint8_t shared_secret_d[CRYPTO_BYTES]; + uint8_t result[32]; + shake256incctx hash_state; int rc; hal_setup(CLOCK_FAST); @@ -69,38 +84,40 @@ int main(void) { entropy_input[i] = i; } - nist_kat_init(entropy_input, NULL, 256); + randombytes_init(entropy_input, NULL, 256); for (size_t i = 0; i < counts; i++) { randombytes(seeds[i], 48); } - hal_send_format("# %s\n", OLD_CRYPTO_ALGNAME); + shake256_inc_init(&hash_state); + + inc_hash_format(&hash_state, "# %s\n\n", OLD_CRYPTO_ALGNAME); for (size_t i = 0; i < counts; i++) { - hal_send_format("count = %d", i); - nist_kat_init(seeds[i], NULL, 256); - hal_send_Bstr("seed = ", seeds[i], 48); + inc_hash_format(&hash_state, "count = %d\n", i); + randombytes_init(seeds[i], NULL, 256); + inc_hash_bstr(&hash_state, "seed = ", seeds[i], 48); rc = crypto_kem_keypair(public_key, secret_key); if (rc != 0) { - hal_send_format("[kat_kem] %s ERROR: crypto_kem_keypair failed!\n", CRYPTO_ALGNAME); + hal_send_str("ERROR: crypto_kem_keypair failed!"); return -1; } - hal_send_Bstr("pk = ", public_key, CRYPTO_PUBLICKEYBYTES); - hal_send_Bstr("sk = ", secret_key, CRYPTO_SECRETKEYBYTES); + inc_hash_bstr(&hash_state, "pk = ", public_key, CRYPTO_PUBLICKEYBYTES); + inc_hash_bstr(&hash_state, "sk = ", secret_key, CRYPTO_SECRETKEYBYTES); rc = crypto_kem_enc(ciphertext, shared_secret_e, public_key); if (rc != 0) { - hal_send_format("[kat_kem] %s ERROR: crypto_kem_enc failed!\n", CRYPTO_ALGNAME); + hal_send_str("ERROR: crypto_kem_enc failed!"); return -2; } - hal_send_Bstr("ct = ", ciphertext, CRYPTO_CIPHERTEXTBYTES); - hal_send_Bstr("ss = ", shared_secret_e, CRYPTO_BYTES); + inc_hash_bstr(&hash_state, "ct = ", ciphertext, CRYPTO_CIPHERTEXTBYTES); + inc_hash_bstr(&hash_state, "ss = ", shared_secret_e, CRYPTO_BYTES); rc = crypto_kem_dec(shared_secret_d, ciphertext, secret_key); if (rc != 0) { - hal_send_format("[kat_kem] %s ERROR: crypto_kem_dec failed!\n", CRYPTO_ALGNAME); + hal_send_str("ERROR: crypto_kem_dec failed!"); return -3; } @@ -110,10 +127,12 @@ int main(void) { return -4; } - hal_send_str(""); + inc_hash_format(&hash_state, "\n"); } + shake256_inc_finalize(&hash_state); + shake256_inc_squeeze(result, 32, &hash_state); + hal_send_bstr("", result, 32); SERIAL_MARKER(); return 0; - }