From d2cb03d6396027fbfde6f72bc2314512fd7b3805 Mon Sep 17 00:00:00 2001 From: Loup Vaillant Date: Fri, 30 Dec 2022 22:49:31 +0100 Subject: [PATCH] Prepare Argon2d and Argon2id support --- src/monocypher.c | 58 ++++++++++++--------------- src/monocypher.h | 12 +++--- tests/gen/{argon2i.c => argon2.c} | 34 ++++++++++------ tests/gen/makefile | 4 +- tests/gen/vectors/{argon2i => argon2} | 6 ++- tests/speed/speed.c | 14 +++++-- tests/test.c | 49 +++++++++++----------- tests/tis-ci-vectors.h | 10 +++-- tests/tis-ci.c | 16 ++++---- 9 files changed, 109 insertions(+), 94 deletions(-) rename tests/gen/{argon2i.c => argon2.c} (77%) rename tests/gen/vectors/{argon2i => argon2} (93%) diff --git a/src/monocypher.c b/src/monocypher.c index 11b817e..d902328 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -637,9 +637,9 @@ void crypto_blake2b(u8 hash[64], const u8 *message, size_t message_size) crypto_blake2b_general(hash, 64, 0, 0, message, message_size); } -//////////////// -/// Argon2 i /// -//////////////// +////////////// +/// Argon2 /// +////////////// // references to R, Z, Q etc. come from the spec // Argon2 operates on 1024 byte blocks. @@ -723,46 +723,40 @@ static void g_rounds(blk *b) } } -const crypto_argon2_settings crypto_argon2i_defaults = { - CRYPTO_ARGON2_I, // algorithm - 100000, 3, 1, // nb_blocks, nb_passes, nb_lanes - 16, 32, // salt_size, hash_size - 0, 0, 0, 0, // no key, no ad -}; - -void crypto_argon2(u8 *hash, void *work_area, const u8 *password, - u32 password_size, const u8 *salt, crypto_argon2_settings s) +void crypto_argon2(u8 *hash, void *work_area, + const u8 *password, u32 password_size, const u8 *salt, + const crypto_argon2_ctx *s) { - const u32 segment_size = s.nb_blocks / s.nb_lanes / 4; + const u32 segment_size = s->nb_blocks / s->nb_lanes / 4; const u32 lane_size = segment_size * 4; - const u32 nb_blocks = lane_size * s.nb_lanes; // s.nb_blocks rounded down + const u32 nb_blocks = lane_size * s->nb_lanes; // nb_blocks rounded down // work area seen as blocks (must be suitably aligned) blk *blocks = (blk*)work_area; { crypto_blake2b_ctx ctx; crypto_blake2b_init(&ctx); - blake_update_32 (&ctx, s.nb_lanes ); // p: number of "threads" - blake_update_32 (&ctx, s.hash_size); - blake_update_32 (&ctx, s.nb_blocks); - blake_update_32 (&ctx, s.nb_passes); + blake_update_32 (&ctx, s->nb_lanes ); // p: number of "threads" + blake_update_32 (&ctx, s->hash_size); + blake_update_32 (&ctx, s->nb_blocks); + blake_update_32 (&ctx, s->nb_passes); blake_update_32 (&ctx, 0x13 ); // v: version number - blake_update_32 (&ctx, s.algorithm); // y: Argon2i, Argon2d... + blake_update_32 (&ctx, s->algorithm); // y: Argon2i, Argon2d... blake_update_32 (&ctx, password_size); crypto_blake2b_update(&ctx, password, password_size); - blake_update_32 (&ctx, s.salt_size); - crypto_blake2b_update(&ctx, salt, s.salt_size); - blake_update_32 (&ctx, s.key_size); - crypto_blake2b_update(&ctx, s.key, s.key_size); - blake_update_32 (&ctx, s.ad_size); - crypto_blake2b_update(&ctx, s.ad, s.ad_size); + blake_update_32 (&ctx, s->salt_size); + crypto_blake2b_update(&ctx, salt, s->salt_size); + blake_update_32 (&ctx, s->key_size); + crypto_blake2b_update(&ctx, s->key, s->key_size); + blake_update_32 (&ctx, s->ad_size); + crypto_blake2b_update(&ctx, s->ad, s->ad_size); u8 initial_hash[72]; // 64 bytes plus 2 words for future hashes crypto_blake2b_final(&ctx, initial_hash); // fill first 2 blocks of each lane u8 hash_area[1024]; - FOR_T(u32, l, 0, s.nb_lanes) { + FOR_T(u32, l, 0, s->nb_lanes) { FOR_T(u32, i, 0, 2) { store32_le(initial_hash + 64, i); // first additional word store32_le(initial_hash + 68, l); // second additional word @@ -785,7 +779,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, // thread per lane. The only reason Monocypher supports multiple // lanes is compatibility. blk tmp; - FOR_T(u32, pass, 0, s.nb_passes) { + FOR_T(u32, pass, 0, s->nb_passes) { FOR_T(u32, slice, 0, 4) { // On the first slice of the first pass, // blocks 0 and 1 are already filled, hence pass_offset. @@ -795,7 +789,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, // Each iteration of the following loop may be performed in // a separate thread. All iterations must be done before we // fill the next slice. - FOR_T(u32, segment, 0, s.nb_lanes) { + FOR_T(u32, segment, 0, s->nb_lanes) { u32 index_ctr = 1; blk index_block; FOR_T (u32, block, pass_offset, segment_size) { @@ -807,7 +801,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, index_block.a[1] = segment; index_block.a[2] = slice; index_block.a[3] = nb_blocks; - index_block.a[4] = s.nb_passes; + index_block.a[4] = s->nb_passes; index_block.a[5] = 1; // type: Argon2i index_block.a[6] = index_ctr; index_ctr++; @@ -838,7 +832,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, u64 y = (window_size * x) >> 32; u64 z = (window_size - 1) - y; u64 ref = (window_start + z) % lane_size; - u32 index = (j2 % s.nb_lanes) * lane_size + (u32)ref; + u32 index = (j2 % s->nb_lanes) * lane_size + (u32)ref; // Find current, previous, and reference blocks u32 lane_offset = segment * lane_size; @@ -869,7 +863,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, // XOR last blocks of each lane blk *last_block = blocks + lane_size - 1; - FOR_T (u32, lane, 1, s.nb_lanes) { + FOR_T (u32, lane, 1, s->nb_lanes) { blk *next_block = last_block + lane_size; xor_block(next_block, last_block); last_block = next_block; @@ -884,7 +878,7 @@ void crypto_argon2(u8 *hash, void *work_area, const u8 *password, ZERO(p, 128 * nb_blocks); // Hash the very last block with H' into the output hash - extended_hash(hash, s.hash_size, final_block, 1024); + extended_hash(hash, s->hash_size, final_block, 1024); WIPE_BUFFER(final_block); } diff --git a/src/monocypher.h b/src/monocypher.h index 08a3029..cb98331 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -140,8 +140,8 @@ void crypto_blake2b_general_init(crypto_blake2b_ctx *ctx, size_t hash_size, const uint8_t *key, size_t key_size); -// Password key derivation (Argon2 i) -// ---------------------------------- +// Password key derivation (Argon2) +// -------------------------------- typedef struct { uint32_t algorithm; // Argon2i, Argon2d, Argon2id @@ -154,17 +154,17 @@ typedef struct { const uint8_t *ad; uint32_t key_size; uint32_t ad_size; -} crypto_argon2_settings; +} crypto_argon2_ctx; +#define CRYPTO_ARGON2_D 0 #define CRYPTO_ARGON2_I 1 - -extern const crypto_argon2_settings crypto_argon2i_defaults; +#define CRYPTO_ARGON2_ID 2 void crypto_argon2(uint8_t *hash, void *work_area, const uint8_t *password, uint32_t password_size, const uint8_t *salt, - crypto_argon2_settings s); + const crypto_argon2_ctx *s); // Key exchange (X-25519) diff --git a/tests/gen/argon2i.c b/tests/gen/argon2.c similarity index 77% rename from tests/gen/argon2i.c rename to tests/gen/argon2.c index fca623b..9f88f74 100644 --- a/tests/gen/argon2i.c +++ b/tests/gen/argon2.c @@ -52,39 +52,47 @@ #include #include "utils.h" -static void test(size_t nb_blocks, size_t hash_size, size_t nb_iterations) +static void test(u32 alg, size_t nb_blocks, size_t hash_size, size_t nb_passes) { RANDOM_INPUT(password, 16 ); RANDOM_INPUT(salt , crypto_pwhash_SALTBYTES); u8 hash[256]; + int algorithm = -1; + switch (alg) { + case 0: fprintf(stderr, "Libsodium does not support Argon2d"); break; + case 1: algorithm = crypto_pwhash_ALG_ARGON2I13; break; + case 2: algorithm = crypto_pwhash_ALG_ARGON2ID13; break; + default: fprintf(stderr, "Unknown algorithm"); + } + if (crypto_pwhash(hash, hash_size, (char*)password, 16, salt, - nb_iterations, nb_blocks * 1024, - crypto_pwhash_ALG_ARGON2I13)) { + nb_passes, nb_blocks * 1024, algorithm)) { fprintf(stderr, "Argon2i failed. " "nb_blocks = %lu, " "hash_size = %lu " - "nb_iterations = %lu\n", - nb_blocks, hash_size, nb_iterations); + "nb_passes = %lu\n", + nb_blocks, hash_size, nb_passes); printf(":deadbeef:\n"); // prints a canary to fail subsequent tests } - print_number(nb_blocks ); - print_number(nb_iterations ); - print_vector(password, 16 ); - print_vector(salt , crypto_pwhash_SALTBYTES); + print_number(alg); + print_number(nb_blocks); + print_number(nb_passes); print_number(1); // one lane (no parallelism) + print_vector(password, 16); + print_vector(salt , crypto_pwhash_SALTBYTES); printf(":\n"); // no key printf(":\n"); // no additionnal data - print_vector(hash , hash_size ); + print_vector(hash, hash_size); printf("\n"); } int main(void) { SODIUM_INIT; - FOR (nb_blocks , 508, 517) { test(nb_blocks, 32 , 3 ); } - FOR (hash_size , 63, 65) { test(8 , hash_size, 3 ); } - FOR (nb_iterations, 3, 6) { test(8 , 32 , nb_iterations); } + FOR (nb_blocks, 508, 517) { test(1, nb_blocks, 32 , 3 ); } + FOR (hash_size, 63, 65) { test(1, 8 , hash_size, 3 ); } + FOR (nb_passes, 3, 6) { test(1, 8 , 32 , nb_passes); } return 0; } diff --git a/tests/gen/makefile b/tests/gen/makefile index 801f596..a80cdf4 100644 --- a/tests/gen/makefile +++ b/tests/gen/makefile @@ -55,7 +55,7 @@ CFLAGS = -pedantic -Wall -Wextra .PHONY: all clean VEC = chacha20 hchacha20 xchacha20 ietf_chacha20 aead_ietf \ - poly1305 blake2b sha512 hmac_sha512 argon2i \ + poly1305 blake2b sha512 hmac_sha512 argon2 \ edDSA edDSA_pk ed_25519 ed_25519_pk ed_25519_check \ x25519 x25519_pk elligator_inv elligator_dir VEC2 = $(patsubst %, %.all.vec, $(VEC)) @@ -116,7 +116,7 @@ aead_ietf.all.vec : aead_ietf.vec blake2b.all.vec : blake2b.vec vectors/blake2b sha512.all.vec : sha512.vec hmac_sha512.all.vec : hmac_sha512.vec vectors/hmac_sha512 -argon2i.all.vec : argon2i.vec vectors/argon2i +argon2.all.vec : argon2.vec vectors/argon2 edDSA.all.vec : edDSA.vec edDSA_pk.all.vec : edDSA_pk.vec ed_25519.all.vec : ed_25519.vec diff --git a/tests/gen/vectors/argon2i b/tests/gen/vectors/argon2 similarity index 93% rename from tests/gen/vectors/argon2i rename to tests/gen/vectors/argon2 index c96ea2b..f093e19 100644 --- a/tests/gen/vectors/argon2i +++ b/tests/gen/vectors/argon2 @@ -1,17 +1,19 @@ +0100000000000000: 0800000000000000: 0300000000000000: +0100000000000000: 0101010101010101010101010101010101010101010101010101010101010101: 02020202020202020202020202020202: -0100000000000000: 0303030303030303: 040404040404040404040404: afe519be3ab0e92375df221dfb17347080c7000b1be85f9ee39978bf11e7cc3a: +0100000000000000: 2000000000000000: 0300000000000000: +0400000000000000: 0101010101010101010101010101010101010101010101010101010101010101: 02020202020202020202020202020202: -0400000000000000: 0303030303030303: 040404040404040404040404: c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8: diff --git a/tests/speed/speed.c b/tests/speed/speed.c index 5c10f79..68b2433 100644 --- a/tests/speed/speed.c +++ b/tests/speed/speed.c @@ -120,14 +120,20 @@ static u64 argon2i(void) { u64 work_area[SIZE / 8]; u8 hash [32]; - RANDOM_INPUT(password, 16); - RANDOM_INPUT(salt , 16); + RANDOM_INPUT(pass, 16); + RANDOM_INPUT(salt, 16); - crypto_argon2_settings s = crypto_argon2i_defaults; + crypto_argon2_ctx s; + memset(&s, 0, sizeof(s)); + s.algorithm = CRYPTO_ARGON2_I; s.nb_blocks = (u32)(SIZE / 1024); + s.nb_passes = 3; + s.nb_lanes = 1; + s.salt_size = sizeof(salt); + s.hash_size = sizeof(hash); TIMING_START { - crypto_argon2(hash, work_area, password, 16, salt, s); + crypto_argon2(hash, work_area, pass, sizeof(pass), salt, &s); } TIMING_END; } diff --git a/tests/test.c b/tests/test.c index f544775..3192985 100644 --- a/tests/test.c +++ b/tests/test.c @@ -517,18 +517,18 @@ static void test_hmac_sha512() } } -/////////////// -/// Argon2i /// -/////////////// -static void argon2i(vector_reader *reader) +////////////// +/// Argon2 /// +////////////// +static void argon2(vector_reader *reader) { - crypto_argon2_settings s = crypto_argon2i_defaults; - + crypto_argon2_ctx s; + s.algorithm = load32_le(next_input(reader).buf); s.nb_blocks = load32_le(next_input(reader).buf); s.nb_passes = load32_le(next_input(reader).buf); - vector password = next_input(reader); - vector salt = next_input(reader); s.nb_lanes = load32_le(next_input(reader).buf); + vector pass = next_input(reader); + vector salt = next_input(reader); vector key = next_input(reader); vector ad = next_input(reader); vector out = next_output(reader); @@ -541,15 +541,15 @@ static void argon2i(vector_reader *reader) s.ad = ad.buf; s.ad_size = ad.size; - crypto_argon2(out.buf, work_area, password.buf, password.size, salt.buf, s); + crypto_argon2(out.buf, work_area, pass.buf, pass.size, salt.buf, &s); free(work_area); } -static void test_argon2i() +static void test_argon2() { - VECTORS(argon2i); + VECTORS(argon2); - printf("\tArgon2i (overlapping i/o)\n"); + printf("\tArgon2 (overlapping i/o)\n"); u8 *work_area = (u8*)alloc(8 * 1024); u8 *clean_work_area = (u8*)alloc(8 * 1024); FOR (i, 0, 10) { @@ -561,27 +561,30 @@ static void test_argon2i() u32 ad_offset = rand64() % 64; u8 hash1[32]; u8 *hash2 = work_area + hash_offset; - u8 pass [16]; FOR (j, 0, 16) { pass[j] = work_area[j + pass_offset]; } - u8 salt [16]; FOR (j, 0, 16) { salt[j] = work_area[j + salt_offset]; } - u8 key [32]; FOR (j, 0, 32) { key [j] = work_area[j + key_offset]; } - u8 ad [32]; FOR (j, 0, 32) { ad [j] = work_area[j + ad_offset]; } + u8 pass[16]; FOR (j, 0, 16) { pass[j] = work_area[j + pass_offset]; } + u8 salt[16]; FOR (j, 0, 16) { salt[j] = work_area[j + salt_offset]; } + u8 key [32]; FOR (j, 0, 32) { key [j] = work_area[j + key_offset]; } + u8 ad [32]; FOR (j, 0, 32) { ad [j] = work_area[j + ad_offset]; } - // without overlap - crypto_argon2_settings s = crypto_argon2i_defaults; + crypto_argon2_ctx s; + s.algorithm = CRYPTO_ARGON2_I; s.nb_blocks = 8; s.nb_passes = 1; + s.nb_lanes = 1; + s.salt_size = sizeof(salt); + s.hash_size = sizeof(hash1); + s.key_size = sizeof(key); + s.ad_size = sizeof(ad); s.key = key; s.ad = ad; - s.key_size = 32; - s.ad_size = 32; - crypto_argon2(hash1, clean_work_area, pass, 16, salt, s); + crypto_argon2(hash1, clean_work_area, pass, 16, salt, &s); // with overlap s.key = work_area + key_offset; s.ad = work_area + ad_offset; crypto_argon2(hash2, work_area, work_area + pass_offset, 16, - work_area + salt_offset, s); + work_area + salt_offset, &s); ASSERT_EQUAL(hash1, hash2, 32); } @@ -1058,7 +1061,7 @@ int main(int argc, char *argv[]) test_blake2b(); test_sha512(); test_hmac_sha512(); - test_argon2i(); + test_argon2(); printf("X25519:\n"); test_x25519(); diff --git a/tests/tis-ci-vectors.h b/tests/tis-ci-vectors.h index 84fd162..5ef6f0d 100644 --- a/tests/tis-ci-vectors.h +++ b/tests/tis-ci-vectors.h @@ -344,25 +344,27 @@ static const char *hmac_sha512_vectors[]={ "ffb3011fcde35b8ff8c09a62fe02e7f17aefd1f458f3c01caa2d57b77699dd335f9670d359fc99c72b30ad3e92c9d39000b127967284cca14b759275531eaba2", }; static size_t nb_hmac_sha512_vectors=45; -static const char *argon2i_vectors[]={ +static const char *argon2_vectors[]={ + "0100000000000000", "0800000000000000", "0300000000000000", + "0100000000000000", "e4e4c4054fe35a75d9c0f679ad8770d8", "227e68e4c1e68ce67ee88e6be251a207", - "0100000000000000", "", "", "2a2ec585be2ec27c215f677e947c212b1b85de797167d4950e29987977c941117c4c5f6f6f547e62d76b88fa121781986a37ea14dc394917af5396ea58915d", + "0100000000000000", "1000000000000000", "0300000000000000", + "0200000000000000", "0101010101010101010101010101010101010101010101010101010101010101", "02020202020202020202020202020202", - "0200000000000000", "0303030303030303", "040404040404040404040404", "a5a960b03adf92c4bc18628f1e23192d3544b91ab57024abc7dc3aed52b807d4", }; -static size_t nb_argon2i_vectors=16; +static size_t nb_argon2_vectors=18; static const char *edDSA_vectors[]={ "50831c8cb43cd6822bf3f6fae0801cb6c843d8066b07346635365fb7d6ee54e5", "b600ab324d70d2372f3ba5a0d8bdd8b8e797f780b642bd56e69a18db74c389bc", diff --git a/tests/tis-ci.c b/tests/tis-ci.c index 1c21747..91df53d 100644 --- a/tests/tis-ci.c +++ b/tests/tis-ci.c @@ -158,15 +158,15 @@ static void hmac_sha512(vector_reader *reader) crypto_hmac_sha512(out.buf, key.buf, key.size, msg.buf, msg.size); } -static void argon2i(vector_reader *reader) +static void argon2(vector_reader *reader) { - crypto_argon2_settings s = crypto_argon2i_defaults; - + crypto_argon2_ctx s; + s.algorithm = load32_le(next_input(reader).buf); s.nb_blocks = load32_le(next_input(reader).buf); s.nb_passes = load32_le(next_input(reader).buf); - vector password = next_input(reader); - vector salt = next_input(reader); s.nb_lanes = load32_le(next_input(reader).buf); + vector pass = next_input(reader); + vector salt = next_input(reader); vector key = next_input(reader); vector ad = next_input(reader); vector out = next_output(reader); @@ -179,7 +179,7 @@ static void argon2i(vector_reader *reader) s.ad = ad.buf; s.ad_size = ad.size; - crypto_argon2(out.buf, work_area, password.buf, password.size, salt.buf, s); + crypto_argon2(out.buf, work_area, pass.buf, pass.size, salt.buf, &s); free(work_area); } @@ -391,7 +391,7 @@ TEST(sha512) //@ ensures \result == 0; TEST(hmac_sha512) //@ ensures \result == 0; -TEST(argon2i) +TEST(argon2) //@ ensures \result == 0; TEST(x25519) //@ ensures \result == 0; @@ -416,7 +416,7 @@ int main(void) { ASSERT(v_blake2b () == 0); ASSERT(v_sha512 () == 0); ASSERT(v_hmac_sha512 () == 0); - ASSERT(v_argon2i () == 0); + ASSERT(v_argon2 () == 0); ASSERT(v_x25519 () == 0); ASSERT(v_edDSA () == 0); ASSERT(v_ed_25519 () == 0); -- 2.47.3