Module Name:    src
Committed By:   jhigh
Date:           Mon Oct 21 02:36:48 UTC 2019

Modified Files:
        src/external/apache2/argon2/lib/libargon2: Makefile
        src/external/apache2/argon2/usr.bin/argon2: Makefile
        src/lib/libcrypt: Makefile crypt.3 crypt.c crypt.h pw_gensalt.c
        src/usr.bin/pwhash: Makefile pwhash.1 pwhash.c
Added Files:
        src/lib/libcrypt: crypt-argon2.c

Log Message:
adding argon2 support to libcrypt. argon2 user authentication now
available via MKARGON2=yes (3 variants supported; argon2id recommended)
before using, please read argon2 paper at
https://github.com/P-H-C/phc-winner-argon2


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/external/apache2/argon2/lib/libargon2/Makefile
cvs rdiff -u -r1.1 -r1.2 src/external/apache2/argon2/usr.bin/argon2/Makefile
cvs rdiff -u -r1.25 -r1.26 src/lib/libcrypt/Makefile
cvs rdiff -u -r0 -r1.1 src/lib/libcrypt/crypt-argon2.c
cvs rdiff -u -r1.27 -r1.28 src/lib/libcrypt/crypt.3
cvs rdiff -u -r1.35 -r1.36 src/lib/libcrypt/crypt.c
cvs rdiff -u -r1.4 -r1.5 src/lib/libcrypt/crypt.h
cvs rdiff -u -r1.7 -r1.8 src/lib/libcrypt/pw_gensalt.c
cvs rdiff -u -r1.7 -r1.8 src/usr.bin/pwhash/Makefile
cvs rdiff -u -r1.8 -r1.9 src/usr.bin/pwhash/pwhash.1
cvs rdiff -u -r1.15 -r1.16 src/usr.bin/pwhash/pwhash.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/apache2/argon2/lib/libargon2/Makefile
diff -u src/external/apache2/argon2/lib/libargon2/Makefile:1.1 src/external/apache2/argon2/lib/libargon2/Makefile:1.2
--- src/external/apache2/argon2/lib/libargon2/Makefile:1.1	Wed Oct  9 13:13:09 2019
+++ src/external/apache2/argon2/lib/libargon2/Makefile	Mon Oct 21 02:36:48 2019
@@ -12,15 +12,7 @@ INCSDIR=	/usr/include
 LIB=	argon2	
 SRCS=	argon2.c core.c blake2b.c thread.c encoding.c ref.c
 
