@@ -0,0 +1,263 @@ | |||
#include "api.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#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; | |||
} |
@@ -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 (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; | |||
} |
@@ -0,0 +1,15 @@ | |||
#include <stdio.h> | |||
#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)); | |||
} |
@@ -0,0 +1,64 @@ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#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; | |||
} |
@@ -0,0 +1,289 @@ | |||
#include "api.h" | |||
#include "randombytes.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#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; | |||
} |
@@ -0,0 +1,102 @@ | |||
#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_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; | |||
} |
@@ -0,0 +1,14 @@ | |||
#include <stdio.h> | |||
#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)); | |||
} |
@@ -0,0 +1,81 @@ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#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; | |||
} |