From: Loup Vaillant Date: Wed, 22 Feb 2017 13:02:11 +0000 (+0100) Subject: reworked API, more tests X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=b7826a99ef11b6a65db251b872bf413dcb9c87f5;p=Monocypher.git reworked API, more tests --- diff --git a/monocypher.c b/monocypher.c index 0d1fdf6..722ad0a 100644 --- a/monocypher.c +++ b/monocypher.c @@ -80,7 +80,14 @@ int crypto_memcmp(const u8 *p1, const u8 *p2, size_t n) { unsigned diff = 0; FOR (i, 0, n) { diff |= (p1[i] ^ p2[i]); } - return diff; + return (1 & ((diff - 1) >> 8)) - 1; +} + +int crypto_zerocmp(const u8 *p, size_t n) +{ + unsigned diff = 0; + FOR (i, 0, n) { diff |= p[i]; } + return (1 & ((diff - 1) >> 8)) - 1; } ///////////////// @@ -159,8 +166,8 @@ void crypto_chacha20_Xinit(crypto_chacha_ctx *ctx, } void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, - const u8 *plain_text, u8 *cipher_text, + const u8 *plain_text, size_t message_size) { FOR (i, 0, message_size) { @@ -190,7 +197,7 @@ void crypto_chacha20_stream(crypto_chacha_ctx *ctx, u8 *cipher_text, size_t message_size) { - crypto_chacha20_encrypt(ctx, 0, cipher_text, message_size); + crypto_chacha20_encrypt(ctx, cipher_text, 0, message_size); } @@ -676,14 +683,12 @@ static u32 gidx_next(gidx_ctx *ctx) } // Main algorithm -void crypto_argon2i(u8 *tag, u32 tag_size, - const u8 *password, u32 password_size, - const u8 *salt, u32 salt_size, - const u8 *key, u32 key_size, - const u8 *ad, u32 ad_size, - void *work_area, - u32 nb_blocks, - u32 nb_iterations) +void crypto_argon2i(u8 *tag, u32 tag_size, + void *work_area, u32 nb_blocks, u32 nb_iterations, + const u8 *password, u32 password_size, + const u8 *salt, u32 salt_size, + const u8 *key, u32 key_size, + const u8 *ad, u32 ad_size) { // work area seen as blocks (must be suitably aligned) block *blocks = (block*)work_area; @@ -938,10 +943,9 @@ static int fe_isnegative(const fe f) static int fe_isnonzero(const fe f) { - static const u8 zero[32] = {0}; u8 s[32]; fe_tobytes(s, f); - return crypto_memcmp(s, zero, 32); + return crypto_zerocmp(s, 32); } /////////////// @@ -955,9 +959,9 @@ sv trim_scalar(u8 s[32]) s[31] |= 64; } -void crypto_x25519(u8 shared_secret [32], - const u8 your_secret_key [32], - const u8 their_public_key[32]) +int crypto_x25519(u8 shared_secret [32], + const u8 your_secret_key [32], + const u8 their_public_key[32]) { // computes the scalar product fe x1, x2, z2, x3, z3; @@ -999,6 +1003,10 @@ void crypto_x25519(u8 shared_secret [32], fe_invert(z2, z2); fe_mul(x2, x2, z2); fe_tobytes(shared_secret, x2); + + // Returns -1 if the input is all zero + // (happens with some malicious public keys) + return -1 - crypto_zerocmp(shared_secret, 32); } void crypto_x25519_public_key(u8 public_key[32], @@ -1280,14 +1288,15 @@ int crypto_check(const u8 signature[64], //////////////////// /// Key exchange /// //////////////////// -void crypto_key_exchange(u8 shared_key[32], - const u8 your_secret_key [32], - const u8 their_public_key[32]) +int crypto_key_exchange(u8 shared_key[32], + const u8 your_secret_key [32], + const u8 their_public_key[32]) { static const u8 zero[16] = {0}; u8 shared_secret[32]; - crypto_x25519(shared_secret, your_secret_key, their_public_key); + int status = crypto_x25519(shared_secret, your_secret_key, their_public_key); crypto_chacha20_H(shared_key, shared_secret, zero); + return status; } //////////////////////////////// @@ -1315,7 +1324,7 @@ void crypto_aead_lock(u8 mac[16], crypto_chacha_ctx e_ctx; crypto_chacha20_Xinit (&e_ctx, key, nonce); crypto_chacha20_stream (&e_ctx, auth_key, 32); - crypto_chacha20_encrypt(&e_ctx, plaintext, ciphertext, text_size); + crypto_chacha20_encrypt(&e_ctx, ciphertext, plaintext, text_size); authenticate2(mac, auth_key, ad, ad_size, ciphertext, text_size); } @@ -1332,7 +1341,7 @@ int crypto_aead_unlock(u8 *plaintext, crypto_chacha20_stream(&e_ctx, auth_key, 32); authenticate2(real_mac, auth_key, ad, ad_size, ciphertext, text_size); if (crypto_memcmp(real_mac, mac, 16)) return -1; // reject forgeries - crypto_chacha20_encrypt(&e_ctx, ciphertext, plaintext, text_size); + crypto_chacha20_encrypt(&e_ctx, plaintext, ciphertext, text_size); return 0; } diff --git a/monocypher.h b/monocypher.h index 1f8e6ed..2bb78ff 100644 --- a/monocypher.h +++ b/monocypher.h @@ -5,9 +5,13 @@ #include // Constant time equality verification -// returns 0 if it matches, something else otherwise. +// returns 0 if it matches, -1 otherwise. int crypto_memcmp(const uint8_t *p1, const uint8_t *p2, size_t n); +// constant time zero comparison. +// returns 0 if the input is all zero, -1 otherwise. +int crypto_zerocmp(const uint8_t *p, size_t n); + //////////////// /// Chacha20 /// //////////////// @@ -30,8 +34,8 @@ void crypto_chacha20_Xinit(crypto_chacha_ctx *ctx, const uint8_t nonce[24]); void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, - const uint8_t *plain_text, uint8_t *cipher_text, + const uint8_t *plain_text, size_t message_size); void crypto_chacha20_stream(crypto_chacha_ctx *ctx, @@ -91,20 +95,19 @@ void crypto_blake2b(uint8_t out[64], const uint8_t *in, size_t inlen); /// Argon2 i /// //////////////// void crypto_argon2i(uint8_t *tag, uint32_t tag_size, // >= 4 + void *work_area, uint32_t nb_blocks, // >= 8 + uint32_t nb_iterations, const uint8_t *password, uint32_t password_size, const uint8_t *salt, uint32_t salt_size, // >= 8 const uint8_t *key, uint32_t key_size, - const uint8_t *ad, uint32_t ad_size, - void *work_area, - uint32_t nb_blocks, // >= 8 - uint32_t nb_iterations); + const uint8_t *ad, uint32_t ad_size); /////////////// /// X-25519 /// /////////////// -void crypto_x25519(uint8_t shared_secret [32], - const uint8_t your_secret_key [32], - const uint8_t their_public_key[32]); +int crypto_x25519(uint8_t shared_secret [32], + const uint8_t your_secret_key [32], + const uint8_t their_public_key[32]); void crypto_x25519_public_key(uint8_t public_key[32], const uint8_t secret_key[32]); @@ -128,9 +131,9 @@ int crypto_check(const uint8_t signature[64], //////////////////// /// Key exchange /// //////////////////// -void crypto_key_exchange(uint8_t shared_key [32], - const uint8_t your_secret_key [32], - const uint8_t their_public_key[32]); +int crypto_key_exchange(uint8_t shared_key [32], + const uint8_t your_secret_key [32], + const uint8_t their_public_key[32]); //////////////////////////////// /// Authenticated encryption /// diff --git a/test.c b/test.c index b7e5437..357d492 100644 --- a/test.c +++ b/test.c @@ -86,7 +86,7 @@ sv stream_drop(stream *s) /// Vector of octets /// //////////////////////// typedef struct { - uint8_t *buf; + u8 *buf; size_t buf_size; size_t size; } vector; @@ -94,7 +94,7 @@ typedef struct { static vector vec_new(size_t buf_size) { vector v; - v.buf = (uint8_t*)alloc(buf_size); + v.buf = (u8*)alloc(buf_size); v.buf_size = buf_size; v.size = 0; return v; @@ -112,12 +112,12 @@ sv vec_del(vector *v) free(v->buf); } -sv vec_push_back(vector *v, uint8_t e) +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; - uint8_t *new_buf = (uint8_t*)alloc(new_buf_size); + u8 *new_buf = (u8*)alloc(new_buf_size); memcpy(new_buf, v->buf, v->buf_size); free(v->buf); v->buf = new_buf; @@ -151,8 +151,8 @@ static vector read_hex_line(stream *s) vector v = vec_new(64); next_number(s); while (stream_peek(s) != ':') { - uint8_t msb = uint_of_char(stream_get(s)); - uint8_t lsb = uint_of_char(stream_get(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); @@ -283,14 +283,12 @@ sv argon2i(const vector in[], vector *out) const vector *key = in + 4; const vector *ad = in + 5; void *work_area = alloc(nb_blocks->buf[0] * 1024); - crypto_argon2i(out ->buf, out ->size, - password->buf, password->size, - salt ->buf, salt ->size, - key ->buf, key ->size, - ad ->buf, ad ->size, - work_area, - nb_blocks ->buf[0], - nb_iterations->buf[0]); + crypto_argon2i(out ->buf, out ->size, + work_area , nb_blocks->buf[0], nb_iterations->buf[0], + password->buf, password ->size, + salt ->buf, salt ->size, + key ->buf, key ->size, + ad ->buf, ad ->size); free(work_area); } @@ -298,12 +296,15 @@ sv x25519(const vector in[], vector *out) { const vector *scalar = in; const vector *point = in + 1; - crypto_x25519(out->buf, scalar->buf, point->buf); + int report = crypto_x25519(out->buf, scalar->buf, point->buf); + int not_zero = crypto_zerocmp(out->buf, out->size); + if ( not_zero && report) printf("FAILURE: x25519 false all_zero report\n"); + if (!not_zero && !report) printf("FAILURE: x25519 failed to report zero\n"); } -sv iterate_x25519(uint8_t k[32], uint8_t u[32]) +sv iterate_x25519(u8 k[32], u8 u[32]) { - uint8_t tmp[32]; + u8 tmp[32]; crypto_x25519(tmp , k, u); memcpy(u, k , 32); memcpy(k, tmp, 32); @@ -311,31 +312,31 @@ sv iterate_x25519(uint8_t k[32], uint8_t u[32]) static int test_x25519() { - uint8_t _1 [32] = {0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, - 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, - 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, - 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79}; - uint8_t k[32] = {9}; - uint8_t u[32] = {9}; + u8 _1 [32] = {0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, + 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, + 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, + 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79}; + u8 k[32] = {9}; + u8 u[32] = {9}; crypto_x25519_public_key(k, u); int status = crypto_memcmp(k, _1, 32); printf("%s: x25519 1\n", status != 0 ? "FAILED" : "OK"); - uint8_t _1k [32] = {0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, - 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, - 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, - 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51}; + u8 _1k [32] = {0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, + 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, + 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, + 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51}; FOR (i, 1, 1000) { iterate_x25519(k, u); } status |= crypto_memcmp(k, _1k, 32); printf("%s: x25519 1K\n", status != 0 ? "FAILED" : "OK"); // too long; didn't run - //uint8_t _100k[32] = {0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, - // 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, - // 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, - // 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24}; - // FOR (i, 1000, 1000000) { iterate_x25519(k, u); } + //u8 _100k[32] = {0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, + // 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, + // 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, + // 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24}; + //FOR (i, 1000, 1000000) { iterate_x25519(k, u); } //status |= crypto_memcmp(k, _100k, 32); //printf("%s: x25519 1M\n", status != 0 ? "FAILED" : "OK"); return status; @@ -372,8 +373,8 @@ sv ed25519_sign2(const vector in[], vector *out) printf("FAILURE: signature check failed to recognise signature\n"); } // test forgery rejections - uint8_t fake_signature1[64]; - uint8_t fake_signature2[64]; + u8 fake_signature1[64]; + u8 fake_signature2[64]; FOR (i, 0, 64) { fake_signature1[i] = out->buf[i] + 1; fake_signature2[i] = out->buf[i] + 1; @@ -389,33 +390,40 @@ sv key_exchange(const vector in[], vector *out) const vector *secret_key = in; const vector *public_key = in + 1; crypto_key_exchange(out->buf, secret_key->buf, public_key->buf); - } static int test_aead() { - uint8_t key[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, - 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7 }; - uint8_t nonce[24] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 }; - uint8_t ad [4] = { 3, 2, 1, 0 }; - uint8_t plaintext[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; - uint8_t box[24]; - uint8_t out[8]; + u8 key[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7 }; + u8 nonce[24] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 }; + u8 ad [4] = { 3, 2, 1, 0 }; + u8 plaintext[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + u8 box[24], box2[24]; + u8 out[8]; int status = 0; - crypto_lock(box, key, nonce, plaintext, 8); // make true message - status |= crypto_unlock(out, key, nonce, box, 8+16); // accept true message - status |= crypto_memcmp(plaintext, out, 8); // roundtrip - box[0]++; // make forgery - status |= !crypto_unlock(out, key, nonce, box, 8+16); // reject forgery - printf("%s: aead\n", status != 0 ? "FAILED" : "OK"); - + // AEAD roundtrip crypto_aead_lock(box, box+16, key, nonce, ad, 4, plaintext, 8); status |= crypto_aead_unlock(out, key, nonce, box, ad, 4, box+16, 8); status |= crypto_memcmp(plaintext, out, 8); box[0]++; status |= !crypto_aead_unlock(out, key, nonce, box, ad, 4, box+16, 8); + printf("%s: aead (detached)\n", status != 0 ? "FAILED" : "OK"); + + // Authenticated roundtrip (easy interface) + crypto_lock(box, key, nonce, plaintext, 8); // make true message + status |= crypto_unlock(out, key, nonce, box, 8+16); // accept true message + status |= crypto_memcmp(plaintext, out, 8); // roundtrip + box[0]++; // make forgery + status |= !crypto_unlock(out, key, nonce, box, 8+16); // reject forgery printf("%s: aead (simplified)\n", status != 0 ? "FAILED" : "OK"); + box[0]--; // undo forgery + + // Same result for both interfaces + crypto_aead_lock(box2, box2 + 16, key, nonce, 0, 0, plaintext, 8); + status |= crypto_memcmp(box, box2, 24); + printf("%s: aead (compared)\n", status != 0 ? "FAILED" : "OK"); return status; } diff --git a/vectors_x25519 b/vectors_x25519 index 36ab64d..68480fa 100644 --- a/vectors_x25519 +++ b/vectors_x25519 @@ -17,3 +17,31 @@ de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f: 0900000000000000000000000000000000000000000000000000000000000000: 0900000000000000000000000000000000000000000000000000000000000000: 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +0000000000000000000000000000000000000000000000000000000000000000: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +0100000000000000000000000000000000000000000000000000000000000000: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f: +0000000000000000000000000000000000000000000000000000000000000000: + +5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb: +eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f: +0000000000000000000000000000000000000000000000000000000000000000: