tech-crypto 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 Fri, Nov 05, 2021 at 11:19:33PM +0000, Taylor R Campbell wrote:
> (For future patches: please use the `-p' option with cvs diff!)

Today I learned something new!

> It looks like we'll descend into external/apache2/argon2 twice this
> way.  Am I mistaken?  Is this intentional?

Uh, not intentional.

> > --- sbin/cgdconfig/Makefile	1 Jul 2016 22:50:09 -0000	1.15
> > +++ sbin/cgdconfig/Makefile	5 Nov 2021 15:41:43 -0000
> > [...]
> > +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
> > +LDADD+=		-Wl,-Bstatic
> > +LDADD+=		-L${ARGON2OBJDIR} -largon2
> > +LDADD+=		-Wl,-Bdynamic
> > +LDADD+=		-pthread
> > +DPADD+=		${ARGON2OBJDIR}/libargon2.a ${LIBPTHREAD}
> 
> Can this be made to use LIBDPLIBS, or are there too many moving parts
> here?

It can use PROGDPLIBS. Again, today I learned something new.
But it doesn't simplify the thing by much.

> Missing __RCSID in body of .c file?

Yeah, sigh. Let's remove this stuff already :p

> > +	uint8_t tmp_pwd[17];
> > +	char tmp_encoded[512];
> 
> Where do these magic constants come from?  Can they be named or made
> more obvious?

tmp_pwd is "generic random data used only for stress testing".
I'll note that in a comment.

tmp_encoded can be removed, see below.

> > +	char encoded[512];
> 
> Is it necessary to pass this in?  We're not using it; can we pass in
> null instead so argon2 doesn't bother to encode it?

Apparently yes! I thought it was mandatory, but that makes
little sense. Thanks.

> Missing include guard.

Ja.

> I wonder whether this can nicely be made a little more obvious, like
> 
> 	memory 123M;
> 
> or something.
> 
> I wonder whether cgdconfig -g/-G could have an option to specify the
> percentage of RAM.

It would be nice but also I wonder the value of specifying custom
RAM amounts. There's an upper limit to how much you can use before
the algorithm becomes seriously slow and the default I've picked is
nearing it on the machines I've tested.

> Why dup what you just created?  Why not kg->kg_key = bits_new(raw,
> keylen)?  This looks like a (minor) memory leak.

This is what the existing code for pkcs5_pbkdf2/sha1 does. I believe
that the returned pointer (raw) is immediately freed after being
compared by the consumer.

> Would be nice if we had automatic tests for cgdconfig -g/-G.

Agree.
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	6 Nov 2021 00:17:47 -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	6 Nov 2021 00:17:47 -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	6 Nov 2021 00:17:47 -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,18 @@ 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
+
+LDADD+=		-Wl,-Bstatic
+PROGDPLIBS+=	argon2 ${ARGON2DIR}/lib/libargon2
+LDADD+=		-Wl,-Bdynamic
+
+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	6 Nov 2021 00:17:48 -0000
@@ -0,0 +1,168 @@
+/*	$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 1;
+	}
+
+	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 = 256;
+	size_t time = 1;
+	const size_t ncpus = get_cpucount();
+	const uint64_t usermem = get_usermem();
+	struct rusage ru1, ru2;
+	struct timeval 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;
+
+	arc4random_buf(tmp_pwd, sizeof(tmp_pwd));
+
+	key = emalloc(keylen);
+	arc4random_buf(key, keylen);
+
+	salt = emalloc(saltlen);
+	arc4random_buf(salt, saltlen);
+
+	mem = usermem / 100000;
+
+	if (mem < ARGON2_MIN_MEMORY)
+		mem = 256;
+
+	/* Decrease 'mem' if it slows down computation too much */
+
+	do {
+		if (getrusage(RUSAGE_SELF, &ru1) == -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 (getrusage(RUSAGE_SELF, &ru2) == -1)
+			goto error;
+		timersub(&ru2.ru_utime, &ru1.ru_utime, &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);
+
+	/* Increase 'time' until we reach a second */
+
+	delta.tv_sec = 0;
+	delta.tv_usec = 0;
+
+	if (getrusage(RUSAGE_SELF, &ru1) == -1)
+		goto error;
+
+	for (; delta.tv_sec < 1 && time < ARGON2_MAX_TIME; ++time) {
+		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 (getrusage(RUSAGE_SELF, &ru2) == -1)
+			goto error;
+		timersub(&ru2.ru_utime, &ru1.ru_utime, &delta);
+	}
+
+	if (time > 1)
+		time--;
+
+	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	6 Nov 2021 00:17:48 -0000
@@ -0,0 +1,34 @@
+/*-
+ * 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
+
+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	6 Nov 2021 00:17:48 -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	6 Nov 2021 00:17:48 -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	6 Nov 2021 00:17:48 -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	6 Nov 2021 00:17:48 -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	6 Nov 2021 00:17:48 -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	6 Nov 2021 00:17:48 -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