cgdconfig(8): Add support for shared keys.

New clause `shared <id> algorithm <alg> subkey <info>' in a keygen
block enables `cgdconfig -C' to reuse a key between different params
files, so you can, e.g., use a single password for multiple disks.
This is better than simply caching the password itself because:

- Hashing the password is expensive, so it should only be done once.

  Suppose your budget is time t before you get bored, and you
  calibrate password hash parameters to unlock n disks before you get
  bored waiting for `cgdconfig -C'.

  . With n password hashings the adversary's cost goes up only by a
    factor of t/n.
  . With one password hashing and n subkeys the adversary's cost goes
    up by a factor of n.

  And if you ever add a disk, rehashing it will make `cgdconfig -C'
  go over budget, whereas another subkey adds negligible cost to you.

- Subkeys work for other types of keygen blocks, like shell_cmd,
  which could be used to get a key from a hardware token that needs a
  button press.

The <info> parameter must be different for each params file;
everything else in the keygen block must be the same.  With this
clause, the keygen block determines a shared key used only to derive
keys; the actual key used by cgdconfig is derived from the shared key
by the specified algorithm.

The only supported algorithm is hkdf-hmac-sha256, which uses
HKDF-Expand of RFC 5869 instantiated with SHA-256.

Example:

	algorithm aes-cbc;
	iv-method encblkno1;
	keylength 128;
	verify_method none;
	keygen pkcs5_pbkdf2/sha1 {
		iterations 39361;
		salt AAAAgMoHiYonye6KogdYJAobCHE=;
		shared "pw" algorithm hkdf-hmac-sha256
		    subkey AAAAgFlw0BMQ5gY+haYkZ6JC+yY=;
	};

The key used for this disk will be derived by

	HKDF-HMAC-SHA256_k(WXDQExDmBj6FpiRnokL7Jg==),

where k is the outcome of PBKDF2-SHA1 with the given parameters.

Note that <info> encodes a four-byte prefix giving the big-endian
length in bits of the info argument to HKDF, just like all other bit
strings in cgdconfig parameters files.

