cgdconfig(8): Add an argon2id password-based key generation method

This provides an extra level of side-channel and cracking resistance
compared to the pre-existing pkcs5_pbkdf2/sha1 method used for
password-based disk encryption.

Several new keygen parameters are supported:

	memory (integer, in kilobytes)
	parallelism (integer, usually the number of CPU cores)
	version (integer, usually 19...)

We do our best to calibrate these automatically when the paramsfile
is initially generated.

lgtm riastradh@
This commit is contained in:
nia 2021-11-22 14:34:35 +00:00
parent 5a3dc90041
commit 1569bcc0b3
11 changed files with 494 additions and 27 deletions

View File

@ -0,0 +1,23 @@
# $NetBSD: Makefile,v 1.4 2021/11/22 14:34:35 nia Exp $
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>

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.292 2021/04/25 23:43:48 christos Exp $
# $NetBSD: Makefile,v 1.293 2021/11/22 14:34:35 nia Exp $
# from: @(#)Makefile 5.25.1.1 (Berkeley) 5/7/91
.include <bsd.own.mk>
@ -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

View File

@ -1,8 +1,10 @@
# $NetBSD: Makefile,v 1.15 2016/07/01 22:50:09 christos Exp $
# $NetBSD: Makefile,v 1.16 2021/11/22 14:34:35 nia Exp $
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>

View File

@ -0,0 +1,182 @@
/* $NetBSD: argon2_utils.c,v 1.1 2021/11/22 14:34:35 nia Exp $ */
/*-
* 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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <util.h>
#include <err.h>
#include "argon2_utils.h"
#ifndef lint
__RCSID("$NetBSD: argon2_utils.c,v 1.1 2021/11/22 14:34:35 nia Exp $");
#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) == -1) {
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) == -1) {
return 0;
}
if (getrlimit(RLIMIT_AS, &rlim) == -1)
return usermem64;
if (usermem64 > rlim.rlim_cur && rlim.rlim_cur != RLIM_INFINITY)
usermem64 = rlim.rlim_cur;
return usermem64; /* bytes */
}
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;
const size_t ncpus = get_cpucount();
const uint64_t usermem = get_usermem(); /* bytes */
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 ret = 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;
fprintf(stderr, "calibrating argon2id parameters...");
/* Decrease 'mem' if it slows down computation too much */
do {
if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1)
goto error;
if ((ret = argon2_hash(ARGON2_MIN_TIME, mem, ncpus,
tmp_pwd, sizeof(tmp_pwd),
salt, saltlen,
key, keylen,
NULL, 0,
Argon2_id, ARGON2_VERSION_NUMBER)) != ARGON2_OK) {
goto error_argon2;
}
fprintf(stderr, ".");
if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1)
goto error;
if (timespeccmp(&tp1, &tp2, >))
goto error_clock;
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 (time = ARGON2_MIN_TIME; delta.tv_sec < 1 &&
time < ARGON2_MAX_TIME; time <<= 1) {
if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1)
goto error;
if ((ret = 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_argon2;
}
fprintf(stderr, ".");
if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1)
goto error;
if (timespeccmp(&tp1, &tp2, >))
goto error_clock;
timespecsub(&tp2, &tp1, &delta);
}
if (time > ARGON2_MIN_TIME)
time >>= 1;
fprintf(stderr, " done\n");
free(key);
free(salt);
*iterations = time;
*memory = mem;
*parallelism = ncpus;
return;
error_argon2:
errx(EXIT_FAILURE,
" failed to calculate Argon2 hash, error code %d", ret);
error_clock:
errx(EXIT_FAILURE,
" failed to calibrate hash parameters: broken monotonic clock?");
error:
err(EXIT_FAILURE, " failed to calibrate hash parameters");
}

View File

@ -0,0 +1,36 @@
/* $NetBSD: argon2_utils.h,v 1.1 2021/11/22 14:34:35 nia Exp $ */
/*-
* 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

View File

@ -1,4 +1,4 @@
.\" $NetBSD: cgdconfig.8,v 1.50 2021/04/30 21:07:34 nia Exp $
.\" $NetBSD: cgdconfig.8,v 1.51 2021/11/22 14:34:35 nia Exp $
.\"
.\" Copyright (c) 2002, The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -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,14 @@ evaluates all of the key generation methods in the parameters file
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.
Recommended for passphrase-based initialization.
.It pkcs5_pbkdf2/sha1
This method requires a passphrase which is entered at configuration
time.
@ -231,8 +239,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 +366,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 +495,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.
@ -483,5 +512,9 @@ The
.Nm
utility appeared in
.Nx 2.0 .
.Pp
.Li argon2id
support appeared in
.Nx 10.0 .
.Sh BUGS
Pass phrases are limited to 1023 bytes.

View File

@ -1,4 +1,4 @@
/* $NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh Exp $ */
/* $NetBSD: cgdconfig.c,v 1.53 2021/11/22 14:34:35 nia Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -33,9 +33,12 @@
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 2002, 2003\
The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh Exp $");
__RCSID("$NetBSD: cgdconfig.c,v 1.53 2021/11/22 14:34:35 nia 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 *kg, size_t len)
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, struct keygen *kg, size_t keylen,
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 params *inparams, int flags)
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 */
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),
kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
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);

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: cgdlex.l,v 1.5 2009/10/29 14:49:03 christos Exp $ */
/* $NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: cgdlex.l,v 1.5 2009/10/29 14:49:03 christos Exp $");
__RCSID("$NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $");
#endif
#include <err.h>
@ -98,6 +98,9 @@ verify_method { RETTOKEN(VERIFY_METHOD); }
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); }

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: cgdparse.y,v 1.5 2008/07/17 16:24:55 drochner Exp $ */
/* $NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: cgdparse.y,v 1.5 2008/07/17 16:24:55 drochner Exp $");
__RCSID("$NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $");
#endif
#include <stdio.h>
@ -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; }

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $ */
/* $NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $");
__RCSID("$NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $");
#endif
#include <sys/types.h>
@ -45,6 +45,11 @@ __RCSID("$NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $");
#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, size_t keylen)
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, struct keygen *kg2)
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, FILE *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);

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.h,v 1.11 2014/12/14 12:31:39 mlelstv Exp $ */
/* $NetBSD: params.h,v 1.12 2021/11/22 14:34:35 nia Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -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 *);