tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: [PATCH] argon2 key generation method for cgdconfig(8)



On Sat, Nov 06, 2021 at 09:42:04AM +0000, Taylor R Campbell wrote:
> Err...  I don't think this will do what you want it to do.  The effect
> will presumably be to add something like
> 
> 	-Wl,-Bstatic -Wl,-Bdynamic ... -largon2
> 
> to the linker command line eventually, because PROGDPLIBS gets
> processed much later on.

Oh yes, it can just use PROGDPLIBS. Got confused because I had a stray
libargon2.so hanging around which was being pulled in by surprise.

> That said, since we already argon2 logic as part of libcrypt, does it
> make sense to have another copy in cgdconfig?
> 
> I guess the main issue is with pthreads.  Maybe we can find a way
> around this with non-threaded weak aliases in libargon2 (maybe
> argon2_thread_create/join), so applications can override them with
> strong symbols that use pthreads but out of the box libcrypt.so
> doesn't require libpthread?

I decided I don't want to add a new library dependency to libcrypt
because external software will be linking against it and it's
surprising for those use cases.

Do we want to use libcrypt here, though? It would add extra
string processing and it also stores hashes secrets in a static
variable, which may be a problem for cgd because we need the hash
to be secret.

> What units are these in?  Maybe add a comment explaining so the number
> 100000 is a little more obvious?

Yes, also added a comment for the 256k value from the argon2 test
suite per rin's question.

> Slightly confused by this logic.  It looks like we increase time
> linearly, and then stop when the _entire sequence of trials_ has
> exceeded 1sec.  Shouldn't we increase time (say) exponentially, and
> stop when _one trial_ has exceeded one second?

Yeah, this is leftover code from libcrypt which doesn't make
as much sense here.

I've reworked it to use CLOCK_MONOTONIC instead of getrusage
(which I think is more appropriate because libargon2 may be
using system time for memory allocation and thread related
tasks), increase time non-linearly, and stop when one trial
has exceeded one second.

> Need #include <stddef.h> for size_t.

Yeah.
? external/apache2/argon2/lib/libargon2/argon2.pico
? external/apache2/argon2/lib/libargon2/argon2.po
? external/apache2/argon2/lib/libargon2/blake2b.pico
? external/apache2/argon2/lib/libargon2/blake2b.po
? external/apache2/argon2/lib/libargon2/core.pico
? external/apache2/argon2/lib/libargon2/core.po
? external/apache2/argon2/lib/libargon2/encoding.pico
? external/apache2/argon2/lib/libargon2/encoding.po
? external/apache2/argon2/lib/libargon2/ref.pico
? external/apache2/argon2/lib/libargon2/ref.po
? external/apache2/argon2/lib/libargon2/thread.pico
? external/apache2/argon2/lib/libargon2/thread.po
? sbin/cgdconfig/a.out
? sbin/cgdconfig/q
? sbin/cgdconfig/test.c
Index: lib/Makefile
===================================================================
RCS file: /cvsroot/src/lib/Makefile,v
retrieving revision 1.292
diff -u -p -r1.292 Makefile
--- lib/Makefile	25 Apr 2021 23:43:48 -0000	1.292
+++ lib/Makefile	8 Nov 2021 13:26:03 -0000
@@ -54,6 +54,10 @@ SUBDIR+=	libskey
 SUBDIR+=	libnvmm
 .endif
 
+.if (${MKARGON2} != "no")
+SUBDIR+=	../external/apache2/argon2/lib/libargon2
+.endif
+
 .if (${MKMDNS} != "no")
 SUBDIR+=	../external/apache2/mDNSResponder/lib
 .endif
