diff --git a/test/kem/functest.c b/test/kem/functest.c new file mode 100644 index 00000000..ffd38ac8 --- /dev/null +++ b/test/kem/functest.c @@ -0,0 +1,263 @@ +#include "api.h" +#include "randombytes.h" + +#include +#include +#include +#include + +#ifndef NTESTS +#define NTESTS 5 +#endif + +const uint8_t canary[8] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF +}; + +/* allocate a bit more for all keys and messages and + * make sure it is not touched by the implementations. + */ +static void write_canary(uint8_t *d) { + for (size_t i = 0; i < 8; i++) { + d[i] = canary[i]; + } +} + +static int check_canary(const uint8_t *d) { + for (size_t i = 0; i < 8; i++) { + if (d[i] != canary[i]) { + return -1; + } + } + return 0; +} + +inline static void* malloc_s(size_t size) { + void *ptr = malloc(size); + if (ptr == NULL) { + perror("Malloc failed!"); + exit(1); + } + return ptr; +} + +// 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) + +#define RETURNS_ZERO(f) \ + if ((f) != 0) { \ + puts(#f " returned non-zero returncode"); \ + res = 1; \ + goto end; \ + } + +// https://stackoverflow.com/a/55243651/248065 +#define MY_TRUTHY_VALUE_X 1 +#define CAT(x,y) CAT_(x,y) +#define CAT_(x,y) x##y +#define HAS_NAMESPACE(x) CAT(CAT(MY_TRUTHY_VALUE_,CAT(PQCLEAN_NAMESPACE,CAT(_,x))),X) + +#if !HAS_NAMESPACE(API_H) +#error "namespace not properly defined for header guard" +#endif + +static int test_keys(void) { + /* + * This is most likely going to be aligned by the compiler. + * 16 extra bytes for canary + * 1 extra byte for unalignment + */ + int res = 0; + + uint8_t *key_a_aligned = malloc_s(CRYPTO_BYTES + 16 + 1); + uint8_t *key_b_aligned = malloc_s(CRYPTO_BYTES + 16 + 1); + uint8_t *pk_aligned = malloc_s(CRYPTO_PUBLICKEYBYTES + 16 + 1); + uint8_t *sendb_aligned = malloc_s(CRYPTO_CIPHERTEXTBYTES + 16 + 1); + uint8_t *sk_a_aligned = malloc_s(CRYPTO_SECRETKEYBYTES + 16 + 1); + + /* + * Make sure all pointers are odd. + * This ensures that the implementation does not assume anything about the + * data alignment. For example this would catch if an implementation + * directly uses these pointers to load into vector registers using movdqa. + */ + uint8_t *key_a = (uint8_t *) ((uintptr_t) key_a_aligned|(uintptr_t) 1); + uint8_t *key_b = (uint8_t *) ((uintptr_t) key_b_aligned|(uintptr_t) 1); + uint8_t *pk = (uint8_t *) ((uintptr_t) pk_aligned|(uintptr_t) 1); + uint8_t *sendb = (uint8_t *) ((uintptr_t) sendb_aligned|(uintptr_t) 1); + uint8_t *sk_a = (uint8_t *) ((uintptr_t) sk_a_aligned|(uintptr_t) 1); + + /* + * Write 8 byte canary before and after the actual memory regions. + * This is used to validate that the implementation does not assume + * anything about the placement of data in memory + * (e.g., assuming that the pk is always behind the sk) + */ + write_canary(key_a); + write_canary(key_a + CRYPTO_BYTES + 8); + write_canary(key_b); + write_canary(key_b + CRYPTO_BYTES + 8); + write_canary(pk); + write_canary(pk + CRYPTO_PUBLICKEYBYTES + 8); + write_canary(sendb); + write_canary(sendb + CRYPTO_CIPHERTEXTBYTES + 8); + write_canary(sk_a); + write_canary(sk_a + CRYPTO_SECRETKEYBYTES + 8); + + int i; + + for (i = 0; i < NTESTS; i++) { + // Alice generates a public key + RETURNS_ZERO(crypto_kem_keypair(pk + 8, sk_a + 8)); + + // Bob derives a secret key and creates a response + RETURNS_ZERO(crypto_kem_enc(sendb + 8, key_b + 8, pk + 8)); + + // Alice uses Bobs response to get her secret key + RETURNS_ZERO(crypto_kem_dec(key_a + 8, sendb + 8, sk_a + 8)); + + if (memcmp(key_a + 8, key_b + 8, CRYPTO_BYTES) != 0) { + printf("ERROR KEYS\n"); + res = 1; + goto end; + } + + // Validate that the implementation did not touch the canary + if (check_canary(key_a) || check_canary(key_a + CRYPTO_BYTES + 8) || + check_canary(key_b) || check_canary(key_b + CRYPTO_BYTES + 8 ) || + check_canary(pk) || check_canary(pk + CRYPTO_PUBLICKEYBYTES + 8 ) || + check_canary(sendb) || check_canary(sendb + CRYPTO_CIPHERTEXTBYTES + 8 ) || + check_canary(sk_a) || check_canary(sk_a + CRYPTO_SECRETKEYBYTES + 8 )) { + printf("ERROR canary overwritten\n"); + res = 1; + goto end; + } + } + +end: + free(key_a_aligned); + free(key_b_aligned); + free(pk_aligned); + free(sendb_aligned); + free(sk_a_aligned); + + return res; +} + +static int test_invalid_sk_a(void) { + uint8_t *sk_a = malloc_s(CRYPTO_SECRETKEYBYTES); + uint8_t *key_a = malloc_s(CRYPTO_BYTES); + uint8_t *key_b = malloc_s(CRYPTO_BYTES); + uint8_t *pk = malloc_s(CRYPTO_PUBLICKEYBYTES); + uint8_t *sendb = malloc_s(CRYPTO_CIPHERTEXTBYTES); + int i; + int returncode; + int res = 0; + + for (i = 0; i < NTESTS; i++) { + // Alice generates a public key + RETURNS_ZERO(crypto_kem_keypair(pk, sk_a)); + + // Bob derives a secret key and creates a response + RETURNS_ZERO(crypto_kem_enc(sendb, key_b, pk)); + + // Replace secret key with random values + randombytes(sk_a, CRYPTO_SECRETKEYBYTES); + + // Alice uses Bobs response to get her secret key + if ((returncode = crypto_kem_dec(key_a, sendb, sk_a)) > 0) { + printf("ERROR failing crypto_kem_dec returned %d instead of " + "negative or zero code\n", + returncode); + res = 1; + goto end; + } + + if (!memcmp(key_a, key_b, CRYPTO_BYTES)) { + printf("ERROR invalid sk_a\n"); + res = 1; + goto end; + } + } + +end: + free(sk_a); + free(key_a); + free(key_b); + free(pk); + free(sendb); + + return res; +} + +static int test_invalid_ciphertext(void) { + uint8_t *sk_a = malloc_s(CRYPTO_SECRETKEYBYTES); + uint8_t *key_a = malloc_s(CRYPTO_BYTES); + uint8_t *key_b = malloc_s(CRYPTO_BYTES); + uint8_t *pk = malloc_s(CRYPTO_PUBLICKEYBYTES); + uint8_t *sendb = malloc_s(CRYPTO_CIPHERTEXTBYTES); + int i; + int returncode; + int res = 0; + + for (i = 0; i < NTESTS; i++) { + // Alice generates a public key + RETURNS_ZERO(crypto_kem_keypair(pk, sk_a)); + + // Bob derives a secret key and creates a response + RETURNS_ZERO(crypto_kem_enc(sendb, key_b, pk)); + + // Change ciphertext to random value + randombytes(sendb, sizeof(sendb)); + + // Alice uses Bobs response to get her secret key + if ((returncode = crypto_kem_dec(key_a, sendb, sk_a)) > 0) { + printf("ERROR crypto_kem_dec should either fail (negative " + "returncode) or succeed (return 0) but returned %d\n", + returncode); + res = 1; + goto end; + } + + if (!memcmp(key_a, key_b, CRYPTO_BYTES)) { + printf("ERROR invalid ciphertext\n"); + res = 1; + goto end; + } + } +end: + free(sk_a); + free(key_a); + free(key_b); + free(pk); + free(sendb); + + return res; +} + +int main(void) { + // Check if CRYPTO_ALGNAME is printable + puts(CRYPTO_ALGNAME); + + int result = 0; + result += test_keys(); + result += test_invalid_sk_a(); + result += test_invalid_ciphertext(); + + if (result != 0) { + puts("Errors occurred"); + } + return result; +} diff --git a/test/kem/nistkat.c b/test/kem/nistkat.c new file mode 100644 index 00000000..364905c2 --- /dev/null +++ b/test/kem/nistkat.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 (uint8_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; + +} diff --git a/test/kem/printparams.c b/test/kem/printparams.c new file mode 100644 index 00000000..efdaf5a0 --- /dev/null +++ b/test/kem/printparams.c @@ -0,0 +1,15 @@ +#include +#include "api.h" + +#define PASTER(x, y) x##_##y +#define EVALUATOR(x, y) PASTER(x, y) +#define NAMESPACE(fun) EVALUATOR(PQCLEAN_NAMESPACE, fun) + +int main() { + printf("{\n"); + printf("\t\"CRYPTO_SECRETKEYBYTES\": %u,\n", NAMESPACE(CRYPTO_SECRETKEYBYTES)); + printf("\t\"CRYPTO_PUBLICKEYBYTES\": %u,\n", NAMESPACE(CRYPTO_PUBLICKEYBYTES)); + printf("\t\"CRYPTO_CIPHERTEXTBYTES\": %u,\n", NAMESPACE(CRYPTO_CIPHERTEXTBYTES)); + printf("\t\"CRYPTO_BYTES\": %u,\n", NAMESPACE(CRYPTO_BYTES)); + printf("\t\"CRYPTO_ALGNAME\": \"%s\"\n}\n", NAMESPACE(CRYPTO_ALGNAME)); +} diff --git a/test/kem/testvectors.c b/test/kem/testvectors.c new file mode 100644 index 00000000..fb0a6f7c --- /dev/null +++ b/test/kem/testvectors.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "api.h" +#include "randombytes.h" + +#define NTESTS 5 + +static void printbytes(const uint8_t *x, size_t xlen) { + size_t i; + for (i = 0; i < xlen; i++) { + printf("%02x", x[i]); + } + printf("\n"); +} + +// 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_kem_keypair NAMESPACE(crypto_kem_keypair) +#define crypto_kem_enc NAMESPACE(crypto_kem_enc) +#define crypto_kem_dec NAMESPACE(crypto_kem_dec) + +int main(void) { + uint8_t key_a[CRYPTO_BYTES], key_b[CRYPTO_BYTES]; + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sendb[CRYPTO_CIPHERTEXTBYTES]; + uint8_t sk_a[CRYPTO_SECRETKEYBYTES]; + int i, j; + for (i = 0; i < NTESTS; i++) { + // Key-pair generation + crypto_kem_keypair(pk, sk_a); + + printbytes(pk, CRYPTO_PUBLICKEYBYTES); + printbytes(sk_a, CRYPTO_SECRETKEYBYTES); + + // Encapsulation + crypto_kem_enc(sendb, key_b, pk); + + printbytes(sendb, CRYPTO_CIPHERTEXTBYTES); + printbytes(key_b, CRYPTO_BYTES); + + // Decapsulation + crypto_kem_dec(key_a, sendb, sk_a); + printbytes(key_a, CRYPTO_BYTES); + + for (j = 0; j < CRYPTO_BYTES; j++) { + if (key_a[j] != key_b[j]) { + printf("ERROR\n"); + return -1; + } + } + } + return 0; +} diff --git a/test/sign/functest.c b/test/sign/functest.c new file mode 100644 index 00000000..aae36d90 --- /dev/null +++ b/test/sign/functest.c @@ -0,0 +1,289 @@ +#include "api.h" +#include "randombytes.h" +#include +#include +#include +#include +#include + +#ifndef NTESTS +#define NTESTS 5 +#endif + +#define MLEN 1024 + +const uint8_t canary[8] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF +}; + +/* allocate a bit more for all keys and messages and + * make sure it is not touched by the implementations. + */ +static void write_canary(uint8_t *d) { + for (size_t i = 0; i < 8; i++) { + d[i] = canary[i]; + } +} + +static int check_canary(const uint8_t *d) { + for (size_t i = 0; i < 8; i++) { + if (d[i] != canary[i]) { + return -1; + } + } + return 0; +} + +/** Safe malloc */ +inline static void* malloc_s(size_t size) { + void *ptr = malloc(size); + if (ptr == NULL) { + perror("Malloc failed!"); + exit(1); + } + return ptr; +} + +// 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_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES) +#define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES) +#define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES) +#define CRYPTO_ALGNAME NAMESPACE(CRYPTO_ALGNAME) + +#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair) +#define crypto_sign NAMESPACE(crypto_sign) +#define crypto_sign_open NAMESPACE(crypto_sign_open) +#define crypto_sign_signature NAMESPACE(crypto_sign_signature) +#define crypto_sign_verify NAMESPACE(crypto_sign_verify) + +#define RETURNS_ZERO(f) \ + if ((f) != 0) { \ + puts("(f) returned non-zero returncode"); \ + res = 1; \ + goto end; \ + } + +// https://stackoverflow.com/a/55243651/248065 +#define MY_TRUTHY_VALUE_X 1 +#define CAT(x,y) CAT_(x,y) +#define CAT_(x,y) x##y +#define HAS_NAMESPACE(x) CAT(CAT(MY_TRUTHY_VALUE_,CAT(PQCLEAN_NAMESPACE,CAT(_,x))),X) + +#if !HAS_NAMESPACE(API_H) +#error "namespace not properly defined for header guard" +#endif + + +static int test_sign(void) { + /* + * This is most likely going to be aligned by the compiler. + * 16 extra bytes for canary + * 1 extra byte for unalignment + */ + uint8_t *pk_aligned = malloc_s(CRYPTO_PUBLICKEYBYTES + 16 + 1); + uint8_t *sk_aligned = malloc_s(CRYPTO_SECRETKEYBYTES + 16 + 1); + uint8_t *sm_aligned = malloc_s(MLEN + CRYPTO_BYTES + 16 + 1); + uint8_t *m_aligned = malloc_s(MLEN + 16 + 1); + + /* + * Make sure all pointers are odd. + * This ensures that the implementation does not assume anything about the + * data alignment. For example this would catch if an implementation + * directly uses these pointers to load into vector registers using movdqa. + */ + uint8_t *pk = (uint8_t *) ((uintptr_t) pk_aligned|(uintptr_t) 1); + uint8_t *sk = (uint8_t *) ((uintptr_t) sk_aligned|(uintptr_t) 1); + uint8_t *sm = (uint8_t *) ((uintptr_t) sm_aligned|(uintptr_t) 1); + uint8_t *m = (uint8_t *) ((uintptr_t) m_aligned|(uintptr_t) 1); + + size_t mlen; + size_t smlen; + int returncode; + int res = 0; + + int i; + /* + * Write 8 byte canary before and after the actual memory regions. + * This is used to validate that the implementation does not assume + * anything about the placement of data in memory + * (e.g., assuming that the pk is always behind the sk) + */ + write_canary(pk); + write_canary(pk + CRYPTO_PUBLICKEYBYTES + 8); + write_canary(sk); + write_canary(sk + CRYPTO_SECRETKEYBYTES + 8); + write_canary(sm); + write_canary(sm + MLEN + CRYPTO_BYTES + 8); + write_canary(m); + write_canary(m + MLEN + 8); + + for (i = 0; i < NTESTS; i++) { + RETURNS_ZERO(crypto_sign_keypair(pk + 8, sk + 8)); + + randombytes(m + 8, MLEN); + RETURNS_ZERO(crypto_sign(sm + 8, &smlen, m + 8, MLEN, sk + 8)); + + // By relying on m == sm we prevent having to allocate CRYPTO_BYTES + // twice + if ((returncode = + crypto_sign_open(sm + 8, &mlen, sm + 8, smlen, pk + 8)) != 0) { + fprintf(stderr, "ERROR Signature did not verify correctly!\n"); + if (returncode > 0) { + fprintf(stderr, "ERROR return code should be < 0 on failure"); + } + res = 1; + goto end; + } + // Validate that the implementation did not touch the canary + if (check_canary(pk) || check_canary(pk + CRYPTO_PUBLICKEYBYTES + 8) || + check_canary(sk) || check_canary(sk + CRYPTO_SECRETKEYBYTES + 8) || + check_canary(sm) || check_canary(sm + MLEN + CRYPTO_BYTES + 8) || + check_canary(m) || check_canary(m + MLEN + 8)) { + fprintf(stderr, "ERROR canary overwritten\n"); + res = 1; + goto end; + } + } +end: + free(pk_aligned); + free(sk_aligned); + free(sm_aligned); + free(m_aligned); + + return res; +} + +static int test_sign_detached(void) { + /* + * This is most likely going to be aligned by the compiler. + * 16 extra bytes for canary + * 1 extra byte for unalignment + */ + uint8_t *pk_aligned = malloc_s(CRYPTO_PUBLICKEYBYTES + 16 + 1); + uint8_t *sk_aligned = malloc_s(CRYPTO_SECRETKEYBYTES + 16 + 1); + uint8_t *sig_aligned = malloc_s(CRYPTO_BYTES + 16 + 1); + uint8_t *m_aligned = malloc_s(MLEN + 16 + 1); + + /* + * Make sure all pointers are odd. + * This ensures that the implementation does not assume anything about the + * data alignment. For example this would catch if an implementation + * directly uses these pointers to load into vector registers using movdqa. + */ + uint8_t *pk = (uint8_t *) ((uintptr_t) pk_aligned|(uintptr_t) 1); + uint8_t *sk = (uint8_t *) ((uintptr_t) sk_aligned|(uintptr_t) 1); + uint8_t *sig = (uint8_t *) ((uintptr_t) sig_aligned|(uintptr_t) 1); + uint8_t *m = (uint8_t *) ((uintptr_t) m_aligned|(uintptr_t) 1); + + size_t siglen; + int returncode; + int res = 0; + + int i; + /* + * Write 8 byte canary before and after the actual memory regions. + * This is used to validate that the implementation does not assume + * anything about the placement of data in memory + * (e.g., assuming that the pk is always behind the sk) + */ + write_canary(pk); + write_canary(pk + CRYPTO_PUBLICKEYBYTES + 8); + write_canary(sk); + write_canary(sk + CRYPTO_SECRETKEYBYTES + 8); + write_canary(sig); + write_canary(sig + CRYPTO_BYTES + 8); + write_canary(m); + write_canary(m + MLEN + 8); + + for (i = 0; i < NTESTS; i++) { + RETURNS_ZERO(crypto_sign_keypair(pk + 8, sk + 8)); + + randombytes(m + 8, MLEN); + RETURNS_ZERO(crypto_sign_signature(sig + 8, &siglen, m + 8, MLEN, sk + 8)); + + if ((returncode = + crypto_sign_verify(sig + 8, siglen, m + 8, MLEN, pk + 8)) != 0) { + fprintf(stderr, "ERROR Signature did not verify correctly!\n"); + if (returncode > 0) { + fprintf(stderr, "ERROR return code should be < 0 on failure"); + } + res = 1; + goto end; + } + // Validate that the implementation did not touch the canary + if (check_canary(pk) || check_canary(pk + CRYPTO_PUBLICKEYBYTES + 8) || + check_canary(sk) || check_canary(sk + CRYPTO_SECRETKEYBYTES + 8) || + check_canary(sig) || check_canary(sig + CRYPTO_BYTES + 8) || + check_canary(m) || check_canary(m + MLEN + 8)) { + fprintf(stderr, "ERROR canary overwritten\n"); + res = 1; + goto end; + } + } + +end: + free(pk_aligned); + free(sk_aligned); + free(sig_aligned); + free(m_aligned); + + return res; +} + +static int test_wrong_pk(void) { + uint8_t *pk = malloc_s(CRYPTO_PUBLICKEYBYTES); + uint8_t *pk2 = malloc_s(CRYPTO_PUBLICKEYBYTES); + uint8_t *sk = malloc_s(CRYPTO_SECRETKEYBYTES); + uint8_t *sm = malloc_s(MLEN + CRYPTO_BYTES); + uint8_t *m = malloc_s(MLEN); + + size_t mlen; + size_t smlen; + + int returncode, res = 0; + + int i; + + for (i = 0; i < NTESTS; i++) { + RETURNS_ZERO(crypto_sign_keypair(pk2, sk)); + + RETURNS_ZERO(crypto_sign_keypair(pk, sk)); + + randombytes(m, MLEN); + RETURNS_ZERO(crypto_sign(sm, &smlen, m, MLEN, sk)); + + // By relying on m == sm we prevent having to allocate CRYPTO_BYTES + // twice + returncode = crypto_sign_open(sm, &mlen, sm, smlen, pk2); + if (!returncode) { + fprintf(stderr, "ERROR Signature did verify correctly under wrong public key!\n"); + if (returncode > 0) { + fprintf(stderr, "ERROR return code should be < 0"); + } + res = 1; + goto end; + } + } +end: + free(pk); + free(pk2); + free(sk); + free(sm); + free(m); + return res; +} + +int main(void) { + // check if CRYPTO_ALGNAME is printable + puts(CRYPTO_ALGNAME); + int result = 0; + result += test_sign(); + result += test_sign_detached(); + result += test_wrong_pk(); + + return result; +} diff --git a/test/sign/nistkat.c b/test/sign/nistkat.c new file mode 100644 index 00000000..267b072f --- /dev/null +++ b/test/sign/nistkat.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include + +#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_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES) +#define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES) +#define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES) +#define CRYPTO_ALGNAME NAMESPACE(CRYPTO_ALGNAME) + +#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair) +#define crypto_sign NAMESPACE(crypto_sign) +#define crypto_sign_open NAMESPACE(crypto_sign_open) + +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]; + size_t mlen = 33; + size_t smlen, mlen1; + uint8_t m[33]; + uint8_t sm[33 + CRYPTO_BYTES]; + int rc; + + for (uint8_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); + + fprintf(fh, "mlen = 33\n"); + + randombytes(m, mlen); + fprintBstr(fh, "msg = ", m, mlen); + + nist_kat_init(seed, NULL, 256); + + rc = crypto_sign_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_sign(sm, &smlen, m, mlen, secret_key); + if (rc != 0) { + fprintf(stderr, "[kat_kem] %s ERROR: crypto_sign failed!\n", CRYPTO_ALGNAME); + return -2; + } + fprintf(fh, "smlen = %zu\n", smlen); + fprintBstr(fh, "sm = ", sm, smlen); + + rc = crypto_sign_open(sm, &mlen1, sm, smlen, public_key); + if (rc != 0) { + fprintf(stderr, "[kat_kem] %s ERROR: crypto_sign_open failed!\n", CRYPTO_ALGNAME); + return -3; + } + + if ( mlen != mlen1 ) { + printf("crypto_sign_open returned bad 'mlen': got <%zu>, expected <%zu>\n", mlen1, mlen); + return -4; + } + if (memcmp(m, sm, mlen)) { + printf("crypto_sign_open returned bad 'm' value\n"); + return -5; + } + return 0; + +} diff --git a/test/sign/printparams.c b/test/sign/printparams.c new file mode 100644 index 00000000..eb218c87 --- /dev/null +++ b/test/sign/printparams.c @@ -0,0 +1,14 @@ +#include +#include "api.h" + +#define PASTER(x, y) x##_##y +#define EVALUATOR(x, y) PASTER(x, y) +#define NAMESPACE(fun) EVALUATOR(PQCLEAN_NAMESPACE, fun) + +int main() { + printf("{\n"); + printf("\t\"CRYPTO_SECRETKEYBYTES\": %u,\n", NAMESPACE(CRYPTO_SECRETKEYBYTES)); + printf("\t\"CRYPTO_PUBLICKEYBYTES\": %u,\n", NAMESPACE(CRYPTO_PUBLICKEYBYTES)); + printf("\t\"CRYPTO_BYTES\": %u,\n", NAMESPACE(CRYPTO_BYTES)); + printf("\t\"CRYPTO_ALGNAME\": \"%s\"\n}\n", NAMESPACE(CRYPTO_ALGNAME)); +} diff --git a/test/sign/testvectors.c b/test/sign/testvectors.c new file mode 100644 index 00000000..fba44b41 --- /dev/null +++ b/test/sign/testvectors.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +#include "api.h" +#include "randombytes.h" + +#define MAXMLEN 2048 + +static void printbytes(const uint8_t *x, size_t xlen) { + size_t i; + for (i = 0; i < xlen; i++) { + printf("%02x", x[i]); + } + printf("\n"); +} + +// 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_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES) +#define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES) +#define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES) + +#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair) +#define crypto_sign NAMESPACE(crypto_sign) +#define crypto_sign_open NAMESPACE(crypto_sign_open) +#define crypto_sign_signature NAMESPACE(crypto_sign_signature) +#define crypto_sign_verify NAMESPACE(crypto_sign_verify) + +int main(void) { + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + + uint8_t mi[MAXMLEN]; + uint8_t sm[MAXMLEN + CRYPTO_BYTES]; + uint8_t sig[CRYPTO_BYTES]; + + size_t smlen; + size_t siglen; + size_t mlen; + + int r; + size_t i, k; + + /* i = 0, 1, 4, 16, 64, 256, 1024 */ + for (i = 0; i < MAXMLEN; i = (i == 0) ? i + 1 : i << 2) { + randombytes(mi, i); + + crypto_sign_keypair(pk, sk); + + printbytes(pk, CRYPTO_PUBLICKEYBYTES); + printbytes(sk, CRYPTO_SECRETKEYBYTES); + + crypto_sign(sm, &smlen, mi, i, sk); + crypto_sign_signature(sig, &siglen, mi, i, sk); + + printbytes(sm, smlen); + printbytes(sig, siglen); + + // By relying on m == sm we prevent having to allocate CRYPTO_BYTES + // twice + r = crypto_sign_open(sm, &mlen, sm, smlen, pk); + r |= crypto_sign_verify(sig, siglen, mi, i, pk); + + if (r) { + printf("ERROR: signature verification failed\n"); + return -1; + } + for (k = 0; k < i; k++) { + if (sm[k] != mi[k]) { + printf("ERROR: message recovery failed\n"); + return -1; + } + } + } + return 0; +}