@@ -0,0 +1,101 @@ | |||
// | |||
// rng.c | |||
// | |||
// Created by Bassham, Lawrence E (Fed) on 8/29/17. | |||
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved. | |||
// Modified for liboqs by Douglas Stebila | |||
// | |||
#include <assert.h> | |||
#include <string.h> | |||
#include "aes.h" | |||
#include "randombytes.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(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_keyexp(&ctx, key); | |||
aes256_ecb(buffer, ctr, 1, &ctx); | |||
} | |||
void nist_kat_init(uint8_t *entropy_input, uint8_t *personalization_string, int security_strength); | |||
void nist_kat_init(uint8_t *entropy_input, uint8_t *personalization_string, int security_strength) { | |||
uint8_t seed_material[48]; | |||
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]; | |||
} | |||
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; | |||
} | |||
int randombytes(uint8_t *x, size_t xlen) { | |||
uint8_t block[16]; | |||
int i = 0; | |||
while (xlen > 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 (xlen > 15) { | |||
memcpy(x + i, block, 16); | |||
i += 16; | |||
xlen -= 16; | |||
} else { | |||
memcpy(x + i, block, xlen); | |||
xlen = 0; | |||
} | |||
} | |||
AES256_CTR_DRBG_Update(NULL, DRBG_ctx.Key, DRBG_ctx.V); | |||
DRBG_ctx.reseed_counter++; | |||
return 0; | |||
} | |||
static void AES256_CTR_DRBG_Update(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; | |||
} | |||
} | |||
AES256_ECB(Key, V, temp + 16 * i); | |||
} | |||
if (provided_data != NULL) | |||
for (int i = 0; i < 48; i++) { | |||
temp[i] ^= provided_data[i]; | |||
} | |||
memcpy(Key, temp, 32); | |||
memcpy(V, temp + 32, 16); | |||
} |
@@ -5,6 +5,7 @@ length-public-key: 21520 | |||
length-ciphertext: 21632 | |||
length-shared-secret: 32 | |||
testvectors-sha256: 91dce2e12200afc88f951aff9349b72d1dda6e53e305135a891aa1a67ef88352 | |||
nistkat-sha256: 2f4f1c352c1b343cce386c54234ca39fe29b48e45c66300f7311f5d3060d82b3 | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 21520 | |||
length-ciphertext: 21632 | |||
length-shared-secret: 32 | |||
testvectors-sha256: 8b62fc01fc1e4b4e336776b09b37aaf55d161b7c815b3298f39d4444b011e10c | |||
nistkat-sha256: 6e54e319cc590c3f136af81990a04cd0009ef78dec92825d2eb834adfec661dc | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 9616 | |||
length-ciphertext: 9720 | |||
length-shared-secret: 16 | |||
testvectors-sha256: d4c7d30254a8cac8ad73b742b31813e47dcae6532a4dcbe13c04d72a2920a086 | |||
nistkat-sha256: c1f006531583896c47416e10707d1c8e487fe549df304d7a9c43155d5e47b8b6 | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 9616 | |||
length-ciphertext: 9720 | |||
length-shared-secret: 16 | |||
testvectors-sha256: 8f922de02d41005fcc3c4164b2ab74c4c7b588ed69e34e22607d1ae4ab13d2c5 | |||
nistkat-sha256: df2b77b8e108c61d16c78a99e79f3351ab15840a690f25c1f87a8e89295e9219 | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 15632 | |||
length-ciphertext: 15744 | |||
length-shared-secret: 24 | |||
testvectors-sha256: 30a2a3f2d834b5d90cd10241f53c4a4379abeea0dbd4eb65b260749b2ba81391 | |||
nistkat-sha256: 7e415ab659d0d08d8f43135e1e9d75a8b342f52b65e8326ebf8135521b987615 | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 15632 | |||
length-ciphertext: 15744 | |||
length-shared-secret: 24 | |||
testvectors-sha256: 00707dc8158c6e51e70e9a7b23a87054c5f2167b77a2e5940b8e82519834717b | |||
nistkat-sha256: 0d3d3a3ad11b69a93e72f1233b310884e97be8d16c9981bf1eb1321880cd0658 | |||
principal-submitter: Douglas Stebila, University of Waterloo | |||
auxiliary-submitters: | |||
- Erdem Alkim | |||
@@ -5,6 +5,7 @@ length-public-key: 1088 | |||
length-ciphertext: 1152 | |||
length-shared-secret: 32 | |||
testvectors-sha256: 2f5cf9937959eb4a3bc910f71e830e9e0de029b28093c6192d2c3e915913016f | |||
nistkat-sha256: d6dbb9399d1ba4ee2d986de3e54a461256b91d6c2f9b90ad2410cf41e09b64d1 | |||
principal-submitter: Peter Schwabe | |||
auxiliary-submitters: | |||
- Roberto Avanzi | |||
@@ -5,6 +5,7 @@ length-public-key: 699 | |||
length-ciphertext: 699 | |||
length-shared-secret: 32 | |||
testvectors-sha256: 1a7c207b96f29043fad3e31e69a806aacd98e035ec0128fdf97350ec833f3b83 | |||
nistkat-sha256: 7ecb93dbc7a588878691f2b2d656ebc42192779f335e3a96197f4ce2134f72c6 | |||
principal-submitter: John M. Schanck | |||
auxiliary-submitters: | |||
- Cong Chen | |||
@@ -41,6 +41,9 @@ testvectors: $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) | |||
.PHONY: printparams | |||
printparams: $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) | |||
.PHONY: nistkat | |||
nistkat: $(DEST_DIR)/nistkat_$(SCHEME)_$(IMPLEMENTATION) | |||
$(DEST_DIR)/test_common_%: common/%.c $(COMMON_FILES) | |||
mkdir -p $(DEST_DIR) | |||
$(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ | |||
@@ -57,10 +60,16 @@ $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE) | |||
mkdir -p $(DEST_DIR) | |||
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/printparams.c -o $@ | |||
$(DEST_DIR)/nistkat_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/nistkat.c $(COMMON_FILES) $(COMMON_DIR)/nistkatrng.c $(COMMON_HEADERS) | |||
mkdir -p $(DEST_DIR) | |||
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/nistkat.c $(COMMON_FILES) $(COMMON_DIR)/nistkatrng.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION) | |||
.PHONY: clean | |||
clean: | |||
$(RM) $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION) | |||
$(RM) $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) | |||
$(RM) $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) | |||
$(RM) $(DEST_DIR)/nistkat_$(SCHEME)_$(IMPLEMENTATION) | |||
$(RM) $(DEST_DIR)/test_aes | |||
$(RM) $(DEST_DIR)/test_fips202 | |||
$(RM) $(DEST_DIR)/test_sha2 |
@@ -0,0 +1,95 @@ | |||
#include <assert.h> | |||
#include <errno.h> | |||
#include <stdbool.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/stat.h> | |||
#include "api.h" | |||
#include "randombytes.h" | |||
// https://stackoverflow.com/a/1489985/1711232 | |||
#define PASTER(x, y) x##_##y | |||
#define EVALUATOR(x, y) PASTER(x, y) | |||
#define NAMESPACE(fun) EVALUATOR(PQCLEAN_NAMESPACE, fun) | |||
#define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES) | |||
#define CRYPTO_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES) | |||
#define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES) | |||
#define CRYPTO_CIPHERTEXTBYTES NAMESPACE(CRYPTO_CIPHERTEXTBYTES) | |||
#define CRYPTO_ALGNAME NAMESPACE(CRYPTO_ALGNAME) | |||
#define crypto_kem_keypair NAMESPACE(crypto_kem_keypair) | |||
#define crypto_kem_enc NAMESPACE(crypto_kem_enc) | |||
#define crypto_kem_dec NAMESPACE(crypto_kem_dec) | |||
void nist_kat_init(unsigned char *entropy_input, unsigned char *personalization_string, int security_strength); | |||
static void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { | |||
size_t i; | |||
fprintf(fp, "%s", S); | |||
for (i = 0; i < L; i++) { | |||
fprintf(fp, "%02X", A[i]); | |||
} | |||
if (L == 0) { | |||
fprintf(fp, "00"); | |||
} | |||
fprintf(fp, "\n"); | |||
} | |||
int main() { | |||
uint8_t entropy_input[48]; | |||
uint8_t seed[48]; | |||
FILE *fh = stdout; | |||
uint8_t public_key[CRYPTO_PUBLICKEYBYTES]; | |||
uint8_t secret_key[CRYPTO_SECRETKEYBYTES]; | |||
uint8_t ciphertext[CRYPTO_CIPHERTEXTBYTES]; | |||
uint8_t shared_secret_e[CRYPTO_BYTES]; | |||
uint8_t shared_secret_d[CRYPTO_BYTES]; | |||
int rc; | |||
for (size_t i = 0; i < 48; i++) { | |||
entropy_input[i] = i; | |||
} | |||
nist_kat_init(entropy_input, NULL, 256); | |||
fprintf(fh, "count = 0\n"); | |||
randombytes(seed, 48); | |||
fprintBstr(fh, "seed = ", seed, 48); | |||
nist_kat_init(seed, NULL, 256); | |||
rc = crypto_kem_keypair(public_key, secret_key); | |||
if (rc != 0) { | |||
fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_keypair failed!\n", CRYPTO_ALGNAME); | |||
return -1; | |||
} | |||
fprintBstr(fh, "pk = ", public_key, CRYPTO_PUBLICKEYBYTES); | |||
fprintBstr(fh, "sk = ", secret_key, CRYPTO_SECRETKEYBYTES); | |||
rc = crypto_kem_enc(ciphertext, shared_secret_e, public_key); | |||
if (rc != 0) { | |||
fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_enc failed!\n", CRYPTO_ALGNAME); | |||
return -2; | |||
} | |||
fprintBstr(fh, "ct = ", ciphertext, CRYPTO_CIPHERTEXTBYTES); | |||
fprintBstr(fh, "ss = ", shared_secret_e, CRYPTO_BYTES); | |||
rc = crypto_kem_dec(shared_secret_d, ciphertext, secret_key); | |||
if (rc != 0) { | |||
fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_dec failed!\n", CRYPTO_ALGNAME); | |||
return -3; | |||
} | |||
rc = memcmp(shared_secret_e, shared_secret_d, CRYPTO_BYTES); | |||
if (rc != 0) { | |||
fprintf(stderr, "[kat_kem] %s ERROR: shared secrets are not equal\n", CRYPTO_ALGNAME); | |||
return -4; | |||
} | |||
return 0; | |||
} |
@@ -65,6 +65,7 @@ EXPECTED_FIELDS = { | |||
KEM_FIELDS = { | |||
'length-ciphertext': {'type': int, 'min': 1}, | |||
'length-shared-secret': {'type': int, 'min': 1}, | |||
'nistkat-sha256': {'type': str, 'length': 64}, | |||
} | |||
SIGNATURE_FIELDS = { | |||
@@ -0,0 +1,49 @@ | |||
""" | |||
Checks that (hash of the) KATs (in NIST format) produced on this platform matches | |||
the one provided in the META file for every scheme/implementation. | |||
Note that this only uses the first test case from the NIST-format KAT files. | |||
The appropriate hash can be generated from the original submission's KAT file | |||
using the command: | |||
cat PQCkemKAT_whatever.rsp | head -n 8 | tail -n 6 | sha256sum | |||
""" | |||
import hashlib | |||
import os | |||
import pqclean | |||
import helpers | |||
def test_nistkat(): | |||
for scheme in pqclean.Scheme.all_schemes(): | |||
if scheme.type != 'kem': continue | |||
for implementation in scheme.implementations: | |||
if helpers.permit_test('nistkat', implementation): | |||
yield check_nistkat, implementation | |||
def check_nistkat(implementation): | |||
helpers.make('nistkat', | |||
TYPE=implementation.scheme.type, | |||
SCHEME=implementation.scheme.name, | |||
IMPLEMENTATION=implementation.name, | |||
working_dir=os.path.join('..', 'test')) | |||
out = helpers.run_subprocess( | |||
[os.path.join('..', 'bin', 'nistkat_{}_{}{}'.format( | |||
implementation.scheme.name, | |||
implementation.name, | |||
'.exe' if os.name == 'nt' else '' | |||
))], | |||
os.path.join('..', 'bin'), | |||
).replace('\r', '') | |||
assert(implementation.scheme.metadata()['nistkat-sha256'].lower() | |||
== hashlib.sha256(out.encode('utf-8')).hexdigest().lower()) | |||
if __name__ == '__main__': | |||
try: | |||
import nose2 | |||
nose2.main() | |||
except ImportError: | |||
import nose | |||
nose.runmodule() |