Index: external/apache2/argon2/lib/libargon2/Makefile
===================================================================
RCS file: external/apache2/argon2/lib/libargon2/Makefile
diff -N external/apache2/argon2/lib/libargon2/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ external/apache2/argon2/lib/libargon2/Makefile	8 Nov 2021 13:26:03 -0000
@@ -0,0 +1,23 @@
+# $NetBSD$
+
+LIBISPRIVATE=	pic
+
+.include <bsd.own.mk>
+
+ARGON2DIR=	${NETBSDSRCDIR}/external/apache2/argon2
+
+.PATH: ${ARGON2DIR}/dist/phc-winner-argon2/src \
+       ${ARGON2DIR}/dist/phc-winner-argon2/src/blake2 \
+       ${ARGON2DIR}/dist/phc-winner-argon2/include
+
+LIB=	argon2
+SRCS=	argon2.c core.c blake2b.c thread.c encoding.c ref.c
+
+CFLAGS+=	-pthread
+CPPFLAGS+=	-I${ARGON2DIR}/dist/phc-winner-argon2/include
+
+.if ${MACHINE} == "vax"
+COPTS.blake2b.c+=	-O0
+.endif
+
+.include <bsd.lib.mk>
Index: sbin/cgdconfig/Makefile
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/Makefile,v
retrieving revision 1.15
diff -u -p -r1.15 Makefile
--- sbin/cgdconfig/Makefile	1 Jul 2016 22:50:09 -0000	1.15
+++ sbin/cgdconfig/Makefile	8 Nov 2021 13:26:03 -0000
@@ -3,6 +3,8 @@
 RUMPPRG=cgdconfig
 MAN=	cgdconfig.8
 
+.include <bsd.own.mk>
+
 SRCS+=	cgdconfig.c		\
 	cgdlex.l		\
 	cgdparse.y		\
@@ -10,6 +12,10 @@ SRCS+=	cgdconfig.c		\
 	params.c		\
 	utils.c
 
+.if ${MKARGON2} != "no"
+SRCS+=	argon2_utils.c
+.endif
+
 CPPFLAGS+= -I${.CURDIR} -I. -DYY_NO_INPUT
 
 YHEADER=1
@@ -17,4 +23,16 @@ YHEADER=1
 DPADD=  ${LIBUTIL} ${LIBCRYPT} ${LIBY} ${LIBL}
 LDADD=  -lutil -lcrypt -ly -ll
 
+.if ${MKARGON2} != "no"
+ARGON2DIR=	${NETBSDSRCDIR}/external/apache2/argon2
+ARGON2OBJDIR!=	cd ${ARGON2DIR}/lib/libargon2 && ${PRINTOBJDIR}
+CPPFLAGS+=	-I${NETBSDSRCDIR}/external/apache2/argon2/dist/phc-winner-argon2/include
+CPPFLAGS+=	-DHAVE_ARGON2
+
+PROGDPLIBS+=	argon2 ${ARGON2DIR}/lib/libargon2
+
+LDADD+=		-pthread
+DPADD+=		${LIBPTHREAD}
+.endif
+
 .include <bsd.prog.mk>