-
-CPPFLAGS= -std=c89 -O3 -Wall -g -I../../dist/phc-winner-argon2/include -Isrc -shared -fPIC
-
-.ifdef NO_THREADS
-CPPFLAGS += -DARGON2_NO_THREADS
-.else
-CPPFLAGS += -pthread
-LDADD+=-lpthread
-.endif
+CPPFLAGS= -std=c89 -O3 -Wall -g -I../../dist/phc-winner-argon2/include -Isrc -fPIC -DARGON2_NO_THREADS
 
 OPTTARGET ?= native
 OPTTEST := $(shell $(CC) -Iinclude -Isrc -march=$(OPTTARGET) src/opt.c -c \

Index: src/external/apache2/argon2/usr.bin/argon2/Makefile
diff -u src/external/apache2/argon2/usr.bin/argon2/Makefile:1.1 src/external/apache2/argon2/usr.bin/argon2/Makefile:1.2
--- src/external/apache2/argon2/usr.bin/argon2/Makefile:1.1	Wed Oct  9 13:13:10 2019
+++ src/external/apache2/argon2/usr.bin/argon2/Makefile	Mon Oct 21 02:36:48 2019
@@ -10,16 +10,7 @@ SRCS=
 SRCS=   argon2.c core.c blake2b.c thread.c encoding.c ref.c
 SRCS+=   run.c
 
-.ifdef NO_THREADS 
-CPPFLAGS += -DARGON2_NO_THREADS
-.else
-CPPFLAGS += -pthread
-LDADD+=-lpthread
-.endif
-
-CPPFLAGS+= -std=c89 -O3 -Wall -g -I../../dist/phc-winner-argon2/include -Isrc #-shared -fPIC
-#LDADD+= -L${LIBARGON2} -largon2
-#DPADD+= ${LIBARGON2_SD}
+CPPFLAGS+= -DARGON2_NO_THREADS -std=c89 -O3 -Wall -g -I../../dist/phc-winner-argon2/include -Isrc 
 
 MAN=argon2.1
 

Index: src/lib/libcrypt/Makefile
diff -u src/lib/libcrypt/Makefile:1.25 src/lib/libcrypt/Makefile:1.26
--- src/lib/libcrypt/Makefile:1.25	Sat Aug 10 18:42:29 2013
+++ src/lib/libcrypt/Makefile	Mon Oct 21 02:36:48 2019
@@ -1,12 +1,24 @@
-#	$NetBSD: Makefile,v 1.25 2013/08/10 18:42:29 dholland Exp $
+#	$NetBSD: Makefile,v 1.26 2019/10/21 02:36:48 jhigh Exp $
+
+.include <bsd.own.mk>
 
 USE_SHLIBDIR=	yes
 
+.if (defined(MKARGON2) && ${MKARGON2} != "no")
+HAVE_ARGON2=1
+.endif
+
 LIB=	crypt
 
 SRCS=	crypt.c md5crypt.c bcrypt.c crypt-sha1.c util.c pw_gensalt.c
 SRCS+=	hmac_sha1.c
 
+.if defined(HAVE_ARGON2)
+SRCS+=		crypt-argon2.c
+CFLAGS+=	-DHAVE_ARGON2 -I../../external/apache2/argon2/dist/phc-winner-argon2/include/
+LDADD+=		-largon2 
+.endif
+
 WARNS?=	5
 
 MAN=	crypt.3

Index: src/lib/libcrypt/crypt.3
diff -u src/lib/libcrypt/crypt.3:1.27 src/lib/libcrypt/crypt.3:1.28
--- src/lib/libcrypt/crypt.3:1.27	Fri Mar 23 18:08:35 2012
+++ src/lib/libcrypt/crypt.3	Mon Oct 21 02:36:48 2019
@@ -1,4 +1,4 @@
-.\"	$NetBSD: crypt.3,v 1.27 2012/03/23 18:08:35 njoly Exp $
+.\"	$NetBSD: crypt.3,v 1.28 2019/10/21 02:36:48 jhigh Exp $
 .\"
 .\" Copyright (c) 1989, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -241,6 +241,25 @@ A valid password looks like this:
 The entire password string is passed as
 .Fa setting
 for interpretation.
+
+.Ss Argon2 encryption
+
+Argon2 is a memory-hard hashing algorithm. crypt() provides all 
+three variants: argon2i, argon2d, and argon2id. It is recommended 
+to use argon2id, which provides a hybrid combination using argon2i 
+on the first pass, and argon2d on the remaining passes.  We 
+parameterize on three variables.  First, m_cost (m), specifies the 
+memory usage in KB.  Second, t_cost (t), specfies the number of 
+iterations.  Third, parallelism (p) specifies the number of threads.  
+A valid Argon2 encoded password looks similar to 
+
+$argon2id$v=19$m=4096,t=6,p=1$qCatF9a1s/6TgcYB$ \
+   yeYYrU/rh7E+LI2CAeHTSHVB3iO+OXiNIUHu6NPeTfo
+
+containing five fields delimited by '$'. The fields, in order, are 
+variant name, version, parameter set , 128-bit salt, and encoded password. 
+The complete password string is required to be processed correctly. 
+
 .Ss "Blowfish" crypt
 The
 .Tn Blowfish
@@ -338,20 +357,14 @@ Historically, the functions
 and
 .Fn encrypt
 did not return any value.
-They have been provided return values primarily to distinguish
+Theyave been provided return values primarily to distinguish
 implementations where hardware support is provided but not
 available or where the DES encryption is not available due to the
 usual political silliness.
 .Sh SEE ALSO
 .Xr login 1 ,
 .Xr passwd 1 ,
-.Xr pwhash 1 ,
-.Xr getpass 3 ,
-.Xr md5 3 ,
-.Xr passwd 5 ,
-.Xr passwd.conf 5
-.Rs
-.%T "Mathematical Cryptology for Computer Scientists and Mathematicians"
+.Xr cal Cryptology for Computer Scientists and Mathematicians"
 .%A Wayne Patterson
 .%D 1987
 .%N ISBN 0-8476-7438-X
@@ -363,14 +376,7 @@ usual political silliness.
 .%J "Communications of the ACM"
 .%V vol. 22
 .%P pp. 594-597
-.%D Nov. 1979
-.Re
-.Rs
-.%T "DES will be Totally Insecure within Ten Years"
-.%A M.E. Hellman
-.%J "IEEE Spectrum"
-.%V vol. 16
-.%P pp. 32-39
+.%D N pp. 32-39
 .%D July 1979
 .Re
 .Sh HISTORY
@@ -387,7 +393,7 @@ Dropping the
 .Em least
 significant bit in each character of the argument to
 .Fn des_setkey
-is ridiculous.
+is ri
 .Pp
 The
 .Fn crypt

Index: src/lib/libcrypt/crypt.c
diff -u src/lib/libcrypt/crypt.c:1.35 src/lib/libcrypt/crypt.c:1.36
--- src/lib/libcrypt/crypt.c:1.35	Sat Oct  5 18:06:16 2019
+++ src/lib/libcrypt/crypt.c	Mon Oct 21 02:36:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: crypt.c,v 1.35 2019/10/05 18:06:16 jhigh Exp $	*/
+/*	$NetBSD: crypt.c,v 1.36 2019/10/21 02:36:48 jhigh Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)crypt.c	8.1.1.1 (Berkeley) 8/18/93";
 #else
-__RCSID("$NetBSD: crypt.c,v 1.35 2019/10/05 18:06:16 jhigh Exp $");
+__RCSID("$NetBSD: crypt.c,v 1.36 2019/10/21 02:36:48 jhigh Exp $");
 #endif
 #endif /* not lint */
 
@@ -575,6 +575,18 @@ __crypt(const char *key, const char *set
 		} else if (strcmp(scheme, "1") == 0) {
 		     /* $1$ found in pw_gensalt.c:__gensalt_md5 */
 			return (__md5crypt(key, setting));
+#ifdef HAVE_ARGON2
+		/* explicit argon2 variant */
+		} else if (strcmp(scheme, "argon2id") == 0) {
+		     /* $argon2id$ found in pw_gensalt.c:__gensalt_argon2 */
+			return (__crypt_argon2(key, setting));
+		} else if (strcmp(scheme, "argon2i") == 0) {
+		     /* $argon2i$ found in pw_gensalt.c:__gensalt_argon2 */
+			return (__crypt_argon2(key, setting));
+		} else if (strcmp(scheme, "argon2d") == 0) {
+		     /* $argon2d$ found in pw_gensalt.c:__gensalt_argon2 */
+			return (__crypt_argon2(key, setting));
+#endif /* HAVE_ARGON2 */
 		} else {
 		     /* invalid scheme, including empty string */
 			return NULL;
@@ -675,6 +687,7 @@ char *
 crypt(const char *key, const char *salt)
 {
 	char *res = __crypt(key, salt);
+
 	if (res)
 		return res;
 	/* How do I handle errors ? Return "*0" or "*1" */

Index: src/lib/libcrypt/crypt.h
diff -u src/lib/libcrypt/crypt.h:1.4 src/lib/libcrypt/crypt.h:1.5
--- src/lib/libcrypt/crypt.h:1.4	Fri Oct 27 18:22:56 2006
+++ src/lib/libcrypt/crypt.h	Mon Oct 21 02:36:48 2019
@@ -1,5 +1,5 @@
 /*
- * $NetBSD: crypt.h,v 1.4 2006/10/27 18:22:56 drochner Exp $
+ * $NetBSD: crypt.h,v 1.5 2019/10/21 02:36:48 jhigh Exp $
  */
 char	*__md5crypt(const char *pw, const char *salt);	/* XXX */
 char *__bcrypt(const char *, const char *);	/* XXX */
@@ -9,6 +9,13 @@ void __hmac_sha1(const unsigned char *, 
 		 unsigned char *);
 void __crypt_to64(char *s, u_int32_t v, int n);
 
+#ifdef HAVE_ARGON2
+char *__crypt_argon2(const char *pw, const char *salt);
+int __gensalt_argon2id(char *salt, size_t saltsiz, const char *option);
+int __gensalt_argon2i(char *salt, size_t saltsiz, const char *option);
+int __gensalt_argon2d(char *salt, size_t saltsiz, const char *option);
+#endif /* HAVE_ARGON2 */
+
 int __gensalt_blowfish(char *salt, size_t saltlen, const char *option);
 int __gensalt_old(char *salt, size_t saltsiz, const char *option);
 int __gensalt_new(char *salt, size_t saltsiz, const char *option);

Index: src/lib/libcrypt/pw_gensalt.c
diff -u src/lib/libcrypt/pw_gensalt.c:1.7 src/lib/libcrypt/pw_gensalt.c:1.8
--- src/lib/libcrypt/pw_gensalt.c:1.7	Sun Jan 18 12:15:27 2009
+++ src/lib/libcrypt/pw_gensalt.c	Mon Oct 21 02:36:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $	*/
+/*	$NetBSD: pw_gensalt.c,v 1.8 2019/10/21 02:36:48 jhigh Exp $	*/
 
 /*
  * Copyright 1997 Niels Provos <pro...@physnet.uni-hamburg.de>
@@ -34,7 +34,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $");
+__RCSID("$NetBSD: pw_gensalt.c,v 1.8 2019/10/21 02:36:48 jhigh Exp $");
 #endif /* not lint */
 
 #include <sys/syslimits.h>
@@ -53,6 +53,13 @@ __RCSID("$NetBSD: pw_gensalt.c,v 1.7 200
 
 #include "crypt.h"
 
+#ifdef HAVE_ARGON2
+#include <argon2.h>
+#define ARGON2_ARGON2_STR       "argon2"
+#define ARGON2_ARGON2I_STR      "argon2i"
+#define ARGON2_ARGON2D_STR      "argon2d"
+#define ARGON2_ARGON2ID_STR     "argon2id"
+#endif /* HAVE_ARGON2 */
 
 static const struct pw_salt {
 	const char *name;
@@ -64,6 +71,13 @@ static const struct pw_salt {
 	{ "md5", __gensalt_md5 },
 	{ "sha1", __gensalt_sha1 },
 	{ "blowfish", __gensalt_blowfish },
+#ifdef HAVE_ARGON2
+	/* argon2 default to argon2id */
+	{ "argon2", __gensalt_argon2id},
+	{ "argon2id", __gensalt_argon2id},
+	{ "argon2i", __gensalt_argon2i},
+	{ "argon2d", __gensalt_argon2d},
+#endif /* HAVE_ARGON2 */
 	{ NULL, NULL }
 };
 
@@ -171,6 +185,120 @@ __gensalt_sha1(char *salt, size_t saltsi
 	return 0;
 }
 
+#ifdef HAVE_ARGON2
+static int __gensalt_argon2_decode_option(char * dst, size_t dlen, const char * option)
+{
+
+	char * in = 0;;
+	char * a = 0;
+	size_t tmp = 0;
+	int error = 0;
+	/* ob buffer: m_cost, t_cost, threads */
+	uint32_t ob[3] = {4096, 3, 1}; 
+
+	memset(dst, 0, dlen);
+
+	if (option == NULL) {
+		goto done;
+	}
+
+	in = (char *)strdup(option);
+
+	while ((a = strsep(&in, ",")) != NULL) {
+		switch(*a) {
+
+			case 'm':
+				a += strlen("m=");
+				if ((getnum(a, &tmp)) == -1) {
+					--error;
+				} else {
+					ob[0] = tmp;
+				}
+
+				break;
+			case 't':
+				a += strlen("t=");
+				if ((getnum(a, &tmp)) == -1) {
+					--error;
+				} else {
+					ob[1] = tmp;
+				}
+
+				break;
+			case 'p':
+				a += strlen("p=");
+				if ((getnum(a, &tmp)) == -1) {
+					--error;
+				} else {
+					ob[2] = tmp;
+				}
+
+				break;
+			default:
+				--error;
+		}
+	}
+
+	free(in);
+done:
+	snprintf(dst, dlen, "m=%d,t=%d,p=%d", ob[0], ob[1], ob[2]);
+
+	return error;
+}
+
+
+static int
+__gensalt_argon2(char *salt, size_t saltsiz, const char *option,argon2_type atype)
+{
+	int rc;
+	int n;
+	char buf[64];
+
+	/* get param, enforcing order and applying defaults */
+	if ((rc = __gensalt_argon2_decode_option(buf, sizeof(buf), option)) < 0) {
+		return 0;
+	}
+
+	n = snprintf(salt, saltsiz, "$%s$v=%d$%s$", 
+		argon2_type2string(atype,0), ARGON2_VERSION_NUMBER, buf);
+
+	if ((size_t)n + 16 >= saltsiz) {
+		return 0;
+	}
+
+	__crypt_to64(&salt[n], arc4random(), 4);
+	__crypt_to64(&salt[n + 4], arc4random(), 4);
+	__crypt_to64(&salt[n + 8], arc4random(), 4);
+	__crypt_to64(&salt[n + 12], arc4random(), 4);
+
+	salt[n + 16] = '$';
+	salt[n + 17] = '\0';
+
+	return 0;
+}
+
+/* argon2 variant-specific hooks to generic */
+int
+__gensalt_argon2id(char *salt, size_t saltsiz, const char *option)
+{
+	return __gensalt_argon2(salt, saltsiz, option, Argon2_id);
+}
+
+int
+__gensalt_argon2i(char *salt, size_t saltsiz, const char *option)
+{
+	return __gensalt_argon2(salt, saltsiz, option, Argon2_i);
+}
+
+int
+__gensalt_argon2d(char *salt, size_t saltsiz, const char *option)
+{
+	return __gensalt_argon2(salt, saltsiz, option, Argon2_d);
+}
+
+#endif /* HAVE_ARGON2 */
+
+
 int
 pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option)
 {

Index: src/usr.bin/pwhash/Makefile
diff -u src/usr.bin/pwhash/Makefile:1.7 src/usr.bin/pwhash/Makefile:1.8
--- src/usr.bin/pwhash/Makefile:1.7	Tue Apr 14 22:15:25 2009
+++ src/usr.bin/pwhash/Makefile	Mon Oct 21 02:36:48 2019
@@ -1,10 +1,14 @@
-#	$NetBSD: Makefile,v 1.7 2009/04/14 22:15:25 lukem Exp $
+#	$NetBSD: Makefile,v 1.8 2019/10/21 02:36:48 jhigh Exp $
 #	from: @(#)Makefile    8.3 (Berkeley) 4/2/94
 
 .include <bsd.own.mk>
 
 PROG=	pwhash
 
+.if ( defined(MKARGON2) && ${MKARGON2} != "no" )
+CPPFLAGS+=	-DHAVE_ARGON2
+.endif
+
 CPPFLAGS+=-I${.CURDIR} -DLOGIN_CAP
 
 DPADD+= ${LIBCRYPT} ${LIBUTIL}

Index: src/usr.bin/pwhash/pwhash.1
diff -u src/usr.bin/pwhash/pwhash.1:1.8 src/usr.bin/pwhash/pwhash.1:1.9
--- src/usr.bin/pwhash/pwhash.1:1.8	Tue May 24 06:15:43 2016
+++ src/usr.bin/pwhash/pwhash.1	Mon Oct 21 02:36:48 2019
@@ -1,4 +1,4 @@
-.\"	$NetBSD: pwhash.1,v 1.8 2016/05/24 06:15:43 abhinav Exp $
+.\"	$NetBSD: pwhash.1,v 1.9 2019/10/21 02:36:48 jhigh Exp $
 .\"	$OpenBSD: encrypt.1,v 1.16 2000/11/09 17:52:07 aaron Exp $
 .\"
 .\" Copyright (c) 1996, Jason Downs.  All rights reserved.
@@ -33,6 +33,7 @@
 .Sh SYNOPSIS
 .Nm pwhash
 .Op Fl km
+.Op Fl A Ar variant[,params] 
 .Op Fl b Ar rounds
 .Op Fl S Ar rounds
 .Op Fl s Ar salt
@@ -64,6 +65,26 @@ Prompt for a single string with echo tur
 Encrypt the salt with HMAC-SHA1 using the password as key and the specified
 .Ar rounds
 as a hint for the number of iterations.
+.It Fl A Ar variant[,params] 
+Encrypt the specified string using Argon2 hashing parameterized using
+variant 
+.Ar variant , 
+where 
+.Ar variant 
+is one of the following: argon2id, argon2i, argon2d.  Variant
+.Ar argon2id
+is recommended.
+
+Following the required 
+.Ar variant 
+name, three optional comma-delimited parameters may be provided,
+
+t=n Specify the number of iterations to n.  The default is 3.
+
+m=n Specify the memory usage in KB  to n. The default is 4096.
+
+p=n Specify the number of threads to n. The default is 1.
+
 .It Fl s Ar salt
 Encrypt the string using DES, with the specified
 .Ar salt .
@@ -80,13 +101,19 @@ the algorithm specified in the default c
 .Pa /etc/passwd.conf
 will be used.
 .Pp
-For MD5 and Blowfish a new random salt is automatically generated for each
+For MD5,  Blowfish, and Argon2 a new random salt is automatically generated for each
 password.
 .Pp
 Specifying the
 .Ar string
 on the command line should be discouraged; using the
 standard input is more secure.
+.Sh EXAMPLES
+The following specifies the argon2id variant, using 1 thread and 4096KB of memory 
+
+pwhash -A argon2id,p=1,m=4096 -p
+
+
 .Sh FILES
 .Bl -tag -width /etc/passwd.conf -compact
 .It Pa /etc/passwd.conf

Index: src/usr.bin/pwhash/pwhash.c
diff -u src/usr.bin/pwhash/pwhash.c:1.15 src/usr.bin/pwhash/pwhash.c:1.16
--- src/usr.bin/pwhash/pwhash.c:1.15	Fri Sep 16 15:39:28 2011
+++ src/usr.bin/pwhash/pwhash.c	Mon Oct 21 02:36:48 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: pwhash.c,v 1.15 2011/09/16 15:39:28 joerg Exp $	*/
+/*	$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $	*/
 /*	$OpenBSD: encrypt.c,v 1.16 2002/02/16 21:27:45 millert Exp $	*/
 
 /*
@@ -28,7 +28,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: pwhash.c,v 1.15 2011/09/16 15:39:28 joerg Exp $");
+__RCSID("$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $");
 #endif
 
 #include <sys/types.h>
@@ -55,12 +55,26 @@ __RCSID("$NetBSD: pwhash.c,v 1.15 2011/0
 #define DO_BLF     3
 #define DO_SHA1	   4
 
+#ifdef HAVE_ARGON2
+#define DO_ARGON2  5
+/*
+ * Argon2 variant may be specified in /etc/passwd.conf
+ * If not found, default to ARGON2_DEFAULT_VARIANT_STR
+ * acceptable values are: argon2i, argon2d, argon2id
+ */
+#define ARGON2_DEFAULT_VARIANT_STR	"argon2id"
+#endif /* HAVE_ARGON2 */
+
 __dead static void
 usage(void)
 {
 
 	(void)fprintf(stderr,
+#ifdef HAVE_ARGON2
+	    "Usage: %s [-km] [-A variant[,params]] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
+#else
 	    "Usage: %s [-km] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
+#endif /* HAVE_ARGON2 */
 	    getprogname());
 	exit(1);
 }
@@ -119,6 +133,21 @@ print_passwd(char *string, int operation
 		salt = extra;
 		break;
 
+#ifdef HAVE_ARGON2
+	case DO_ARGON2:
+		/* pwhash -A <variant>[,param]* */
+		/* param
+		 *    m=<m_cost>
+		 *    t=<t_cost>
+		 *    p=<threads>
+		 */
+		snprintf(option, sizeof(option), "%s", extra);
+		opt = option;
+		key = strsep(&opt, ",");
+		error = pw_gensalt(buf, _PASSWORD_LEN, key, opt);
+		break;
+#endif /* HAVE_ARGON2 */
+
 	default:
 		pw_getconf(option, sizeof(option), "default", "localcipher");
 		opt = option;
@@ -146,7 +175,11 @@ main(int argc, char **argv)
 	if (strcmp(getprogname(), "makekey") == 0)
 		operation = DO_MAKEKEY;
 
+#ifdef HAVE_ARGON2
+	while ((opt = getopt(argc, argv, "kmpS:s:b:A:")) != -1) {
+#else
 	while ((opt = getopt(argc, argv, "kmpS:s:b:")) != -1) {
+#endif /* HAVE_ARGON2 */
 		switch (opt) {
 		case 'k':                       /* Stdin/Stdout Unix crypt */
 			if (operation != -1 || prompt)
@@ -188,6 +221,15 @@ main(int argc, char **argv)
 			extra = optarg;
 			break;
 
+#ifdef HAVE_ARGON2
+		case 'A':                       /* Argon2 password hash */
+			if (operation != -1)
+				usage();
+			operation = DO_ARGON2;
+			extra = optarg;
+			break;
+#endif /* HAVE_ARGON2 */
+
 		default:
 			usage();
 		}

Added files:

Index: src/lib/libcrypt/crypt-argon2.c
diff -u /dev/null src/lib/libcrypt/crypt-argon2.c:1.1
--- /dev/null	Mon Oct 21 02:36:49 2019
+++ src/lib/libcrypt/crypt-argon2.c	Mon Oct 21 02:36:48 2019
@@ -0,0 +1,254 @@
+#include <stdlib.h>
+#include <stdio.h> 
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <pwd.h>
+#include <errno.h>
+#include <argon2.h>
+
+#include <err.h>
+#include "crypt.h"
+
+/* defaults pulled from run.c */
+#define HASHLEN		32
+#define T_COST_DEF 	3 
+#define LOG_M_COST_DEF 	12 /* 2^12 = 4 MiB */
+#define LANES_DEF 	1
+#define THREADS_DEF 	1
+#define OUTLEN_DEF 	32
+#define MAX_PASS_LEN 	128
+
+#define ARGON2_CONTEXT_INITIALIZER	\
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	T_COST_DEF, LOG_M_COST_DEF,\
+	LANES_DEF, THREADS_DEF, \
+	ARGON2_VERSION_NUMBER, 0, 0, ARGON2_DEFAULT_FLAGS}
+
+#define ARGON2_ARGON2_STR	"argon2"
+#define ARGON2_ARGON2I_STR	"argon2i"
+#define ARGON2_ARGON2D_STR	"argon2d"
+#define ARGON2_ARGON2ID_STR	"argon2id"
+
+/* getnum also declared in pw_getsalt.c */
+/* maybe move to util.h?? */
+static int
+getnum(const char *str, size_t *num)
+{
+        char *ep;
+        unsigned long rv;
+ 
+        if (str == NULL) {
+                *num = 0;
+                return 0;
+        }
+
+        rv = strtoul(str, &ep, 0);
+
+        if (str == ep || *ep) {
+                errno = EINVAL;
+                return -1;
+        }
+
+        if (errno == ERANGE && rv == ULONG_MAX)
+                return -1;
+        *num = (size_t)rv;
+        return 0;  
+}
+
+/* process params to argon2 */
+/* we don't force param order as input, */
+/* but we do provide the expected order to argon2 api */
+static int decode_option(argon2_context * ctx, argon2_type * atype, const char * option) 
+{
+	size_t tmp=0;
+        char * in = 0,*inp;;
+        char * a=0;
+        char * p=0;
+	size_t sl;
+	int    error=0;
+
+        in = (char *)strdup(option);
+	inp = in;
+
+	if (*inp == '$') inp++;
+
+	a = strsep(&inp, "$");
+
+	sl = strlen(a);
+
+	if (sl == strlen(ARGON2_ARGON2I_STR) && 
+	   !(strcmp(ARGON2_ARGON2I_STR, a))) {
+		*atype=Argon2_i;
+	} else if (sl == strlen(ARGON2_ARGON2D_STR) && 
+	        !(strcmp(ARGON2_ARGON2D_STR, a))) {
+		*atype=Argon2_d;
+	}
+	else if (sl == strlen(ARGON2_ARGON2ID_STR) && 
+	        !(strcmp(ARGON2_ARGON2ID_STR, a))) {
+		*atype=Argon2_id;
+	} else { /* default to id, we assume simple mistake */
+		/* don't abandon yet */
+		*atype=Argon2_id;
+	}
+
+	a = strsep(&inp, "$");
+
+	if ((getnum(a, &tmp))<0) { /* on error, default to current */
+				/* should start thinking about aborting */
+		ctx->version = ARGON2_VERSION_NUMBER;
+	} else {
+		ctx->version = tmp;
+	}
+
+	a = strsep(&inp, "$");
+
+	/* parse labelled argon2 params */
+	/* m_cost (m)
+	 * t_cost (t)
+	 * threads (p)
+	 */
+	while ((p = strsep(&a, ","))) {
+		switch (*p) {
+			case 'm':
+				p += strlen("m=");
+				if ((getnum(p, &tmp)) < 0) {
+					--error;
+				} else {
+					ctx->m_cost = tmp;
+				}
+				break;
+			case 't':
+				p += strlen("t=");
+				if ((getnum(p, &tmp)) < 0) {
+					--error;
+				} else {
+					ctx->t_cost = tmp;
+				}
+				break;
+			case 'p':
+				p += strlen("p=");
+				if ((getnum(p, &tmp)) < 0) {
+					--error;
+				} else {
+					ctx->threads = tmp;
+				}
+				break;
+			default:
+				return -1;
+
+		}
+	}
+
+	a = strsep(&inp, "$");
+
+	snprintf((char *)ctx->salt,ctx->saltlen, "%s", a);
+
+	a = strsep(&inp, "$");
+
+	if (*a) {
+		snprintf((char *)ctx->pwd,ctx->pwdlen, "%s", a);
+	} else {
+		/* don't care if passwd hash is missing */
+		/* if missing, most likely coming from */
+		/* pwhash or similar */ 
+	}
+
+	/* free our token buffer */
+        free(in);
+
+	/* 0 on success, <0 otherwise */
+        return error;
+}
+
+char * 
+__crypt_argon2(const char *pw, const char * salt)
+{
+	/* we use the libargon2 api to generate */
+	/* return code */
+	int rc=0;
+	/* output buffer */
+	char ebuf[32];
+	/* ptr into argon2 encoded buffer */
+	char * blkp=0;
+	/* argon2 variable, default to id */
+	argon2_type atype = Argon2_id;
+	/* default to current argon2 version */
+	int version=ARGON2_VERSION_NUMBER;
+	/* argon2 context to collect params */
+	argon2_context ctx = ARGON2_CONTEXT_INITIALIZER;
+	/* argon2 encoded buffer */
+	char encodebuf[256];
+	/* argon2 salt buffer */
+	char saltbuf[128];
+	/* argon2 pwd buffer */
+	char pwdbuf[128];
+	/* returned static buffer */
+	static char rbuf[512];
+
+	/* clear buffers */
+	memset(encodebuf, 0, sizeof(encodebuf));
+	memset(saltbuf, 0, sizeof(saltbuf));
+	memset(pwdbuf, 0, sizeof(pwdbuf));
+	memset(rbuf, 0, sizeof(rbuf));
+
+	/* we use static buffers to avoid allocation */
+	/* and easier cleanup */
+	ctx.out = (uint8_t *)ebuf;
+	ctx.outlen = sizeof(ebuf);
+
+	ctx.out = (uint8_t *)encodebuf;
+	ctx.outlen = sizeof(encodebuf);
+
+	ctx.salt = (uint8_t *)saltbuf;
+	ctx.saltlen = sizeof(saltbuf);
+
+	ctx.pwd= (uint8_t *)pwdbuf;
+	ctx.pwdlen = sizeof(pwdbuf);
+
+	/* decode salt string to argon2 params */
+	/* argon2 context for param collection */
+	rc = decode_option(&ctx, &atype, salt);
+
+	if (rc < 0) {
+	/* unable to parse input params */
+		return 0;
+	}
+
+	rc = argon2_hash(ctx.t_cost, ctx.m_cost,
+		ctx.threads, pw, strlen(pw), ctx.salt, strlen((char*)ctx.salt),
+		ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf), atype, ctx.version);
+
+	if (rc != ARGON2_OK) {
+		fprintf(stderr, "Failed: %s\n", argon2_error_message(rc));
+		return 0;
+	}
+
+	/* get encoded passwd */
+	if ((blkp = strrchr(encodebuf, '$')) == NULL) {
+		return 0;
+	}
+
+	/* skip over '$' */
+	blkp++;
+
+	/* we don't use encoded here because it base64 encodes salt */
+	/* same encoding format as argon2 api, but with original salt */
+	snprintf(rbuf, sizeof(rbuf)-1, "$%s$v=%d$m=%d,t=%d,p=%d$%s$%s",
+			argon2_type2string(atype,0),
+			version,
+			ctx.m_cost,
+			ctx.t_cost,
+			ctx.threads,
+			ctx.salt,
+			blkp);
+
+	/* clear buffers */
+	memset(encodebuf, 0, sizeof(encodebuf));
+	memset(saltbuf, 0, sizeof(saltbuf));
+	memset(pwdbuf, 0, sizeof(pwdbuf));
+
+	/* return encoded str */
+	return rbuf;
+}

Reply via email to