If you have multiple disks configured using the same keygen block
except for the info parameter, `cgdconfig -C' will only prompt once
for your passphrase, generate a shared key k with PBKDF2 as usual,
and then reuse it for each of the disks.
This commit is contained in:
riastradh 2022-08-12 10:49:17 +00:00
parent 732db29a3c
commit 920e28df65
13 changed files with 766 additions and 18 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1218 2022/08/12 10:48:27 riastradh Exp $
# $NetBSD: mi,v 1.1219 2022/08/12 10:49:17 riastradh Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -1417,6 +1417,7 @@
./usr/tests/dev/cgd tests-fs-tests compattestfile,atf
./usr/tests/dev/cgd/Atffile tests-fs-tests compattestfile,atf
./usr/tests/dev/cgd/Kyuafile tests-fs-tests compattestfile,atf,kyua
./usr/tests/dev/cgd/h_countkey tests-fs-tests compattestfile,atf
./usr/tests/dev/cgd/h_img2cgd tests-obsolete obsolete
./usr/tests/dev/cgd/h_img2cgd/cgd.conf tests-obsolete obsolete
./usr/tests/dev/cgd/h_img2cgd/h_img2cgd tests-obsolete obsolete

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.21 2022/05/17 18:56:29 christos Exp $
# $NetBSD: Makefile,v 1.22 2022/08/12 10:49:17 riastradh Exp $
RUMPPRG=cgdconfig
MAN= cgdconfig.8
@ -8,6 +8,7 @@ MAN= cgdconfig.8
SRCS+= cgdconfig.c \
cgdlex.l \
cgdparse.y \
hkdf_hmac_sha256.c \
pkcs5_pbkdf2.c \
params.c \
utils.c

View File

@ -1,4 +1,4 @@
.\" $NetBSD: cgdconfig.8,v 1.54 2022/08/12 10:48:44 riastradh Exp $
.\" $NetBSD: cgdconfig.8,v 1.55 2022/08/12 10:49:17 riastradh Exp $
.\"
.\" Copyright (c) 2002, The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -395,6 +395,46 @@ Version of Argon2 to use.
Should be the most recent version, currently
.Dv 19 .
Only used for argon2id.
.It shared Ar name No algorithm Ar kdf No subkey Ar info
Makes the key generation take an extra step to derive a subkey from the
main key using the key derivation function
.Ar kdf
with input
.Ar info .
.Pp
This enables a single password entry, for example, to decrypt multiple
disks that use different keys, each derived as a subkey from the main
key generated from the password.
.Bl -tag -width 6n
.It Ar name
A string used to identify the same main key generation shared between
parameters files for different disks listed in a single
.Pa cgd.conf
configuration file.
.It Ar kdf
The name of a key derivation function used to derive a subkey from the
main key.
Supported values:
.Bl -tag -width 6n -offset indent
.It Li hkdf-hmac-sha256
The HKDF-Expand function of RFC 5869, instantiated with SHA-256.
.El
.It Ar info
A base64 length-encoded string to distinguish different subkeys derived
from a shared main key.
Need not be secret.
For example, it could be a nickname, or the disk's World-Wide Name, or
a UUID generated for the disk, or just a random string.
.El
.Pp
It is an error to reuse a shared key
.Ar name
with different keygen blocks, other than the
.Ar info
parameter,
between parameters files used by a single
.Pa cgd.conf
configuration file.
.El
.Sh FILES
.Bl -tag -width indentxxxxxxxxxxxxxxxxxx -compact
@ -474,6 +514,45 @@ An example parameters file which stores its key locally:
ly2TdxkFqOkYYcbyUKu/f60L;
.Ed
.Pp
An example pair of configuration files which use shared keys so they
can be derived from a single passphrase entry, with the 64-bit
World-Wide Name of each disk (base64 length-encoded) as its subkey
info:
.Bl -tag -offset indent -width 6n
.It Pa /etc/cgd/wd0a
.Bd -literal
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method gpt;
keygen argon2id {
iterations 32;
memory 5214;
parallelism 2;
version 19;
salt AAAAgLZ5QgleU2m/Ib6wiPYxz98=;
shared "my laptop" algorithm hkdf-hmac-sha256 \e
subkey AAAAQEGELNr3bj3I;
};
.Ed
.It Pa /etc/cgd/wd1a
.Bd -literal
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method gpt;
keygen argon2id {
iterations 32;
memory 5214;
parallelism 2;
version 19;
salt AAAAgLZ5QgleU2m/Ib6wiPYxz98=;
shared "my laptop" algorithm hkdf-hmac-sha256 \e
subkey AAAAQHSC15pr1Pe4;
};
.Ed
.El
.Pp
An example
.Pa /etc/cgd/cgd.conf :
.Bd -literal
@ -517,6 +596,15 @@ program's execution.
.%I University of Luxembourg
.%U https://www.password-hashing.net/
.Re
.Rs
.%A H. Krawczyk
.%A P. Eronen
.%T HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
.%I Internet Engineering Task Force
.%U https://www.rfc-editor.org/rfc/rfc5869.html
.%N RFC 5869
.%D May 2010
.Re
.Pp
.Dq PKCS #5 v2.0: Password-Based Cryptography Standard ,
RSA Laboratories, March 25, 1999.
@ -526,8 +614,9 @@ The
utility appeared in
.Nx 2.0 .
.Pp
Support for
.Li argon2id
support appeared in
and for shared keys 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.55 2022/08/12 10:48:44 riastradh Exp $ */
/* $NetBSD: cgdconfig.c,v 1.56 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -33,12 +33,13 @@
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 2002, 2003\
The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: cgdconfig.c,v 1.55 2022/08/12 10:48:44 riastradh Exp $");
__RCSID("$NetBSD: cgdconfig.c,v 1.56 2022/08/12 10:49:17 riastradh Exp $");
#endif
#ifdef HAVE_ARGON2
#include <argon2.h>
#endif
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@ -66,6 +67,7 @@ __RCSID("$NetBSD: cgdconfig.c,v 1.55 2022/08/12 10:48:44 riastradh Exp $");
#include <sys/resource.h>
#include <sys/statvfs.h>
#include <sys/bitops.h>
#include <sys/queue.h>
#include <dev/cgdvar.h>
@ -76,6 +78,7 @@ __RCSID("$NetBSD: cgdconfig.c,v 1.55 2022/08/12 10:48:44 riastradh Exp $");
#include "utils.h"
#include "cgdconfig.h"
#include "prog_ops.h"
#include "hkdf_hmac_sha256.h"
#define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf"
@ -105,6 +108,19 @@ int nflag = 0;
#define PFLAG_STDIN 0x04
int pflag = PFLAG_GETPASS;
/*
* When configuring all cgds, save a cache of shared keys for key
* derivation.
*/
struct sharedkey {
int alg;
string_t *id;
bits_t *key;
LIST_ENTRY(sharedkey) list;
};
LIST_HEAD(, sharedkey) sharedkeys;
static int configure(int, char **, struct params *, int);
static int configure_stdin(struct params *, int argc, char **);
static int generate(struct params *, int, char **, const char *);
@ -216,6 +232,8 @@ main(int argc, char **argv)
const char *outfile = NULL;
setprogname(*argv);
if (hkdf_hmac_sha256_selftest())
err(EXIT_FAILURE, "Crypto self-test failed");
eliminate_cores();
if (mlockall(MCL_FUTURE))
err(EXIT_FAILURE, "Can't lock memory");
@ -348,13 +366,69 @@ main(int argc, char **argv)
}
static bits_t *
getkey(const char *dev, struct keygen *kg, size_t len)
getsubkey_hkdf_hmac_sha256(bits_t *key, bits_t *info, size_t subkeylen)
{
bits_t *ret = NULL;
uint8_t *tmp;
tmp = emalloc(BITS2BYTES(subkeylen));
if (hkdf_hmac_sha256(tmp, BITS2BYTES(subkeylen),
bits_getbuf(key), BITS2BYTES(bits_len(key)),
bits_getbuf(info), BITS2BYTES(bits_len(info)))) {
warnx("failed to derive HKDF-HMAC-SHA256 subkey");
goto out;
}
ret = bits_new(tmp, subkeylen);
out: free(tmp);
return ret;
}
static bits_t *
getsubkey(int alg, bits_t *key, bits_t *info, size_t subkeylen)
{
switch (alg) {
case SHARED_ALG_HKDF_HMAC_SHA256:
return getsubkey_hkdf_hmac_sha256(key, info, subkeylen);
default:
warnx("unrecognised shared key derivation method %d", alg);
return NULL;
}
}
static bits_t *
getkey(const char *dev, struct keygen *kg, size_t len0)
{
bits_t *ret = NULL;
bits_t *tmp;
VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len));
VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len0));
for (; kg; kg=kg->next) {
struct sharedkey *sk = NULL;
size_t len = len0;
/*
* If shared, determine the shared key's length and
* probe the cache of shared keys.
*/
if (kg->kg_sharedid) {
const char *id = string_tocharstar(kg->kg_sharedid);
len = kg->kg_sharedlen;
LIST_FOREACH(sk, &sharedkeys, list) {
if (kg->kg_sharedalg == sk->alg &&
kg->kg_sharedlen == bits_len(sk->key) &&
strcmp(id, string_tocharstar(sk->id)) == 0)
break;
}
if (sk) {
tmp = sk->key;
goto derive;
}
}
switch (kg->kg_method) {
case KEYGEN_STOREDKEY:
tmp = getkey_storedkey(dev, kg, len);
@ -388,6 +462,32 @@ getkey(const char *dev, struct keygen *kg, size_t len)
return NULL;
}
/*
* If shared, cache the key.
*/
if (kg->kg_sharedid) {
assert(sk == NULL);
sk = ecalloc(1, sizeof(*sk));
sk->alg = kg->kg_sharedalg;
sk->id = string_dup(kg->kg_sharedid);
sk->key = tmp;
LIST_INSERT_HEAD(&sharedkeys, sk, list);
}
derive: if (kg->kg_sharedid) {
/*
* tmp holds the master key, owned by the
* struct sharedkey record; replace it by the
* derived subkey.
*/
tmp = getsubkey(kg->kg_sharedalg, tmp,
kg->kg_sharedinfo, len0);
if (tmp == NULL) {
if (ret)
bits_free(ret);
return NULL;
}
}
if (ret)
ret = bits_xor_d(tmp, ret);
else

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $ */
/* $NetBSD: cgdlex.l,v 1.7 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $");
__RCSID("$NetBSD: cgdlex.l,v 1.7 2022/08/12 10:49:17 riastradh Exp $");
#endif
#include <err.h>
@ -107,6 +107,8 @@ keygen_method { RETTOKEN(KEYGEN_METHOD); }
keygen_salt { RETTOKEN(KEYGEN_SALT); }
keygen_iterations { RETTOKEN(KEYGEN_ITERATIONS); }
xor_key { RETTOKEN(XOR_KEY); }
shared { RETTOKEN(SHARED); }
subkey { RETTOKEN(SUBKEY); }
[;\n] { return EOL; }
\\\n /* ignore a quoted nl */
[ \t] /* ignore spaces and tabs */

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $ */
/* $NetBSD: cgdparse.y,v 1.7 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $");
__RCSID("$NetBSD: cgdparse.y,v 1.7 2022/08/12 10:49:17 riastradh Exp $");
#endif
#include <stdio.h>
@ -67,7 +67,8 @@ static struct params *yy_global_params;
%token <string> STRINGLIT
%token <token> ALGORITHM KEYLENGTH IVMETHOD VERIFY_METHOD
%token <token> KEYGEN SALT ITERATIONS MEMORY PARALLELISM VERSION KEY CMD
%token <token> KEYGEN SALT ITERATIONS MEMORY PARALLELISM VERSION KEY CMD SHARED
%token <token> SUBKEY
%token EOL
@ -104,6 +105,8 @@ kgvar: SALT bits EOL { $$ = keygen_salt($2); }
| VERSION INTEGER EOL { $$ = keygen_version($2); }
| KEY bits EOL { $$ = keygen_key($2); }
| CMD stringlit EOL { $$ = keygen_cmd($2); }
| SHARED stringlit ALGORITHM stringlit SUBKEY bits EOL
{ $$ = keygen_shared($2, $4, $6); }
| EOL { $$ = NULL; }
stringlit: STRINGLIT | tokstr | intstr

View File

@ -0,0 +1,273 @@
/* $NetBSD: hkdf_hmac_sha256.c,v 1.1 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2022 The NetBSD Foundation, Inc.
* All rights reserved.
*
* 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/cdefs.h>
__RCSID("$NetBSD: hkdf_hmac_sha256.c,v 1.1 2022/08/12 10:49:17 riastradh Exp $");
#include <sys/sha2.h>
#include <stdint.h>
#include <string.h>
#include "hkdf_hmac_sha256.h"
/* RFC 2104: HMAC */
struct hmacsha256 {
SHA256_CTX sha256;
uint8_t key[SHA256_BLOCK_LENGTH];
};
static void
hmacsha256_init(struct hmacsha256 *H, const void *key, size_t keylen)
{
uint8_t hkey[SHA256_DIGEST_LENGTH];
uint8_t ipad[SHA256_BLOCK_LENGTH];
unsigned i;
if (keylen > SHA256_BLOCK_LENGTH) { /* XXX should not happen here */
SHA256_Init(&H->sha256);
SHA256_Update(&H->sha256, key, keylen);
SHA256_Final(hkey, &H->sha256);
key = hkey;
keylen = sizeof(hkey);
}
memset(H->key, 0, sizeof(H->key));
memcpy(H->key, key, keylen);
for (i = 0; i < SHA256_BLOCK_LENGTH; i++)
ipad[i] = 0x36 ^ H->key[i];
SHA256_Init(&H->sha256);
SHA256_Update(&H->sha256, ipad, SHA256_BLOCK_LENGTH);
explicit_memset(hkey, 0, sizeof(hkey));
explicit_memset(ipad, 0, sizeof(ipad));
}
static void
hmacsha256_update(struct hmacsha256 *H, const void *buf, size_t buflen)
{
SHA256_Update(&H->sha256, buf, buflen);
}
static void
hmacsha256_final(uint8_t h[static SHA256_DIGEST_LENGTH],
struct hmacsha256 *H)
{
uint8_t opad[SHA256_BLOCK_LENGTH];
unsigned i;
for (i = 0; i < SHA256_BLOCK_LENGTH; i++)
opad[i] = 0x5c ^ H->key[i];
SHA256_Final(h, &H->sha256);
SHA256_Init(&H->sha256);
SHA256_Update(&H->sha256, opad, SHA256_BLOCK_LENGTH);
SHA256_Update(&H->sha256, h, SHA256_DIGEST_LENGTH);
SHA256_Final(h, &H->sha256);
explicit_memset(opad, 0, sizeof(opad));
explicit_memset(H, 0, sizeof(*H));
}
/* RFC 5869 HKDF, Sec. 2.3 HKDF-Expand */
int
hkdf_hmac_sha256(void *okm, size_t L,
const void *prk, size_t prklen,
const void *info, size_t infolen)
{
struct hmacsha256 hmacsha256;
size_t n, tlen;
uint8_t T[SHA256_DIGEST_LENGTH], *p = okm;
uint8_t i;
if (L > 255*SHA256_DIGEST_LENGTH)
return -1;
if (L == 0)
return 0;
for (tlen = 0, i = 1; L > 0; i++, tlen = SHA256_DIGEST_LENGTH) {
hmacsha256_init(&hmacsha256, prk, prklen);
hmacsha256_update(&hmacsha256, T, tlen);
hmacsha256_update(&hmacsha256, info, infolen);
hmacsha256_update(&hmacsha256, &i, 1);
hmacsha256_final(T, &hmacsha256);
n = (L < SHA256_DIGEST_LENGTH ? L : SHA256_DIGEST_LENGTH);
memcpy(p, T, n);
p += n;
L -= n;
}
explicit_memset(T, 0, sizeof(T));
return 0;
}
#if 0
#include <stdarg.h>
#include <stdio.h>
static void
hexdump(const void *buf, size_t len, const char *fmt, ...)
{
va_list va;
const uint8_t *p = buf;
size_t i;
printf("### ");
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
printf(" (%zu bytes):\n", len);
for (i = 0; i < len; i++) {
if (i % 8 == 0)
printf(" ");
printf(" %02x", p[i]);
if (i % 16 == 15)
printf("\n");
}
if (i % 16)
printf("\n");
}
#endif
int
hkdf_hmac_sha256_selftest(void)
{
const struct {
size_t L;
const uint8_t *okm;
size_t prklen;
const uint8_t *prk;
size_t infolen;
const uint8_t *info;
} C[] = {
[0] = { /* A.1 Test Case 1 with SHA-256 */
.L = 42,
.okm = (const uint8_t[]) {
0x3c,0xb2,0x5f,0x25, 0xfa,0xac,0xd5,0x7a,
0x90,0x43,0x4f,0x64, 0xd0,0x36,0x2f,0x2a,
0x2d,0x2d,0x0a,0x90, 0xcf,0x1a,0x5a,0x4c,
0x5d,0xb0,0x2d,0x56, 0xec,0xc4,0xc5,0xbf,
0x34,0x00,0x72,0x08, 0xd5,0xb8,0x87,0x18,
0x58,0x65,
},
.prklen = 32,
.prk = (const uint8_t[]) {
0x07,0x77,0x09,0x36, 0x2c,0x2e,0x32,0xdf,
0x0d,0xdc,0x3f,0x0d, 0xc4,0x7b,0xba,0x63,
0x90,0xb6,0xc7,0x3b, 0xb5,0x0f,0x9c,0x31,
0x22,0xec,0x84,0x4a, 0xd7,0xc2,0xb3,0xe5,
},
.infolen = 10,
.info = (const uint8_t[]) {
0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
0xf8,0xf9,
},
},
[1] = { /* A.2 Test Case 2 with SHA-256, longer I/O */
.L = 82,
.okm = (const uint8_t[]) {
0xb1,0x1e,0x39,0x8d, 0xc8,0x03,0x27,0xa1,
0xc8,0xe7,0xf7,0x8c, 0x59,0x6a,0x49,0x34,
0x4f,0x01,0x2e,0xda, 0x2d,0x4e,0xfa,0xd8,
0xa0,0x50,0xcc,0x4c, 0x19,0xaf,0xa9,0x7c,
0x59,0x04,0x5a,0x99, 0xca,0xc7,0x82,0x72,
0x71,0xcb,0x41,0xc6, 0x5e,0x59,0x0e,0x09,
0xda,0x32,0x75,0x60, 0x0c,0x2f,0x09,0xb8,
0x36,0x77,0x93,0xa9, 0xac,0xa3,0xdb,0x71,
0xcc,0x30,0xc5,0x81, 0x79,0xec,0x3e,0x87,
0xc1,0x4c,0x01,0xd5, 0xc1,0xf3,0x43,0x4f,
0x1d,0x87,
},
.prklen = 32,
.prk = (const uint8_t[]) {
0x06,0xa6,0xb8,0x8c, 0x58,0x53,0x36,0x1a,
0x06,0x10,0x4c,0x9c, 0xeb,0x35,0xb4,0x5c,
0xef,0x76,0x00,0x14, 0x90,0x46,0x71,0x01,
0x4a,0x19,0x3f,0x40, 0xc1,0x5f,0xc2,0x44,
},
.infolen = 80,
.info = (const uint8_t[]) {
0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
},
},
[2] = { /* A.3 Test Case 3 with SHA-256, empty info */
.L = 42,
.okm = (const uint8_t[]) {
0x8d,0xa4,0xe7,0x75, 0xa5,0x63,0xc1,0x8f,
0x71,0x5f,0x80,0x2a, 0x06,0x3c,0x5a,0x31,
0xb8,0xa1,0x1f,0x5c, 0x5e,0xe1,0x87,0x9e,
0xc3,0x45,0x4e,0x5f, 0x3c,0x73,0x8d,0x2d,
0x9d,0x20,0x13,0x95, 0xfa,0xa4,0xb6,0x1a,
0x96,0xc8,
},
.prklen = 32,
.prk = (const uint8_t[]) {
0x19,0xef,0x24,0xa3, 0x2c,0x71,0x7b,0x16,
0x7f,0x33,0xa9,0x1d, 0x6f,0x64,0x8b,0xdf,
0x96,0x59,0x67,0x76, 0xaf,0xdb,0x63,0x77,
0xac,0x43,0x4c,0x1c, 0x29,0x3c,0xcb,0x04,
},
.infolen = 0,
.info = NULL,
},
};
uint8_t okm[128];
unsigned i;
for (i = 0; i < __arraycount(C); i++) {
if (hkdf_hmac_sha256(okm, C[i].L, C[i].prk, C[i].prklen,
C[i].info, C[i].infolen))
return -1;
if (memcmp(okm, C[i].okm, C[i].L))
return -1;
}
return 0;
}
#if 0
int
main(void)
{
return hkdf_hmac_sha256_selftest();
}
#endif

View File

@ -0,0 +1,40 @@
/* $NetBSD: hkdf_hmac_sha256.h,v 1.1 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2022 The NetBSD Foundation, Inc.
* All rights reserved.
*
* 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 HKDF_HMAC_SHA256_H
#define HKDF_HMAC_SHA256_H
#include <stddef.h>
int hkdf_hmac_sha256(void *, size_t,
const void *, size_t,
const void *, size_t);
int hkdf_hmac_sha256_selftest(void);
#endif /* HKDF_HMAC_SHA256_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $ */
/* $NetBSD: params.c,v 1.33 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -31,11 +31,13 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $");
__RCSID("$NetBSD: params.c,v 1.33 2022/08/12 10:49:17 riastradh Exp $");
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sha2.h>
#include <sys/stat.h>
#include <err.h>
@ -325,6 +327,10 @@ keygen_new(void)
kg->kg_salt = NULL;
kg->kg_key = NULL;
kg->kg_cmd = NULL;
kg->kg_sharedid = NULL;
kg->kg_sharedalg = SHARED_ALG_UNKNOWN;
kg->kg_sharedlen = (size_t)-1;
kg->kg_sharedinfo = NULL;
kg->next = NULL;
return kg;
}
@ -338,6 +344,8 @@ keygen_free(struct keygen *kg)
bits_free(kg->kg_salt);
bits_free(kg->kg_key);
string_free(kg->kg_cmd);
string_free(kg->kg_sharedid);
bits_free(kg->kg_sharedinfo);
keygen_free(kg->next);
free(kg);
}
@ -432,6 +440,8 @@ keygen_verify(const struct keygen *kg)
warnx("keygen [u]randomkey does not need `salt'");
if (kg->kg_cmd)
warnx("keygen [u]randomkey does not need `cmd'");
if (kg->kg_sharedid)
warnx("keygen [u]randomkey makes no sense shared");
break;
case KEYGEN_SHELL_CMD:
if (kg->kg_iterations != (size_t)-1)
@ -550,6 +560,15 @@ keygen_combine(struct keygen *kg1, struct keygen *kg2)
if (kg2->kg_cmd)
string_assign(&kg1->kg_cmd, kg2->kg_cmd);
if (kg2->kg_sharedid)
string_assign(&kg1->kg_sharedid, kg2->kg_sharedid);
if (kg2->kg_sharedalg != SHARED_ALG_UNKNOWN) {
kg1->kg_sharedalg = kg2->kg_sharedalg;
kg1->kg_sharedlen = kg2->kg_sharedlen;
}
if (kg2->kg_sharedinfo)
bits_assign(&kg1->kg_sharedinfo, kg2->kg_sharedinfo);
return kg1;
}
@ -668,6 +687,27 @@ keygen_cmd(string_t *in)
return kg;
}
struct keygen *
keygen_shared(string_t *id, string_t *alg, bits_t *info)
{
struct keygen *kg = keygen_new();
const char *algname = string_tocharstar(alg);
if (!strcmp("hkdf-hmac-sha256", algname)) {
kg->kg_sharedalg = SHARED_ALG_HKDF_HMAC_SHA256;
kg->kg_sharedlen = 8*SHA256_DIGEST_LENGTH;
}
if (kg->kg_sharedalg == SHARED_ALG_UNKNOWN) {
warnx("unrecognized shared key derivation algorithm \"%s\"",
algname);
}
kg->kg_sharedid = id;
kg->kg_sharedinfo = info;
return kg;
}
struct params *
params_fget(FILE *f)
{
@ -806,6 +846,26 @@ print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val)
string_free(str);
}
static void
print_shared(FILE *f, int ts, struct keygen *kg)
{
static const char *const sharedalgs[] = {
[SHARED_ALG_UNKNOWN] = "unknown",
[SHARED_ALG_HKDF_HMAC_SHA256] = "hkdf-hmac-sha256",
};
if (kg->kg_sharedid == NULL ||
kg->kg_sharedalg < 0 ||
(size_t)kg->kg_sharedalg >= __arraycount(sharedalgs))
return;
fprintf(f, "%*sshared \"%s\" \\\n", ts, "",
string_tocharstar(kg->kg_sharedid));
ts += 4;
fprintf(f, "%*salgorithm %s \\\n", ts, "",
sharedalgs[kg->kg_sharedalg]);
print_kvpair_b64(f, 0, ts, "subkey", kg->kg_sharedinfo);
}
int
keygen_fput(struct keygen *kg, int ts, FILE *f)
{
@ -835,6 +895,7 @@ keygen_fput(struct keygen *kg, int ts, FILE *f)
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);
print_shared(f, ts, kg);
(void)fprintf(f, "};\n");
break;
#endif
@ -842,12 +903,14 @@ keygen_fput(struct keygen *kg, int ts, FILE *f)
(void)fprintf(f, "pkcs5_pbkdf2 {\n");
print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
print_shared(f, ts, kg);
(void)fprintf(f, "};\n");
break;
case KEYGEN_PKCS5_PBKDF2_SHA1:
(void)fprintf(f, "pkcs5_pbkdf2/sha1 {\n");
print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
print_shared(f, ts, kg);
(void)fprintf(f, "};\n");
break;
default:

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.h,v 1.12 2021/11/22 14:34:35 nia Exp $ */
/* $NetBSD: params.h,v 1.13 2022/08/12 10:49:17 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -43,6 +43,10 @@ struct keygen {
bits_t *kg_salt;
bits_t *kg_key;
string_t *kg_cmd;
string_t *kg_sharedid;
int kg_sharedalg;
size_t kg_sharedlen;
bits_t *kg_sharedinfo;
struct keygen *next;
};
@ -78,6 +82,11 @@ struct params {
#define VERIFY_MBR 0x5
#define VERIFY_GPT 0x6
/* shared key derivation methods */
#define SHARED_ALG_UNKNOWN 0x0
#define SHARED_ALG_HKDF_HMAC_SHA256 0x1
__BEGIN_DECLS
struct params *params_new(void);
void params_free(struct params *);
@ -117,6 +126,7 @@ struct keygen *keygen_parallelism(size_t);
struct keygen *keygen_version(size_t);
struct keygen *keygen_key(bits_t *);
struct keygen *keygen_cmd(string_t *);
struct keygen *keygen_shared(string_t *, string_t *, bits_t *);
int keygen_fput(struct keygen *, int, FILE *);
__END_DECLS

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.12 2022/08/12 10:48:28 riastradh Exp $
# $NetBSD: Makefile,v 1.13 2022/08/12 10:49:17 riastradh Exp $
#
.include <bsd.own.mk>
@ -10,6 +10,9 @@ FILESDIR= ${TESTSDIR}
TESTS_SH+= t_cgd
TESTS_SH+= t_cgdconfig
SCRIPTSDIR= ${TESTSDIR}
SCRIPTS+= h_countkey.sh
.if ${MKRUMP} != "no"
TESTS_C+= t_cgd_3des
TESTS_C+= t_cgd_adiantum

