reorg
This commit is contained in:
parent
188312f23c
commit
5f380fb74a
263
test/kem/functest.c
Normal file
263
test/kem/functest.c
Normal file
@ -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;
|
||||
}
|
95
test/kem/nistkat.c
Normal file
95
test/kem/nistkat.c
Normal file
@ -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;
|
||||
|
||||
}
|
15
test/kem/printparams.c
Normal file
15
test/kem/printparams.c
Normal file
@ -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));
|
||||
}
|
64
test/kem/testvectors.c
Normal file
64
test/kem/testvectors.c
Normal file
@ -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;
|
||||
}
|
289
test/sign/functest.c
Normal file
289
test/sign/functest.c
Normal file
@ -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;
|
||||
}
|
102
test/sign/nistkat.c
Normal file
102
test/sign/nistkat.c
Normal file
@ -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;
|
||||
|
||||
}
|
14
test/sign/printparams.c
Normal file
14
test/sign/printparams.c
Normal file
@ -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));
|
||||
}
|
81
test/sign/testvectors.c
Normal file
81
test/sign/testvectors.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user