]> git.codecow.com Git - Monocypher.git/commitdiff
Prepare Argon2d and Argon2id support
authorLoup Vaillant <loup@loup-vaillant.fr>
Fri, 30 Dec 2022 21:49:31 +0000 (22:49 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Fri, 30 Dec 2022 23:16:45 +0000 (00:16 +0100)
src/monocypher.c
src/monocypher.h
tests/gen/argon2.c [moved from tests/gen/argon2i.c with 77% similarity]
tests/gen/makefile
tests/gen/vectors/argon2 [moved from tests/gen/vectors/argon2i with 93% similarity]
tests/speed/speed.c
tests/test.c
tests/tis-ci-vectors.h
tests/tis-ci.c

index 11b817e973bd27edc328d6d2a9ac9c6cc1369065..d902328209a0bc9eaaed2ff4f749a239100dba34 100644 (file)
@@ -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 ///
-////////////////
+//////////////
+/// 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);
 }
 
index 08a3029c3f1c5fc013cd597957b01678f63387e9..cb98331e06c18808db963b55fecee355221cfd68 100644 (file)
@@ -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)
similarity index 77%
rename from tests/gen/argon2i.c
rename to tests/gen/argon2.c
index fca623bc21bb3565df82f033660ff956fd8a2838..9f88f749fbbabe55560fe3d448b43132824ac66f 100644 (file)
 #include <sodium.h>
 #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;
 }
index 801f596d0639d178671b32367862aa537e002751..a80cdf485de90ce4a0e30db3101a0f1cdbe56445 100644 (file)
@@ -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
similarity index 93%
rename from tests/gen/vectors/argon2i
rename to tests/gen/vectors/argon2
index c96ea2bc02dac1cc10965dd7e9ded59e6551f487..f093e190e7524b3aa8d86c763c3fa0a790e67618 100644 (file)
@@ -1,17 +1,19 @@
+0100000000000000:
 0800000000000000:
 0300000000000000:
+0100000000000000:
 0101010101010101010101010101010101010101010101010101010101010101:
 02020202020202020202020202020202:
-0100000000000000:
 0303030303030303:
 040404040404040404040404:
 afe519be3ab0e92375df221dfb17347080c7000b1be85f9ee39978bf11e7cc3a:
 
+0100000000000000:
 2000000000000000:
 0300000000000000:
+0400000000000000:
 0101010101010101010101010101010101010101010101010101010101010101:
 02020202020202020202020202020202:
-0400000000000000:
 0303030303030303:
 040404040404040404040404:
 c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8:
index 5c10f79f24521fc0e6d2e582b43bb297b7b89649..68b2433be96f59ab6e95bc66c7b3326f1dae91e6 100644 (file)
@@ -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;
 }
index f544775be3175bb7524f63bf65543e46e6a70f08..3192985b498c12070c7705ba0276feec83eb348f 100644 (file)
@@ -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();
index 84fd162e3e163cc7666d638a03eaf69b7ff3a664..5ef6f0dedaed0e45353c22c93effd7a3f2a76e26 100644 (file)
@@ -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",
index 1c217470347406fc7b6adfb4158fb80274a6e5c9..91df53d9079a250b7ca619469473df462a791370 100644 (file)
@@ -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);