Index: sbin/cgdconfig/argon2_utils.c
===================================================================
RCS file: sbin/cgdconfig/argon2_utils.c
diff -N sbin/cgdconfig/argon2_utils.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sbin/cgdconfig/argon2_utils.c	8 Nov 2021 13:26:03 -0000
@@ -0,0 +1,171 @@
+/*	$NetBSD$ */
+/*-
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nia Alarie.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <argon2.h>
+#include <stdlib.h>
+#include <time.h>
+#include <util.h>
+#include <err.h>
+
+#include "argon2_utils.h"
+
+#ifndef lint
+__RCSID("$NetBSD$");
+#endif
+
+static size_t
+get_cpucount(void)
+{
+	const int mib[] = { CTL_HW, HW_NCPUONLINE };
+	int ncpuonline = 1;
+	size_t ncpuonline_len = sizeof(ncpuonline);
+
+	if (sysctl(mib, __arraycount(mib),
+	    &ncpuonline, &ncpuonline_len, NULL, 0) < 0) {
+		return 1;
+	}
+	return ncpuonline;
+}
+
+static uint64_t
+get_usermem(void)
+{
+	const int mib[] = { CTL_HW, HW_USERMEM64 };
+	uint64_t usermem64 = 0;
+	size_t usermem64_len = sizeof(usermem64);
+	struct rlimit rlim;
+
+	if (sysctl(mib, __arraycount(mib),
+	    &usermem64, &usermem64_len, NULL, 0) < 0) {
+		return 0;
+	}
+
+	if (getrlimit(RLIMIT_AS, &rlim) < 0)
+		return usermem64;
+	if (usermem64 > rlim.rlim_cur && rlim.rlim_cur != RLIM_INFINITY)
+		usermem64 = rlim.rlim_cur;
+	return usermem64;
+}
+
+void
+argon2id_calibrate(size_t keylen, size_t saltlen,
+    size_t *iterations, size_t *memory, size_t *parallelism)
+{
+	size_t mem = ARGON2_MIN_MEMORY; /* kilobytes */
+	size_t time = ARGON2_MIN_TIME;
+	const size_t ncpus = get_cpucount();
+	const uint64_t usermem = get_usermem();
+	struct timespec tp1, tp2;
+	struct timespec delta;
+	unsigned int limit = 0;
+	uint8_t *key = NULL, *salt = NULL;
+	uint8_t tmp_pwd[17]; /* just random data for testing */
+	int err = ARGON2_OK;
+
+	key = emalloc(keylen);
+	salt = emalloc(saltlen);
+
+	arc4random_buf(tmp_pwd, sizeof(tmp_pwd));
+	arc4random_buf(salt, saltlen);
+
+	/* 1kb to argon2 per 100kb of user memory */
+	mem = usermem / 100000;
+
+	/* 256k: reasonable lower bound from the argon2 test suite */
+	if (mem < 256)
+		mem = 256;
+
+	/* Decrease 'mem' if it slows down computation too much */
+
+	do {
+		if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1)
+			goto error;
+		if ((err = argon2_hash(time, mem, ncpus,
+		    tmp_pwd, sizeof(tmp_pwd),
+		    salt, saltlen,
+		    key, keylen,
+		    NULL, 0,
+		    Argon2_id, ARGON2_VERSION_NUMBER)) != ARGON2_OK) {
+			goto error_a2;
+		}
+		if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1)
+			goto error;
+		if (timespeccmp(&tp1, &tp2, >))
+			goto error; /* broken system... */
+		timespecsub(&tp2, &tp1, &delta);
+		if (delta.tv_sec >= 1)
+			mem /= 2;
+		if (mem < ARGON2_MIN_MEMORY) {
+			mem = ARGON2_MIN_MEMORY;
+			break;
+		}
+	} while (delta.tv_sec >= 1 && (limit++) < 3);
+
+	delta.tv_sec = 0;
+	delta.tv_nsec = 0;
+
+	/* Increase 'time' until we reach a second */
+
+	for (; delta.tv_sec < 1 && time < ARGON2_MAX_TIME; time <<= 1) {
+		if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1)
+			goto error;
+		if ((err = argon2_hash(time, mem, ncpus,
+		    tmp_pwd, sizeof(tmp_pwd),
+		    salt, saltlen,
+		    key, keylen,
+		    NULL, 0,
+		    Argon2_id, ARGON2_VERSION_NUMBER)) != ARGON2_OK) {
+			goto error_a2;
+		}
+		if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1)
+			goto error;
+		if (timespeccmp(&tp1, &tp2, >))
+			goto error; /* broken system... */
+		timespecsub(&tp2, &tp1, &delta);
+	}
+
+	if (time > ARGON2_MIN_TIME)
+		time >>= 1;
+
+	free(key);
+	free(salt);
+	*iterations = time;
+	*memory = mem;
+	*parallelism = ncpus;
+	return;
+
+error_a2:
+	errx(EXIT_FAILURE,
+	    "failed to calculate Argon2 hash, error code %d\n", err);
+error:
+	errx(EXIT_FAILURE, "failed to calculate hash parameters");
+}
Index: sbin/cgdconfig/argon2_utils.h
===================================================================
RCS file: sbin/cgdconfig/argon2_utils.h
diff -N sbin/cgdconfig/argon2_utils.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sbin/cgdconfig/argon2_utils.h	8 Nov 2021 13:26:03 -0000
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nia Alarie.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARGON2_UTILS_H
+#define ARGON2_UTILS_H
+#include <stddef.h>
+
+void	argon2id_calibrate(size_t, size_t, size_t *, size_t *, size_t *);
+#endif
Index: sbin/cgdconfig/cgdconfig.8
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/cgdconfig.8,v
retrieving revision 1.50
diff -u -p -r1.50 cgdconfig.8
--- sbin/cgdconfig/cgdconfig.8	30 Apr 2021 21:07:34 -0000	1.50
+++ sbin/cgdconfig/cgdconfig.8	8 Nov 2021 13:26:03 -0000
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd April 18, 2021
+.Dd November 4, 2021
 .Dt CGDCONFIG 8
 .Os
 .Sh NAME
@@ -164,6 +164,13 @@ evaluates all of the key generation meth
 and uses the exclusive-or of the outputs of all the methods.
 The methods and descriptions are as follows:
 .Bl -tag -width indentxxxxxxxxxxx
