return (u32)(ref < ctx->nb_blocks ? ref : ref - ctx->nb_blocks);
}
+const crypto_argon2_settings crypto_argon2i_defaults = {
+ CRYPTO_ARGON2_I, // algorithm
+ 100000, 3, 1, // nb_blocks, nb_iterations, nb_lanes
+ 16, 32, // salt_size, hash_size
+ 0, 0, 0, 0, // no key, no ad
+};
+
// Main algorithm
-void crypto_argon2i_general(u8 *hash, u32 hash_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)
+void crypto_argon2(u8 *hash, void *work_area, const u8 *password,
+ u32 password_size, const u8 *salt, crypto_argon2_settings s)
{
// work area seen as blocks (must be suitably aligned)
block *blocks = (block*)work_area;
{
crypto_blake2b_ctx ctx;
crypto_blake2b_init(&ctx);
-
- blake_update_32 (&ctx, 1 ); // p: number of threads
- blake_update_32 (&ctx, hash_size );
- blake_update_32 (&ctx, nb_blocks );
- blake_update_32 (&ctx, nb_iterations);
- blake_update_32 (&ctx, 0x13 ); // v: version number
- blake_update_32 (&ctx, 1 ); // y: Argon2i
+ 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_iterations);
+ blake_update_32 (&ctx, 0x13 ); // v: version number
+ 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, salt_size);
- crypto_blake2b_update(&ctx, salt, salt_size);
- blake_update_32 (&ctx, key_size);
- crypto_blake2b_update(&ctx, key, key_size);
- blake_update_32 (&ctx, ad_size);
- crypto_blake2b_update(&ctx, ad, 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);
WIPE_BUFFER(hash_area);
}
- // Actual number of blocks
- nb_blocks -= nb_blocks & 3; // round down to 4 p (p == 1 thread)
+ // Actual number of blocks (must be a multiple of 4 p)
+ u32 nb_blocks = s.nb_blocks - s.nb_blocks % (4 * s.nb_lanes);
const u32 segment_size = nb_blocks >> 2;
// fill (then re-fill) the rest of the blocks
block tmp;
gidx_ctx ctx; // public information, no need to wipe
- FOR_T (u32, pass_number, 0, nb_iterations) {
+ FOR_T (u32, pass_number, 0, s.nb_iterations) {
int first_pass = pass_number == 0;
FOR_T (u32, segment, 0, 4) {
- gidx_init(&ctx, pass_number, segment, nb_blocks, nb_iterations);
+ gidx_init(&ctx, pass_number, segment, nb_blocks, s.nb_iterations);
// On the first segment of the first pass,
// blocks 0 and 1 are already filled.
ZERO(p, 128 * nb_blocks);
// hash the very last block with H' into the output hash
- extended_hash(hash, hash_size, final_block, 1024);
+ extended_hash(hash, s.hash_size, final_block, 1024);
WIPE_BUFFER(final_block);
}
-void crypto_argon2i(u8 *hash, u32 hash_size,
- void *work_area, u32 nb_blocks, u32 nb_iterations,
- const u8 *password, u32 password_size,
- const u8 *salt, u32 salt_size)
-{
- crypto_argon2i_general(hash, hash_size, work_area, nb_blocks, nb_iterations,
- password, password_size, salt , salt_size, 0,0,0,0);
-}
-
////////////////////////////////////
/// Arithmetic modulo 2^255 - 19 ///
////////////////////////////////////
// Password key derivation (Argon2 i)
// ----------------------------------
-void crypto_argon2i(uint8_t *hash, uint32_t hash_size, // >= 4
- void *work_area, uint32_t nb_blocks, // >= 8
- uint32_t nb_iterations, // >= 3
- const uint8_t *password, uint32_t password_size,
- const uint8_t *salt, uint32_t salt_size); // >= 8
-
-void crypto_argon2i_general(uint8_t *hash, uint32_t hash_size,// >= 4
- void *work_area, uint32_t nb_blocks,// >= 8
- uint32_t nb_iterations, // >= 3
- 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);
+
+typedef struct {
+ uint32_t algorithm; // Argon2i, Argon2d, Argon2id
+ uint32_t nb_blocks; // memory hardness, >= 8
+ uint32_t nb_iterations; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
+ uint32_t nb_lanes; // parallelism level (single threaded anyway)
+ uint32_t salt_size; // we recommend 16 bytes
+ uint32_t hash_size; // we recommend 32 bytes per key
+ const uint8_t *key; // pointers are aligned to 8 bytes
+ const uint8_t *ad;
+ uint32_t key_size;
+ uint32_t ad_size;
+} crypto_argon2_settings;
+
+#define CRYPTO_ARGON2_I 1
+
+extern const crypto_argon2_settings crypto_argon2i_defaults;
+
+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);
// Key exchange (X-25519)
{
u64 work_area[SIZE / 8];
u8 hash [32];
- u32 nb_blocks = (u32)(SIZE / 1024);
RANDOM_INPUT(password, 16);
RANDOM_INPUT(salt , 16);
+ crypto_argon2_settings s = crypto_argon2i_defaults;
+ s.nb_blocks = (u32)(SIZE / 1024);
+
TIMING_START {
- crypto_argon2i(hash, 32, work_area, nb_blocks, 3,
- password, 16, salt, 16);
+ crypto_argon2(hash, work_area, password, 16, salt, s);
}
TIMING_END;
}
vector ad = next_input(reader);
vector out = next_output(reader);
void *work_area = alloc(nb_blocks * 1024);
- crypto_argon2i_general(out.buf, (u32)out.size,
- work_area, (u32)nb_blocks, (u32)nb_iterations,
- password.buf, (u32)password.size,
- salt .buf, (u32)salt .size,
- key .buf, (u32)key .size,
- ad .buf, (u32)ad .size);
+
+ crypto_argon2_settings s = crypto_argon2i_defaults;
+ s.nb_blocks = nb_blocks;
+ s.nb_iterations = nb_iterations;
+ s.hash_size = out.size;
+ s.salt_size = salt.size;
+ s.key = key.buf;
+ s.key_size = key.size;
+ s.ad = ad.buf;
+ s.ad_size = ad.size;
+
+ crypto_argon2(out.buf, work_area, password.buf, password.size, salt.buf, s);
free(work_area);
}
{
VECTORS(argon2i);
- printf("\tArgon2i (easy interface)\n");
- {
- void *work_area = alloc(8 * 1024);
- RANDOM_INPUT(password , 32);
- RANDOM_INPUT(salt , 16);
- u8 hash_general[32];
- u8 hash_easy [32];
- crypto_argon2i_general(hash_general, 32, work_area, 8, 1,
- password, 32, salt, 16, 0, 0, 0, 0);
- crypto_argon2i(hash_easy, 32, work_area, 8, 1, password, 32, salt, 16);
- ASSERT_EQUAL(hash_general, hash_easy, 32);
- free(work_area);
- }
-
printf("\tArgon2i (overlapping i/o)\n");
u8 *work_area = (u8*)alloc(8 * 1024);
u8 *clean_work_area = (u8*)alloc(8 * 1024);
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]; }
- crypto_argon2i_general(hash1, 32, clean_work_area, 8, 1,
- pass, 16, salt, 16, key, 32, ad, 32);
- crypto_argon2i_general(hash2, 32, work_area, 8, 1,
- work_area + pass_offset, 16,
- work_area + salt_offset, 16,
- work_area + key_offset, 32,
- work_area + ad_offset, 32);
+ // without overlap
+ crypto_argon2_settings s = crypto_argon2i_defaults;
+ s.nb_blocks = 8;
+ s.nb_iterations = 1;
+ s.key = key;
+ s.ad = ad;
+ s.key_size = 32;
+ s.ad_size = 32;
+ 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);
+
ASSERT_EQUAL(hash1, hash2, 32);
}
free(work_area);
vector ad = next_input(reader);
vector out = next_output(reader);
void *work_area = alloc(nb_blocks * 1024);
- crypto_argon2i_general(out.buf, (u32)out.size,
- work_area, (u32)nb_blocks, (u32)nb_iterations,
- password.buf, (u32)password.size,
- salt .buf, (u32)salt .size,
- key .buf, (u32)key .size,
- ad .buf, (u32)ad .size);
+
+ crypto_argon2_settings s = crypto_argon2i_defaults;
+ s.nb_blocks = nb_blocks;
+ s.nb_iterations = nb_iterations;
+ s.hash_size = out.size;
+ s.salt_size = salt.size;
+ s.key = key.buf;
+ s.key_size = key.size;
+ s.ad = ad.buf;
+ s.ad_size = ad.size;
+
+ crypto_argon2(out.buf, work_area, password.buf, password.size, salt.buf, s);
free(work_area);
}