From cd5f1f0af31acf74b486c3f6ef8034568048c835 Mon Sep 17 00:00:00 2001 From: Loup Vaillant Date: Mon, 5 Jun 2017 23:02:10 +0200 Subject: [PATCH] Modified tests to be Frama-C friendly (no input) --- makefile | 27 ++- tests/test.c | 288 ++++++++--------------------- tests/vector_to_header.c | 67 +++++++ tests/vectors/test_diff | 26 --- tests/vectors/test_equal | 17 -- tests/vectors/{sha512 => v_sha512} | 0 6 files changed, 163 insertions(+), 262 deletions(-) create mode 100644 tests/vector_to_header.c delete mode 100644 tests/vectors/test_diff delete mode 100644 tests/vectors/test_equal rename tests/vectors/{sha512 => v_sha512} (100%) diff --git a/makefile b/makefile index 99929a8..4eb1c23 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,7 @@ -CC=gcc -CFLAGS= -I src -O2 -Wall -Wextra -std=c11 -pedantic +CC=clang +CFLAGS= -I src -O2 -Wall -Wextra -std=c11 -pedantic -g + +#-fno-stack-protector .PHONY: all clean directories # disable implicit rules @@ -13,9 +15,28 @@ clean: rm -f test sodium donna # Test suite based on test vectors -test: tests/test.c bin/monocypher.o bin/sha512.o +TEST_DEPS=tests/test.c bin/monocypher.o bin/sha512.o +test: $(TEST_DEPS) \ + bin/argon2i.h \ + bin/blake2b.h \ + bin/blake2b_easy.h \ + bin/chacha20.h \ + bin/ed25519_key.h \ + bin/ed25519_sign.h \ + bin/h_chacha20.h \ + bin/key_exchange.h \ + bin/poly1305.h \ + bin/v_sha512.h \ + bin/x25519.h \ + bin/x_chacha20.h + $(CC) $(CFLAGS) -I bin -o $@ $(TEST_DEPS) + +bin/vector: tests/vector_to_header.c $(CC) $(CFLAGS) -o $@ $^ +bin/%.h: tests/vectors/% bin/vector + bin/vector $$(basename $<) <$< >$@ + # Test suite based on comparison with libsodium C_SODIUM_FLAGS=$$(pkg-config --cflags libsodium) LD_SODIUM_FLAGS=$$(pkg-config --libs libsodium) diff --git a/tests/test.c b/tests/test.c index b28cb3f..163fd96 100644 --- a/tests/test.c +++ b/tests/test.c @@ -4,6 +4,19 @@ #include "monocypher.h" #include "sha512.h" +#include "chacha20.h" +#include "argon2i.h" +#include "blake2b.h" +#include "blake2b_easy.h" +#include "ed25519_key.h" +#include "ed25519_sign.h" +#include "h_chacha20.h" +#include "key_exchange.h" +#include "poly1305.h" +#include "v_sha512.h" +#include "x25519.h" +#include "x_chacha20.h" + #define FOR(i, start, end) for (size_t (i) = (start); (i) < (end); (i)++) #define sv static void typedef int8_t i8; @@ -13,9 +26,9 @@ typedef int32_t i32; typedef int64_t i64; typedef uint64_t u64; -///////////////////////// -/// General utilities /// -///////////////////////// +///////////////// +/// Utilities /// +///////////////// static void* alloc(size_t size) { @@ -27,203 +40,47 @@ static void* alloc(size_t size) return buf; } -static int is_digit(int c) -{ - return (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'f') - || (c >= 'A' && c <= 'F'); -} - -static unsigned uint_of_char(unsigned char c) -{ - if (c >= '0' && c <= '9') { return c - '0'; } - if (c >= 'a' && c <= 'f') { return c - 'a' + 10; } - if (c >= 'A' && c <= 'F') { return c - 'A' + 10; } - fprintf(stderr, - "'%c' (%d): Not a hexadecimal char" - " (note: they go in pairs)\n", c, c); - exit(1); -} - -//////////////////////////////// -/// File streams with lookup /// -//////////////////////////////// -typedef struct { FILE *file; int head; int valid; } stream; - -sv stream_open(stream *s, const char *filename) -{ - s->file = fopen(filename, "r"); - s->valid = 0; - if (s->file == NULL) { - fprintf(stderr, "Could not open file %s", filename); - exit(1); - } -} -sv stream_close(stream *s) { fclose(s->file); } - -static int stream_peek(stream *s) -{ - if (!s->valid) { - s-> valid = 1; - s-> head = getc(s->file); - } - return s->head; -} - -static int stream_get(stream *s) -{ - char c = stream_peek(s); - s->valid = 0; - return c; -} - -sv stream_drop(stream *s) -{ - stream_get(s); -} - -//////////////////////// -/// Vector of octets /// -//////////////////////// typedef struct { u8 *buf; - size_t buf_size; size_t size; } vector; -static vector vec_new(size_t buf_size) -{ - vector v; - v.buf = (u8*)alloc(buf_size); - v.buf_size = buf_size; - v.size = 0; - return v; -} - -static vector vec_uninitialized(size_t size) -{ - vector v = vec_new(size); - v.size = size; - return v; -} - -sv vec_del(vector *v) -{ - free(v->buf); -} - -sv vec_push_back(vector *v, u8 e) -{ - if (v->buf_size == v->size) { - // double initial buffer size (and then some) - size_t new_buf_size = v->buf_size * 2 + 1; - u8 *new_buf = (u8*)alloc(new_buf_size); - memcpy(new_buf, v->buf, v->buf_size); - free(v->buf); - v->buf = new_buf; - v->buf_size = new_buf_size; - } - v->buf[v->size] = e; - v->size++; -} - -static int vec_cmp(const vector *u, const vector *v) -{ - if (u->size != v-> size) - return -1; - return crypto_memcmp(u->buf, v->buf, u->size); -} - -sv next_number(stream *s) -{ - while (stream_peek(s) != EOF && - stream_peek(s) != ':' && - !is_digit(stream_peek(s))) - stream_drop(s); -} - -// Read a line into a vector. -// A vector file is a list of colon terminated hex numbers. -// Ignores any character between a column and the following digit. -// The user must free the vector's memory with vec_del() -static vector read_hex_line(stream *s) -{ - vector v = vec_new(64); - next_number(s); - while (stream_peek(s) != ':') { - u8 msb = uint_of_char(stream_get(s)); - u8 lsb = uint_of_char(stream_get(s)); - vec_push_back(&v, lsb | (msb << 4)); - } - stream_drop(s); - next_number(s); - return v; -} - -///////////////////////////// -/// Test helper functions /// -///////////////////////////// - -// Pulls some test vectors, feed it to f, get a status back -// The test fails if the status is not zero -static int generic_test(int (*f)(const vector[]), - const char * filename, size_t nb_vectors) -{ - int status = 0; - vector *inputs = (vector*)alloc(nb_vectors * sizeof(vector)); - int nb_tests = 0; - stream stream; - stream_open(&stream, filename); - - while (stream_peek(&stream) != EOF) { - FOR (i, 0, nb_vectors) { inputs[i] = read_hex_line(&stream); } - status |= f(inputs); - FOR (i, 0, nb_vectors) { vec_del(inputs + i); } - nb_tests++; - } - printf("%s %3d tests: %s\n", - status != 0 ? "FAILED" : "OK", nb_tests, filename); - free(inputs); - stream_close(&stream); - return status; -} - -// Same, except f writes to a buffer. If it's different than -// some expected result, the test fails. static int test(void (*f)(const vector[], vector*), - const char *filename, size_t nb_vectors) -{ - int status = 0; - vector *inputs = (vector*)alloc(nb_vectors * sizeof(vector)); - int nb_tests = 0; - stream stream; - stream_open(&stream, filename); - - while (stream_peek(&stream) != EOF) { - FOR (i, 0, nb_vectors) { inputs[i] = read_hex_line(&stream); } - - vector expected = read_hex_line(&stream); - vector output = vec_uninitialized(expected.size); - f(inputs, &output); - status |= vec_cmp(&output, &expected); - - vec_del(&output); - vec_del(&expected); - FOR (i, 0, nb_vectors) { vec_del(inputs + i); } + const char *name, size_t nb_inputs, + size_t nb_vectors, u8 **vectors, size_t *sizes) +{ + int status = 0; + int nb_tests = 0; + size_t idx = 0; + vector in[nb_vectors]; + while (idx < nb_vectors) { + size_t out_size = sizes[idx + nb_inputs]; + vector out; + out.buf = (u8*)alloc(out_size); + out.size = out_size; + FOR (i, 0, nb_inputs) { + in[i].buf = vectors[idx+i]; + in[i].size = sizes [idx+i]; + } + f(in, &out); + vector expected; + expected.buf = vectors[idx+nb_inputs]; + expected.size = sizes [idx+nb_inputs]; + status |= out.size - expected.size; + status |= crypto_memcmp(out.buf, expected.buf, out.size); + free(out.buf); + idx += nb_inputs + 1; nb_tests++; } printf("%s %3d tests: %s\n", - status != 0 ? "FAILED" : "OK", nb_tests, filename); - free(inputs); - stream_close(&stream); + status != 0 ? "FAILED" : "OK", nb_tests, name); return status; } -/////////////////////////// -/// Test the test suite /// -/////////////////////////// -static int equal(const vector v[]) { return vec_cmp(v, v + 1); } -static int diff (const vector v[]) { return !vec_cmp(v, v + 1); } +#define TEST(name, nb_inputs) test(name, #name, nb_inputs, \ + nb_##name##_vectors, \ + name##_vectors, \ + name##_sizes) //////////////////////// /// The tests proper /// @@ -237,14 +94,14 @@ sv chacha20(const vector in[], vector *out) crypto_chacha20_stream(&ctx, out->buf, out->size); } -sv hchacha20(const vector in[], vector *out) +sv h_chacha20(const vector in[], vector *out) { const vector *key = in; const vector *input = in + 1; crypto_chacha20_H(out->buf, key->buf, input->buf); } -sv xchacha20(const vector in[], vector *out) +sv x_chacha20(const vector in[], vector *out) { const vector *key = in; const vector *nonce = in + 1; @@ -344,7 +201,7 @@ static int test_x25519() return status; } -sv sha512(const vector in[], vector *out) +sv v_sha512(const vector in[], vector *out) { crypto_sha512(out->buf, in->buf, in->size); } @@ -354,21 +211,21 @@ sv ed25519_key(const vector in[], vector *out) crypto_sign_public_key(out->buf, in->buf); } -sv ed25519_sign1(const vector in[], vector *out) +sv ed25519_sign(const vector in[], vector *out) { const vector *secret_k = in; + const vector *public_k = in + 1; const vector *msg = in + 2; - // reconsruct public key before signing - crypto_sign(out->buf, secret_k->buf, 0, msg->buf, msg->size); -} + u8 out2[64]; -sv ed25519_sign2(const vector in[], vector *out) -{ - const vector *secret_k = in; - const vector *public_k = in + 1; - const vector *msg = in + 2; - // Use cached public key to sign + // Sign with cached public key, then by reconstructing the key crypto_sign(out->buf, secret_k->buf, public_k->buf, msg->buf, msg->size); + crypto_sign(out2 , secret_k->buf, 0 , msg->buf, msg->size); + // Compare signatures (must be the same) + if (crypto_memcmp(out->buf, out2, out->size)) { + printf("FAILURE: reconstructing public key" + " yields different signature\n"); + } // test successful signature verification if (crypto_check(out->buf, public_k->buf, msg->buf, msg->size)) { @@ -433,21 +290,20 @@ static int test_aead() int main(void) { int status = 0; - status |= generic_test(equal, "tests/vectors/test_equal" , 2); - status |= generic_test(diff , "tests/vectors/test_diff" , 2); - status |= test(chacha20 , "tests/vectors/chacha20" , 2); - status |= test(hchacha20 , "tests/vectors/h_chacha20" , 2); - status |= test(xchacha20 , "tests/vectors/x_chacha20" , 2); - status |= test(blake2b , "tests/vectors/blake2b" , 2); - status |= test(blake2b_easy , "tests/vectors/blake2b_easy", 1); - status |= test(poly1305 , "tests/vectors/poly1305" , 2); - status |= test(argon2i , "tests/vectors/argon2i" , 6); - status |= test(x25519 , "tests/vectors/x25519" , 2); - status |= test(key_exchange , "tests/vectors/key_exchange", 2); - status |= test(sha512 , "tests/vectors/sha512" , 1); - status |= test(ed25519_key , "tests/vectors/ed25519_key" , 1); - status |= test(ed25519_sign1, "tests/vectors/ed25519_sign", 3); - status |= test(ed25519_sign2, "tests/vectors/ed25519_sign", 3); + /* status |= generic_test(equal, "tests/vectors/test_equal" , 2); */ + /* status |= generic_test(diff , "tests/vectors/test_diff" , 2); */ + status |= TEST(chacha20 , 2); + status |= TEST(h_chacha20 , 2); + status |= TEST(x_chacha20 , 2); + status |= TEST(blake2b , 2); + status |= TEST(blake2b_easy, 1); + status |= TEST(poly1305 , 2); + status |= TEST(argon2i , 6); + status |= TEST(x25519 , 2); + status |= TEST(key_exchange, 2); + status |= TEST(v_sha512 , 1); + status |= TEST(ed25519_key , 1); + status |= TEST(ed25519_sign, 3); status |= test_x25519(); status |= test_aead(); return status; diff --git a/tests/vector_to_header.c b/tests/vector_to_header.c new file mode 100644 index 0000000..170bd2a --- /dev/null +++ b/tests/vector_to_header.c @@ -0,0 +1,67 @@ +// Transforms a test vector file (from stdin) into a C header. + +#include +#include +#include + +static int is_digit(int c) +{ + return (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F'); +} + +int main(int argc, char** argv) +{ + if (argc != 2) { + fprintf(stderr, "Wrong use of vector transformer. Give one argument\n"); + return 1; + } + + char *prefix = argv[1]; + int c = getchar(); + int nb_vec = 0; + + printf("#include \n"); + printf("#include \n"); + while (c != EOF) { + int size = 0; + if (c == ':') { + // Empty lines can't be C arrays. + // We make them null pointers instead + printf("#define %s_%d 0\n", prefix, nb_vec); + } + else { + printf("uint8_t %s_%d[] = { ", prefix, nb_vec); + while (c != ':') { + char msb = c; c = getchar(); + char lsb = c; c = getchar(); + printf("0x%c%c, ", msb, lsb); + size ++; + } + printf("};\n"); + } + c = getchar(); + printf("#define %s_%d_size %d\n", prefix, nb_vec, size); + + // seek next line + while (!is_digit(c) && c != ':' && c != EOF) { + c = getchar(); + } + nb_vec++; + } + + printf("size_t nb_%s_vectors = %d;\n", prefix, nb_vec); + + printf("uint8_t *%s_vectors[] = { ", prefix); + for (int i = 0; i < nb_vec; i++) { + printf("%s_%d, ", prefix, i); + } + printf("};\n"); + + printf("size_t %s_sizes[] = { ", prefix); + for (int i = 0; i < nb_vec; i++) { + printf("%s_%d_size, ", prefix, i); + } + printf("};\n"); +} diff --git a/tests/vectors/test_diff b/tests/vectors/test_diff deleted file mode 100644 index fb61114..0000000 --- a/tests/vectors/test_diff +++ /dev/null @@ -1,26 +0,0 @@ -: -00: - -00: -: - -00: -01: - -01: -00: - -0000: -000000: - -000000: -0000: - -0012: -0011: - -0011: -0211: - -001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788001122334455667388: -001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788: diff --git a/tests/vectors/test_equal b/tests/vectors/test_equal deleted file mode 100644 index 99fa4a3..0000000 --- a/tests/vectors/test_equal +++ /dev/null @@ -1,17 +0,0 @@ -: -: - -00: -00: - -0000: -0000: - -0011: -0011: - -001122: -001122: - -001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788: -001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788001122334455667788: diff --git a/tests/vectors/sha512 b/tests/vectors/v_sha512 similarity index 100% rename from tests/vectors/sha512 rename to tests/vectors/v_sha512 -- 2.47.3