+.It argon2id
+This method requires a passphrase which is entered at configuration
+time.
+Argon2 is a memory-hard password hashing scheme and winner of the
+2013-2015 Password Hashing Competition.
+It has numerous parameters allowing its hardness to scale with the
+performance of the system.
 .It pkcs5_pbkdf2/sha1
 This method requires a passphrase which is entered at configuration
 time.
@@ -231,8 +238,8 @@ scan for a valid FFS file system.
 .It re-enter
 prompt for passphrase twice, and ensure entered passphrases are
 identical.
-This method only works with the pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2 key
-generators.
+This method only works with the argon2id, pkcs5_pbkdf2/sha1, and
+pkcs5_pbkdf2 key generators.
 .El
 .Ss /etc/cgd/cgd.conf
 The file
@@ -358,10 +365,22 @@ The command to execute.
 Only used for the shell_cmd key generation method.
 .It iterations Ar integer
 The number of iterations.
-Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2.
+Only used for argon2id, pkcs5_pbkdf2/sha1, and pkcs5_pbkdf2.
 .It salt Ar base64
 The salt.
-Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2.
+Only used for argon2id, pkcs5_pbkdf2/sha1, and pkcs5_pbkdf2.
+.It memory Ar integer
+Memory consumption in kilobytes.
+Only used for argon2id.
+.It parallelism Ar integer
+Number of threads to use to compute the password hash.
+Should be equivalent to the number of CPUs/hardware threads.
+Only used for argon2id.
+.It version Ar integer
+Version of Argon2 to use.
+Should be the most recent version, currently
+.Dv 19 .
+Only used for argon2id.
 .El
 .Sh FILES
 .Bl -tag -width indentxxxxxxxxxxxxxxxxxx -compact
@@ -475,6 +494,15 @@ program's execution.
 .Xr fstab 5 ,
 .Xr disklabel 8 ,
 .Xr gpt 8
+.Rs
+.%T "Argon2: the memory-hard function for password hashing and other applications"
+.%A Alex Biryukov
+.%A Daniel Dinu
+.%A Dmitry Khovratovich
+.%D 2017
+.%I University of Luxembourg
+.%U https://www.password-hashing.net/
+.Re
 .Pp
 .Dq PKCS #5 v2.0: Password-Based Cryptography Standard ,
 RSA Laboratories, March 25, 1999.
Index: sbin/cgdconfig/cgdconfig.c
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/cgdconfig.c,v
retrieving revision 1.52
diff -u -p -r1.52 cgdconfig.c
--- sbin/cgdconfig/cgdconfig.c	16 Jun 2021 23:22:08 -0000	1.52
+++ sbin/cgdconfig/cgdconfig.c	8 Nov 2021 13:26:03 -0000
@@ -36,6 +36,9 @@ __COPYRIGHT("@(#) Copyright (c) 2002, 20
 __RCSID("$NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh Exp $");
 #endif
 
+#ifdef HAVE_ARGON2
+#include <argon2.h>
+#endif
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -113,6 +116,9 @@ static void	 eliminate_cores(void);
 static bits_t	*getkey(const char *, struct keygen *, size_t);
 static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
 static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
+#ifdef HAVE_ARGON2
+static bits_t	*getkey_argon2id(const char *, struct keygen *, size_t);
+#endif
 static bits_t	*getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
 				     int);
 static bits_t	*getkey_shell_cmd(const char *, struct keygen *, size_t);
