mirror_zfs/module/os/freebsd/zfs/hkdf.c
Matthew Macy 9f0a21e641
Add FreeBSD support to OpenZFS
Add the FreeBSD platform code to the OpenZFS repository.  As of this
commit the source can be compiled and tested on FreeBSD 11 and 12.
Subsequent commits are now required to compile on FreeBSD and Linux.
Additionally, they must pass the ZFS Test Suite on FreeBSD which is
being run by the CI.  As of this commit 1230 tests pass on FreeBSD
and there are no unexpected failures.

Reviewed-by: Sean Eric Fagan <sef@ixsystems.com>
Reviewed-by: Jorgen Lundman <lundman@lundman.net>
Reviewed-by: Richard Laager <rlaager@wiktel.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Co-authored-by: Ryan Moeller <ryan@iXsystems.com>
Signed-off-by: Matt Macy <mmacy@FreeBSD.org>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #898 
Closes #8987
2020-04-14 11:36:28 -07:00

103 lines
2.7 KiB
C

/*
* CDDL HEADER START
*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
*/
#include <sys/dmu.h>
#include <sys/hkdf.h>
#include <sys/freebsd_crypto.h>
#include <sys/hkdf.h>
static int
hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
uint_t km_len, uint8_t *out_buf)
{
crypto_key_t key;
/* initialize the salt as a crypto key */
key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(salt_len);
key.ck_data = salt;
crypto_mac(&key, key_material, km_len, out_buf, SHA512_DIGEST_LENGTH);
return (0);
}
static int
hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
uint8_t *out_buf, uint_t out_len)
{
struct hmac_ctx ctx;
crypto_key_t key;
uint_t i, T_len = 0, pos = 0;
uint8_t c;
uint_t N = (out_len + SHA512_DIGEST_LENGTH) / SHA512_DIGEST_LENGTH;
uint8_t T[SHA512_DIGEST_LENGTH];
if (N > 255)
return (SET_ERROR(EINVAL));
/* initialize the salt as a crypto key */
key.ck_format = CRYPTO_KEY_RAW;
key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
key.ck_data = extract_key;
for (i = 1; i <= N; i++) {
c = i;
crypto_mac_init(&ctx, &key);
crypto_mac_update(&ctx, T, T_len);
crypto_mac_update(&ctx, info, info_len);
crypto_mac_update(&ctx, &c, 1);
crypto_mac_final(&ctx, T, SHA512_DIGEST_LENGTH);
bcopy(T, out_buf + pos,
(i != N) ? SHA512_DIGEST_LENGTH : (out_len - pos));
pos += SHA512_DIGEST_LENGTH;
}
return (0);
}
/*
* HKDF is designed to be a relatively fast function for deriving keys from a
* master key + a salt. We use this function to generate new encryption keys
* so as to avoid hitting the cryptographic limits of the underlying
* encryption modes. Note that, for the sake of deriving encryption keys, the
* info parameter is called the "salt" everywhere else in the code.
*/
int
hkdf_sha512(uint8_t *key_material, uint_t km_len, uint8_t *salt,
uint_t salt_len, uint8_t *info, uint_t info_len, uint8_t *output_key,
uint_t out_len)
{
int ret;
uint8_t extract_key[SHA512_DIGEST_LENGTH];
ret = hkdf_sha512_extract(salt, salt_len, key_material, km_len,
extract_key);
if (ret != 0)
return (ret);
ret = hkdf_sha512_expand(extract_key, info, info_len, output_key,
out_len);
if (ret != 0)
return (ret);
return (0);
}