commit 4473110bc6c07fb5185a1540e12d50db7f8f12f7
parent 39332326aa2b6f5e79cf9fed4e9ab28e6f6e3dd1
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 10 Jan 2022 12:02:31 +0100
crypto: implement derivekey
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
4 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/crypto/authenc.ha b/crypto/authenc.ha
@@ -1,3 +1,5 @@
+use errors;
+
// A secret session key.
export type sessionkey = [32]u8;
diff --git a/crypto/keyderiv.ha b/crypto/keyderiv.ha
@@ -0,0 +1,46 @@
+use errors;
+use crypto::argon2;
+
+// Given a password, derive a key. Given the same password, salt, memory, and
+// passes, this function will always produce the same key. This function is
+// designed to derive cryptographic keys from user-provided passwords, or to
+// verify a password for user logins.
+//
+// The user provides a buffer for the key to be written to via the 'dest'
+// parameter. The minimum supported length for this buffer is 4 bytes, and the
+// recommended length is 32 bytes.
+//
+// The salt parameter should be randomly generated, stored alongside the key,
+// and used in subsequent calls to produce the same key. It must be at least 8
+// bytes, but 16 bytes is recommended. Use [[crypto::random]] to generate a
+// different salt for each key.
+//
+// The 'mem' and 'passes' functions are provided to tune the behavior of this
+// algorithm. It is designed to be computationally expensive, and you must
+// adjust these figures to suit your hardware and use-case. If you provide a u32
+// for 'mem', the algorithm will dynamically allocate that many kilobytes of
+// working memory. To allocate this memory yourself, provide a []u64 instead.
+// The number of passes controls the amount of time spent generating the key,
+// higher numbers take longer.
+//
+// To identify ideal values for these parameters, start with 100000 for 'mem'
+// (100 MiB) and 0 for 'passes'. If it takes too long, reduce the amount of
+// memory, and if it does not take long enough, increase the amount of memory.
+// If you have reached the maximum amount of memory you are able to use,
+// increase passes.
+export fn derivekey(
+ dest: []u8,
+ salt: []u8,
+ password: []u8,
+ mem: (u32 | []u64),
+ passes: u32,
+) (void | errors::nomem) = {
+ const config = argon2::config {
+ mem = mem,
+ parallel = 1,
+ passes = passes + 3,
+ version = argon2::VERSION,
+ ...
+ };
+ return argon2::argon2i(dest, password, salt, &config);
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -185,6 +185,13 @@ compress_zlib() {
hash::adler32 io fmt
}
+crypto() {
+ gen_srcs crypto \
+ authenc.ha \
+ keyderiv.ha
+ gen_ssa crypto errors crypto::argon2
+}
+
gensrcs_crypto_aes() {
gen_srcs crypto::aes \
aes_ct64.ha \
@@ -1095,6 +1102,7 @@ bufio
bytes
compress::flate
compress::zlib
+crypto
crypto::aes
crypto::argon2
crypto::blake2b
diff --git a/stdlib.mk b/stdlib.mk
@@ -144,6 +144,12 @@ stdlib_deps_any+=$(stdlib_compress_zlib_any)
stdlib_compress_zlib_linux=$(stdlib_compress_zlib_any)
stdlib_compress_zlib_freebsd=$(stdlib_compress_zlib_any)
+# gen_lib crypto (any)
+stdlib_crypto_any=$(HARECACHE)/crypto/crypto-any.o
+stdlib_deps_any+=$(stdlib_crypto_any)
+stdlib_crypto_linux=$(stdlib_crypto_any)
+stdlib_crypto_freebsd=$(stdlib_crypto_any)
+
# gen_lib crypto::aes (any)
stdlib_crypto_aes_any=$(HARECACHE)/crypto/aes/crypto_aes-any.o
stdlib_deps_any+=$(stdlib_crypto_aes_any)
@@ -653,6 +659,17 @@ $(HARECACHE)/compress/zlib/compress_zlib-any.ssa: $(stdlib_compress_zlib_any_src
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncompress::zlib \
-t$(HARECACHE)/compress/zlib/compress_zlib.td $(stdlib_compress_zlib_any_srcs)
+# crypto (+any)
+stdlib_crypto_any_srcs= \
+ $(STDLIB)/crypto/authenc.ha \
+ $(STDLIB)/crypto/keyderiv.ha
+
+$(HARECACHE)/crypto/crypto-any.ssa: $(stdlib_crypto_any_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_crypto_argon2_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/crypto
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto \
+ -t$(HARECACHE)/crypto/crypto.td $(stdlib_crypto_any_srcs)
+
# crypto::aes (+any)
stdlib_crypto_aes_any_srcs= \
$(STDLIB)/crypto/aes/aes_ct64.ha
@@ -1862,6 +1879,12 @@ testlib_deps_any+=$(testlib_compress_zlib_any)
testlib_compress_zlib_linux=$(testlib_compress_zlib_any)
testlib_compress_zlib_freebsd=$(testlib_compress_zlib_any)
+# gen_lib crypto (any)
+testlib_crypto_any=$(TESTCACHE)/crypto/crypto-any.o
+testlib_deps_any+=$(testlib_crypto_any)
+testlib_crypto_linux=$(testlib_crypto_any)
+testlib_crypto_freebsd=$(testlib_crypto_any)
+
# gen_lib crypto::aes (any)
testlib_crypto_aes_any=$(TESTCACHE)/crypto/aes/crypto_aes-any.o
testlib_deps_any+=$(testlib_crypto_aes_any)
@@ -2372,6 +2395,17 @@ $(TESTCACHE)/compress/zlib/compress_zlib-any.ssa: $(testlib_compress_zlib_any_sr
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncompress::zlib \
-t$(TESTCACHE)/compress/zlib/compress_zlib.td $(testlib_compress_zlib_any_srcs)
+# crypto (+any)
+testlib_crypto_any_srcs= \
+ $(STDLIB)/crypto/authenc.ha \
+ $(STDLIB)/crypto/keyderiv.ha
+
+$(TESTCACHE)/crypto/crypto-any.ssa: $(testlib_crypto_any_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_crypto_argon2_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/crypto
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto \
+ -t$(TESTCACHE)/crypto/crypto.td $(testlib_crypto_any_srcs)
+
# crypto::aes (+any)
testlib_crypto_aes_any_srcs= \
$(STDLIB)/crypto/aes/aes_ct64.ha \