@@ -337,6 +343,11 @@ getkey(const char *dev, struct keygen *k
 		case KEYGEN_URANDOMKEY:
 			tmp = getkey_randomkey(dev, kg, len, 0);
 			break;
+#ifdef HAVE_ARGON2
+		case KEYGEN_ARGON2ID:
+			tmp = getkey_argon2id(dev, kg, len);
+			break;
+#endif
 		case KEYGEN_PKCS5_PBKDF2_SHA1:
 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
 			break;
@@ -454,6 +465,40 @@ getkey_pkcs5_pbkdf2(const char *target, 
 	return ret;
 }
 
+#ifdef HAVE_ARGON2
+static bits_t *
+getkey_argon2id(const char *target, struct keygen *kg, size_t keylen)
+{
+	bits_t *ret;
+	char *passp;
+	char buf[1024];
+	uint8_t	raw[256];
+	int err;
+
+	snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
+	    pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
+	passp = maybe_getpass(buf);
+	if ((err = argon2_hash(kg->kg_iterations, kg->kg_memory,
+	    kg->kg_parallelism,
+	    passp, strlen(passp),
+	    bits_getbuf(kg->kg_salt),
+	    BITS2BYTES(bits_len(kg->kg_salt)),
+	    raw, sizeof(raw),
+	    NULL, 0,
+	    Argon2_id, kg->kg_version)) != ARGON2_OK) {
+		warnx("failed to generate Argon2id key, error code %d", err);
+		return NULL;
+	}
+
+	ret = bits_new(raw, keylen);
+	kg->kg_key = bits_dup(ret);
+	explicit_memset(passp, 0, strlen(passp));
+	explicit_memset(raw, 0, sizeof(raw));
+	free(passp);
+	return ret;
+}
+#endif
+
 /*ARGSUSED*/
 static bits_t *
 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
@@ -606,8 +651,9 @@ configure(int argc, char **argv, struct 
 	for (kg = p->keygen;
 	    (pflag & PFLAG_GETPASS_MASK) && kg;
 	    kg = kg->next)
-		if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
-		    (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
+		if (kg->kg_method == KEYGEN_ARGON2ID ||
+		    kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1 ||
+		    kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD) {
 			loop = 1;
 			break;
 		}
@@ -984,22 +1030,39 @@ static int
 verify_reenter(struct params *p)
 {
 	struct keygen *kg;
-	bits_t *orig_key, *key;
+	bits_t *orig_key, *key = NULL;
 	int ret;
 
 	ret = 0;
 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
-		if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
-		    (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
+		if (kg->kg_method != KEYGEN_ARGON2ID &&
+		    kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1 &&
+		    kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD)
 			continue;
 
 		orig_key = kg->kg_key;
 		kg->kg_key = NULL;
 
-		/* add a compat flag till the _OLD method goes away */
-		key = getkey_pkcs5_pbkdf2("re-enter device", kg,
-			bits_len(orig_key),
-			kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
+		switch (kg->kg_method) {
+#ifdef HAVE_ARGON2
+		case KEYGEN_ARGON2ID:
+			key = getkey_argon2id("re-enter device", kg,
+				bits_len(orig_key));
+			break;
+#endif
+		case KEYGEN_PKCS5_PBKDF2_SHA1:
+			key = getkey_pkcs5_pbkdf2("re-enter device", kg,
+				bits_len(orig_key), 0);
+			break;
+		case KEYGEN_PKCS5_PBKDF2_OLD:
+			key = getkey_pkcs5_pbkdf2("re-enter device", kg,
+				bits_len(orig_key), 1);
+			break;
+		default:
+			warnx("unsupported keygen method");
+			kg->kg_key = orig_key;
+			return -1;
+		}
 
 		ret = !bits_match(key, orig_key);
 
Index: sbin/cgdconfig/cgdlex.l
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/cgdlex.l,v
retrieving revision 1.5
diff -u -p -r1.5 cgdlex.l
--- sbin/cgdconfig/cgdlex.l	29 Oct 2009 14:49:03 -0000	1.5
+++ sbin/cgdconfig/cgdlex.l	8 Nov 2021 13:26:03 -0000
@@ -98,6 +98,9 @@ verify_method				{ RETTOKEN(VERIFY_METHO
 keygen					{ RETTOKEN(KEYGEN); }
 salt					{ RETTOKEN(SALT); }
 iterations				{ RETTOKEN(ITERATIONS); }
+memory					{ RETTOKEN(MEMORY); }
+parallelism				{ RETTOKEN(PARALLELISM); }
+version					{ RETTOKEN(VERSION); }
 key					{ RETTOKEN(KEY); }
 cmd					{ RETTOKEN(CMD); }
 keygen_method				{ RETTOKEN(KEYGEN_METHOD); }
Index: sbin/cgdconfig/cgdparse.y
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/cgdparse.y,v
retrieving revision 1.5
diff -u -p -r1.5 cgdparse.y
--- sbin/cgdconfig/cgdparse.y	17 Jul 2008 16:24:55 -0000	1.5
+++ sbin/cgdconfig/cgdparse.y	8 Nov 2021 13:26:03 -0000
@@ -67,7 +67,7 @@ static struct params *yy_global_params;
 %token <string> STRINGLIT
 
 %token <token> ALGORITHM KEYLENGTH IVMETHOD VERIFY_METHOD
-%token <token> KEYGEN SALT ITERATIONS KEY CMD
+%token <token> KEYGEN SALT ITERATIONS MEMORY PARALLELISM VERSION KEY CMD
 
 %token EOL
 
@@ -99,6 +99,9 @@ kgvars: /* empty */			{ $$ = NULL; }
 
 kgvar:	  SALT bits EOL			{ $$ = keygen_salt($2); }
 	| ITERATIONS INTEGER EOL	{ $$ = keygen_iterations($2); }
+	| MEMORY INTEGER EOL		{ $$ = keygen_memory($2); }
+	| PARALLELISM INTEGER EOL	{ $$ = keygen_parallelism($2); }
+	| VERSION INTEGER EOL		{ $$ = keygen_version($2); }
 	| KEY bits EOL			{ $$ = keygen_key($2); }
 	| CMD stringlit EOL		{ $$ = keygen_cmd($2); }
 	| EOL				{ $$ = NULL; }
Index: sbin/cgdconfig/params.c
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/params.c,v
retrieving revision 1.31
diff -u -p -r1.31 params.c
--- sbin/cgdconfig/params.c	3 Jun 2021 15:40:27 -0000	1.31
+++ sbin/cgdconfig/params.c	8 Nov 2021 13:26:03 -0000
@@ -45,6 +45,11 @@ __RCSID("$NetBSD: params.c,v 1.31 2021/0
 #include <string.h>
 #include <util.h>
 
+#ifdef HAVE_ARGON2
+#include <argon2.h>
+#include "argon2_utils.h"
+#endif
+
 #include "params.h"
 #include "pkcs5_pbkdf2.h"
 #include "utils.h"
@@ -314,6 +319,9 @@ keygen_new(void)
 	kg = emalloc(sizeof(*kg));
 	kg->kg_method = KEYGEN_UNKNOWN;
 	kg->kg_iterations = (size_t)-1;
+	kg->kg_memory = (size_t)-1;
+	kg->kg_parallelism = (size_t)-1;
+	kg->kg_version = (size_t)-1;
 	kg->kg_salt = NULL;
 	kg->kg_key = NULL;
 	kg->kg_cmd = NULL;
@@ -346,6 +354,34 @@ keygen_verify(const struct keygen *kg)
 	if (!kg)
 		return 1;
 	switch (kg->kg_method) {
+#ifdef HAVE_ARGON2
+	case KEYGEN_ARGON2ID:
+		if (kg->kg_iterations == (size_t)-1) {
+			warnx("keygen argon2id must provide `iterations'");
+			return 0;
+		}
+		if (kg->kg_memory == (size_t)-1) {
+			warnx("keygen argon2id must provide `memory'");
+			return 0;
+		}
+		if (kg->kg_parallelism == (size_t)-1) {
+			warnx("keygen argon2id must provide `parallelism'");
+			return 0;
+		}
+		if (kg->kg_version == (size_t)-1) {
+			warnx("keygen argon2id must provide `version'");
+			return 0;
+		}
+		if (kg->kg_cmd)
+			warnx("keygen argon2id does not need a `cmd'");
+		if (kg->kg_key)
+			warnx("keygen argon2id does not need a `key'");
+		if (!kg->kg_salt) {
+			warnx("keygen argon2id must provide a salt");
+			return 0;
+		}
+		break;
+#endif
 	case KEYGEN_PKCS5_PBKDF2_OLD:
 		if (kg->kg_iterations == (size_t)-1) {
 			warnx("keygen pkcs5_pbkdf2 must provide `iterations'");
@@ -445,6 +481,14 @@ keygen_filldefaults(struct keygen *kg, s
 	case KEYGEN_URANDOMKEY:
 	case KEYGEN_SHELL_CMD:
 		break;
+#ifdef HAVE_ARGON2
+	case KEYGEN_ARGON2ID:
+		kg->kg_version = ARGON2_VERSION_NUMBER;
+		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
+		argon2id_calibrate(BITS2BYTES(keylen), DEFAULT_SALTLEN,
+		    &kg->kg_iterations, &kg->kg_memory, &kg->kg_parallelism);
+		break;
+#endif
 	case KEYGEN_PKCS5_PBKDF2_OLD:
 	case KEYGEN_PKCS5_PBKDF2_SHA1:
 		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
@@ -488,6 +532,15 @@ keygen_combine(struct keygen *kg1, struc
 	if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0)
 		kg1->kg_iterations = kg2->kg_iterations;
 
+	if (kg2->kg_memory != (size_t)-1 && kg2->kg_memory > 0)
+		kg1->kg_memory = kg2->kg_memory;
+
+	if (kg2->kg_parallelism != (size_t)-1 && kg2->kg_parallelism > 0)
+		kg1->kg_parallelism = kg2->kg_parallelism;
+
+	if (kg2->kg_version != (size_t)-1 && kg2->kg_version > 0)
+		kg1->kg_version = kg2->kg_version;
+
 	if (kg2->kg_salt)
 		bits_assign(&kg1->kg_salt, kg2->kg_salt);
 
@@ -506,6 +559,10 @@ keygen_method(string_t *in)
 	struct keygen *kg = keygen_new();
 	const char *kgm = string_tocharstar(in);
 
+#ifdef HAVE_ARGON2
+	if (!strcmp("argon2id", kgm))
+		kg->kg_method = KEYGEN_ARGON2ID;
+#endif
 	if (!strcmp("pkcs5_pbkdf2", kgm))
 		kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD;
 	if (!strcmp("pkcs5_pbkdf2/sha1", kgm))
@@ -551,6 +608,33 @@ keygen_iterations(size_t in)
 	return kg;
 }
 
+struct keygen *
+keygen_memory(size_t in)
+{
+	struct keygen *kg = keygen_new();
+
+	kg->kg_memory = in;
+	return kg;
+}
+
+struct keygen *
+keygen_parallelism(size_t in)
+{
+	struct keygen *kg = keygen_new();
+
+	kg->kg_parallelism = in;
+	return kg;
+}
+
+struct keygen *
+keygen_version(size_t in)
+{
+	struct keygen *kg = keygen_new();
+
+	kg->kg_version = in;
+	return kg;
+}
+
 void
 keygen_addlist(struct keygen **l, struct keygen *e)
 {
@@ -743,6 +827,17 @@ keygen_fput(struct keygen *kg, int ts, F
 	case KEYGEN_URANDOMKEY:
 		(void)fprintf(f, "urandomkey;\n");
 		break;
+#ifdef HAVE_ARGON2
+	case KEYGEN_ARGON2ID:
+		(void)fprintf(f, "argon2id {\n");
+		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
+		print_kvpair_int(f, ts, "memory", kg->kg_memory);
+		print_kvpair_int(f, ts, "parallelism", kg->kg_parallelism);
+		print_kvpair_int(f, ts, "version", kg->kg_version);
+		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
+		(void)fprintf(f, "};\n");
+		break;
+#endif
 	case KEYGEN_PKCS5_PBKDF2_OLD:
 		(void)fprintf(f, "pkcs5_pbkdf2 {\n");
 		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
Index: sbin/cgdconfig/params.h
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/params.h,v
retrieving revision 1.11
diff -u -p -r1.11 params.h
--- sbin/cgdconfig/params.h	14 Dec 2014 12:31:39 -0000	1.11
+++ sbin/cgdconfig/params.h	8 Nov 2021 13:26:03 -0000
@@ -37,6 +37,9 @@
 struct keygen {
 	int		 kg_method;
 	size_t		 kg_iterations;
+	size_t		 kg_memory;		/* only used for Argon2 */
+	size_t		 kg_parallelism;	/* only used for Argon2 */
+	size_t		 kg_version;		/* only used for Argon2 */
 	bits_t		*kg_salt;
 	bits_t		*kg_key;
 	string_t	*kg_cmd;
@@ -63,6 +66,7 @@ struct params {
 #define KEYGEN_URANDOMKEY		0x4
 #define KEYGEN_PKCS5_PBKDF2_SHA1	0x5
 #define KEYGEN_SHELL_CMD		0x6
+#define KEYGEN_ARGON2ID			0x7
 
 /* verification methods */
 
@@ -108,6 +112,9 @@ struct keygen	*keygen_method(string_t *)
 struct keygen	*keygen_set_method(struct keygen *, string_t *);
 struct keygen	*keygen_salt(bits_t *);
 struct keygen	*keygen_iterations(size_t);
+struct keygen	*keygen_memory(size_t);
+struct keygen	*keygen_parallelism(size_t);
+struct keygen	*keygen_version(size_t);
 struct keygen	*keygen_key(bits_t *);
 struct keygen	*keygen_cmd(string_t *);
 


Home | Main Index | Thread Index | Old Index