View File

@ -0,0 +1,11 @@
#!/bin/sh
set -Ceu
n=$(cat "$1" 2>/dev/null || echo 0)
n=$((n + 1))
echo $n >"$1".tmp
mv -f "$1".tmp "$1"
shift
echo ${1+"$@"} | base64 -d

View File

@ -1,4 +1,4 @@
# $NetBSD: t_cgdconfig.sh,v 1.2 2022/08/12 10:48:44 riastradh Exp $
# $NetBSD: t_cgdconfig.sh,v 1.3 2022/08/12 10:49:17 riastradh Exp $
#
# Copyright (c) 2022 The NetBSD Foundation, Inc.
# All rights reserved.
@ -25,6 +25,8 @@
# POSSIBILITY OF SUCH DAMAGE.
#
COUNTKEY=$(atf_get_srcdir)/h_countkey
atf_test_case storedkey
storedkey_head()
{
@ -120,8 +122,158 @@ EOF
cgdconfig -t params
}
atf_test_case sharedstoredkey10
sharedstoredkey10_head()
{
atf_set descr "Test shared key generation from storedkey, 10-byte info"
}
sharedstoredkey10_body()
{
cat <<EOF >params
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen storedkey {
key AAABAAd3CTYsLjLfDdw/DcR7umOQtsc7tQ+cMSLshErXwrPl;
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAAAUPDx8vP09fb3+Pk=;
};
EOF
atf_check -o inline:'PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb8=\n' \
cgdconfig -t params
}
atf_test_case sharedstoredkey80
sharedstoredkey80_head()
{
atf_set descr "Test shared key generation from storedkey, 80-byte info"
}
sharedstoredkey80_body()
{
cat <<EOF >params
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen storedkey {
key AAABAAamuIxYUzYaBhBMnOs1tFzvdgAUkEZxAUoZP0DBX8JE;
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAACgLCxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJ \
ysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn \
6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/;
};
EOF
atf_check -o inline:'sR45jcgDJ6HI5/eMWWpJNE8BLtotTvrYoFDMTBmvqXw=\n' \
cgdconfig -t params
}
atf_test_case sharedstoredkeys
sharedstoredkeys_head()
{
atf_set descr "Test multiple shared key generations from stored keys"
}
sharedstoredkeys_body()
{
cat <<EOF >wd0e
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen storedkey {
key AAABAAd3CTYsLjLfDdw/DcR7umOQtsc7tQ+cMSLshErXwrPl;
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAAAUPDx8vP09fb3+Pk=;
};
EOF
cat <<EOF >ld1e
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen storedkey {
key AAABAAd3CTYsLjLfDdw/DcR7umOQtsc7tQ+cMSLshErXwrPl;
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAAAQMxUtCBh7ha6mUU=;
};
EOF
cat <<EOF >cgd.conf0
cgd0 /dev/wd0e wd0e
cgd1 /dev/ld1e ld1e
EOF
cat <<EOF >expected0
/dev/wd0e: PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb8=
/dev/ld1e: ADxn574yb7sVdxHphNRRdObZxntMJA/ssMuUX6SXgEY=
EOF
cat <<EOF >cgd.conf1
cgd0 /dev/ld1e ld1e
cgd1 /dev/wd0e wd0e
EOF
cat <<EOF >expected1
/dev/ld1e: ADxn574yb7sVdxHphNRRdObZxntMJA/ssMuUX6SXgEY=
/dev/wd0e: PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb8=
EOF
atf_check -o file:expected0 cgdconfig -T -f cgd.conf0
atf_check -o file:expected1 cgdconfig -T -f cgd.conf1
}
atf_test_case sharedshellkeys
sharedshellkeys_head()
{
atf_set descr "Test multiple shared key generations from shell_cmd"
}
sharedshellkeys_body()
{
cat <<EOF >wd0e
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen shell_cmd {
cmd "${COUNTKEY} n B3cJNiwuMt8N3D8NxHu6Y5C2xzu1D5wxIuyEStfCs+U=";
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAAAUPDx8vP09fb3+Pk=;
};
EOF
cat <<EOF >ld1e
algorithm adiantum;
iv-method encblkno1;
keylength 256;
verify_method none;
keygen shell_cmd {
cmd "${COUNTKEY} n B3cJNiwuMt8N3D8NxHu6Y5C2xzu1D5wxIuyEStfCs+U=";
shared "helloworld" algorithm hkdf-hmac-sha256 \
subkey AAAAQMxUtCBh7ha6mUU=;
};
EOF
cat <<EOF >cgd.conf0
cgd0 /dev/wd0e wd0e
cgd1 /dev/ld1e ld1e
EOF
cat <<EOF >expected0
/dev/wd0e: PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb8=
/dev/ld1e: ADxn574yb7sVdxHphNRRdObZxntMJA/ssMuUX6SXgEY=
EOF
cat <<EOF >cgd.conf1
cgd0 /dev/ld1e ld1e
cgd1 /dev/wd0e wd0e
EOF
cat <<EOF >expected1
/dev/ld1e: ADxn574yb7sVdxHphNRRdObZxntMJA/ssMuUX6SXgEY=
/dev/wd0e: PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb8=
EOF
atf_check -o file:expected0 cgdconfig -T -f cgd.conf0
atf_check -o inline:'1\n' cat n
atf_check -o file:expected1 cgdconfig -T -f cgd.conf1
atf_check -o inline:'2\n' cat n
}
atf_init_test_cases()
{
atf_add_test_case sharedshellkeys
atf_add_test_case sharedstoredkey10
atf_add_test_case sharedstoredkey80
atf_add_test_case sharedstoredkeys
atf_add_test_case storedkey
atf_add_test_case storedkey2a
atf_add_test_case storedkey2b