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.
}
}
-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
// 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.
// 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) {
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++;
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;
// 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;
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);
}
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
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)
#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;
}
.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))
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
+0100000000000000:
0800000000000000:
0300000000000000:
+0100000000000000:
0101010101010101010101010101010101010101010101010101010101010101:
02020202020202020202020202020202:
-0100000000000000:
0303030303030303:
040404040404040404040404:
afe519be3ab0e92375df221dfb17347080c7000b1be85f9ee39978bf11e7cc3a:
+0100000000000000:
2000000000000000:
0300000000000000:
+0400000000000000:
0101010101010101010101010101010101010101010101010101010101010101:
02020202020202020202020202020202:
-0400000000000000:
0303030303030303:
040404040404040404040404:
c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8:
{
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;
}
}
}
-///////////////
-/// 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);
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) {
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);
}
test_blake2b();
test_sha512();
test_hmac_sha512();
- test_argon2i();
+ test_argon2();
printf("X25519:\n");
test_x25519();
"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",
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);
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);
}
//@ ensures \result == 0;
TEST(hmac_sha512)
//@ ensures \result == 0;
-TEST(argon2i)
+TEST(argon2)
//@ ensures \result == 0;
TEST(x25519)
//@ ensures \result == 0;
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);