hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 635e17e1da70b37b9b716cfebc6db6bb3cd95904
parent 11db66bdb7574ee8f6d642dea0498907f9121b6b
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Fri, 20 Jan 2023 11:28:56 +0100

crypto::argon2: fix initial hash and block indexing

The initial hash requires the memory size as given and not the
rounded one.

The function to determine the reference block has been adjusted
according to the golang implementation.

Unfortunately the `argon2::low_mem_config` has been affected by
the bugs this commit fixes and produced invalid keys/hashes.

Co-authored-by: illiliti <illiliti@dimension.sh>
Signed-off-by: Armin Preiml <apreiml@strohwolke.at>

Diffstat:
Mcrypto/argon2/+test.ha | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrypto/argon2/argon2.ha | 53++++++++++++++++++++++++++++++++---------------------
Mscripts/gen-stdlib | 8+++++---
Mstdlib.mk | 4++--
4 files changed, 154 insertions(+), 26 deletions(-)

diff --git a/crypto/argon2/+test.ha b/crypto/argon2/+test.ha @@ -2,6 +2,8 @@ // (c) 2021-2022 Armin Preiml <apreiml@strohwolke.at> // (c) 2022 Drew DeVault <sir@cmpwn.com> use bytes; +use encoding::hex; +use strings; @test fn mode_d_one_pass() void = { let pass: [32]u8 = [1...]; @@ -129,3 +131,116 @@ use bytes; assert(bytes::equal(result, expected)); }; +type tcase = struct { + c: config, + m: mode, + h: str, +}; + +@test fn samples() void = { + const pass = strings::toutf8("trustno1"); + const salt = strings::toutf8("abcdefgh"); + + const tests: [_]tcase = [ + // XXX disabled for now because it's slow + // tcase { + // c = low_mem_config, + // m = mode::ID, + // h = "8974537c53677aae532b319af700bb4232a0d74eee7d57296b2a3f8303a6bafe", + // }, + // tcase { + // c = default_config, + // m = mode::ID, + // h = "3b282cbf435b0e022f7041549583ddc802e519109f1da8f12d2054910913d660", + // }, + tcase { + c = config { + passes = 1, + parallel = 3, + version = 0x13, + mem = 64, + ... + }, + m = mode::ID, + h = "c7ada5ba3222fa45a3802249b509dcfb10e68a50e3faad2a6377eeca8395ab47", + }, + tcase { + c = config { + passes = 1, + parallel = 4, + version = 0x13, + mem = 64, + ... + }, + m = mode::ID, + h = "21543b2017ede3f865ea5cb88295628ba25eb3be53a8c4aeb0ac1a264be0110a", + }, + tcase { + c = config { + passes = 1, + parallel = 4, + version = 0x13, + mem = 64, + ... + }, + m = mode::I, + h = "5c3124ce5f3556e5e25f06b5108718f2cd72afee98a3249656eb85ecc0e5b314", + }, + tcase { + c = config { + passes = 1, + parallel = 4, + version = 0x13, + mem = 64, + ... + }, + m = mode::D, + h = "d75524ad0b899363ce77f2d1e1040763dc01cfc725db635391bba163001f08cb", + }, + tcase { + c = config { + passes = 3, + parallel = 3, + version = 0x13, + mem = 64, + ... + }, + m = mode::ID, + h = "226c3ca6caba42b102035d332a11b350f1e19675fccb6e24aa33ca8c31d588c1", + }, + tcase { + c = config { + passes = 1, + parallel = 8, + version = 0x13, + mem = 64, + ... + }, + m = mode::ID, + h = "fadf598b70708f4d91b0e98f038fd25a73950f1f85d57fb250740d817f95e9a9", + }, + tcase { + c = config { + passes = 1, + parallel = 4, + version = 0x13, + mem = 96, + ... + }, + m = mode::ID, + h = "c99aa41cb53cc4919d336c19d38b30d8633c71faa9475293f3fbe0aa6ccd65b2", + }, + ]; + + for (let i = 0z; i < len(tests); i += 1) { + const t = tests[i]; + const expected = hex::decodestr(t.h)!; + defer free(expected); + let dest: []u8 = alloc([0...], len(expected)); + defer free(dest); + + argon2(dest, pass, salt, &t.c, t.m)!; + assert(bytes::equal(expected, dest)); + }; +}; + diff --git a/crypto/argon2/argon2.ha b/crypto/argon2/argon2.ha @@ -1,4 +1,3 @@ -// License: MPL-2.0 // (c) 2022 Alexey Yerin <yyp@disroot.org> // (c) 2021-2022 Armin Preiml <apreiml@strohwolke.at> // (c) 2021-2022 Drew DeVault <sir@cmpwn.com> @@ -177,13 +176,15 @@ fn argon2( let mem: []u64 = alloc([0...], membytes); yield mem[..membytes / 8]; }; - // round down memory to nearest multiple of 4 times parallel - mem = mem[..len(mem) - len(mem) % (4 * cfg.parallel * BLOCKSIZE)]; - const memsize = (len(mem) / BLOCKSIZE): u32; + const rawmemsize = (len(mem) / BLOCKSIZE): u32; let h0: [64]u8 = [0...]; - inithash(&h0, len(dest): u32, password, salt, cfg, mode, memsize); + inithash(&h0, len(dest): u32, password, salt, cfg, mode, rawmemsize); + // round down memory to nearest multiple of 4 times parallel + mem = mem[..len(mem) - len(mem) % (4 * cfg.parallel * BLOCKSIZE)]; + + const memsize = (len(mem) / BLOCKSIZE): u32; const cols = 4 * (memsize / (4 * cfg.parallel)); let ctx = context { rows = cfg.parallel, @@ -247,30 +248,35 @@ fn blocku8(ctx: *context, i: size, j: size) []u8 = { }; fn refblock(cfg: *config, ctx: *context, seed: u64, i: size, j: size) []u64 = { - const j1: u64 = seed & 0xffffffff; - const segstart = j - (j % ctx.sliceblocks); + const segstart = (j - (j % ctx.sliceblocks)) / ctx.sliceblocks; + const index = j % ctx.sliceblocks; - const l: u64 = if (segstart == 0 && ctx.pass == 0) { - yield 0; + const l: size = if (segstart == 0 && ctx.pass == 0) { + yield i; } else { yield (seed >> 32) % cfg.parallel; }; - let poolstart: u64 = 0; - let poolsize: u64 = segstart; - if (ctx.pass > 0) { - poolstart = (segstart + ctx.sliceblocks) % ctx.cols; - poolsize = 3 * ctx.sliceblocks; + let poolstart: u64 = ((segstart + 1) % SLICES) * ctx.sliceblocks; + let poolsize: u64 = 3 * ctx.sliceblocks; + + if (i == l) { + poolsize += index; }; - if (l == i: u64) { - poolsize += (j - segstart); + if (ctx.pass == 0) { + poolstart = 0; + poolsize = segstart * ctx.sliceblocks; + if (segstart == 0 || i == l) { + poolsize += index; + }; }; - if ((j - segstart) == 0 || l == i: u64) { + if (index == 0 || i == l) { poolsize -= 1; }; + const j1: u64 = seed & 0xffffffff; const x: u64 = (j1 * j1) >> 32; const y: u64 = (poolsize * x) >> 32; const z: u64 = (poolstart + poolsize - (y+1)) % ctx.cols: u64; @@ -381,7 +387,7 @@ fn segproc(cfg: *config, ctx: *context, i: size, slice: size) void = { case mode::I => yield true; case mode::ID => - yield ctx.pass == 0 && slice <= 2; + yield ctx.pass == 0 && slice < 2; case mode::D => yield false; }; @@ -417,8 +423,12 @@ fn segproc(cfg: *config, ctx: *context, i: size, slice: size) void = { case mode::I => yield false; }; + + const pj = if (j == 0) ctx.cols - 1 else j - 1; + let prev = block(ctx, i, pj); + const seed: u64 = if (dmodeseed) { - yield block(ctx, i, (j - 1) % ctx.cols)[0]; + yield prev[0]; } else { if (b % BLOCKSIZE == 0) { ctx.seedsinit[6] += 1; @@ -429,8 +439,9 @@ fn segproc(cfg: *config, ctx: *context, i: size, slice: size) void = { }; yield ctx.seedblock[b % BLOCKSIZE]; }; - compress(block(ctx, i, j), block(ctx, i, (j - 1) % ctx.cols), - refblock(cfg, ctx, seed, i, j), ctx.pass > 0); + + let ref = refblock(cfg, ctx, seed, i, j); + compress(block(ctx, i, j), prev, ref, ctx.pass > 0); }; }; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -278,12 +278,14 @@ crypto_argon2() { if [ $testing -eq 0 ] then gen_srcs crypto::argon2 argon2.ha + gen_ssa crypto::argon2 bufio bytes crypto::blake2b \ + crypto::math endian errors hash io rt types else gen_srcs crypto::argon2 argon2.ha +test.ha + gen_ssa crypto::argon2 bufio bytes crypto::blake2b \ + crypto::math encoding::hex endian errors hash io rt \ + strings types fi - - gen_ssa crypto::argon2 bufio bytes crypto::blake2b \ - crypto::math endian errors hash io types } crypto_bcrypt() { diff --git a/stdlib.mk b/stdlib.mk @@ -825,7 +825,7 @@ $(HARECACHE)/crypto/aes/xts/crypto_aes_xts-any.ssa: $(stdlib_crypto_aes_xts_any_ stdlib_crypto_argon2_any_srcs = \ $(STDLIB)/crypto/argon2/argon2.ha -$(HARECACHE)/crypto/argon2/crypto_argon2-any.ssa: $(stdlib_crypto_argon2_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_crypto_blake2b_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) +$(HARECACHE)/crypto/argon2/crypto_argon2-any.ssa: $(stdlib_crypto_argon2_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_crypto_blake2b_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/argon2 @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::argon2 \ @@ -3047,7 +3047,7 @@ testlib_crypto_argon2_any_srcs = \ $(STDLIB)/crypto/argon2/argon2.ha \ $(STDLIB)/crypto/argon2/+test.ha -$(TESTCACHE)/crypto/argon2/crypto_argon2-any.ssa: $(testlib_crypto_argon2_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_blake2b_$(PLATFORM)) $(testlib_crypto_math_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_types_$(PLATFORM)) +$(TESTCACHE)/crypto/argon2/crypto_argon2-any.ssa: $(testlib_crypto_argon2_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_blake2b_$(PLATFORM)) $(testlib_crypto_math_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/crypto/argon2 @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::argon2 \