Commit d60ac92c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux

Pull fscrypt updates from Eric Biggers:
 "Make fs/crypto/ use the HMAC-SHA512 library functions instead of
  crypto_shash.

  This is simpler, faster, and more reliable"

* tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux:
  fscrypt: use HMAC-SHA512 library for HKDF
  fscrypt: Remove redundant __GFP_NOWARN
parents a769648f 19591f7e
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -2,10 +2,9 @@
config FS_ENCRYPTION
	bool "FS Encryption (Per-file encryption)"
	select CRYPTO
	select CRYPTO_HASH
	select CRYPTO_HKDF
	select CRYPTO_SKCIPHER
	select CRYPTO_LIB_SHA256
	select CRYPTO_LIB_SHA512
	select KEYS
	help
	  Enable encryption of files and directories.  This
@@ -32,8 +31,6 @@ config FS_ENCRYPTION_ALGS
	select CRYPTO_CBC
	select CRYPTO_CTS
	select CRYPTO_ECB
	select CRYPTO_HMAC
	select CRYPTO_SHA512
	select CRYPTO_XTS

config FS_ENCRYPTION_INLINE_CRYPT
+1 −1
Original line number Diff line number Diff line
@@ -148,7 +148,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
	 */
	for (i = 0; i < nr_pages; i++) {
		pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS :
						     GFP_NOWAIT | __GFP_NOWARN);
						     GFP_NOWAIT);
		if (!pages[i])
			break;
	}
+0 −1
Original line number Diff line number Diff line
@@ -11,7 +11,6 @@
 * This has not yet undergone a rigorous security audit.
 */

#include <crypto/hash.h>
#include <crypto/sha2.h>
#include <crypto/skcipher.h>
#include <linux/export.h>
+10 −16
Original line number Diff line number Diff line
@@ -11,10 +11,10 @@
#ifndef _FSCRYPT_PRIVATE_H
#define _FSCRYPT_PRIVATE_H

#include <crypto/sha2.h>
#include <linux/fscrypt.h>
#include <linux/minmax.h>
#include <linux/siphash.h>
#include <crypto/hash.h>
#include <linux/blk-crypto.h>

#define CONST_STRLEN(str)	(sizeof(str) - 1)
@@ -381,11 +381,7 @@ bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
				    u32 *encrypted_len_ret);

/* hkdf.c */
struct fscrypt_hkdf {
	struct crypto_shash *hmac_tfm;
};

int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
void fscrypt_init_hkdf(struct hmac_sha512_key *hkdf, const u8 *master_key,
		       unsigned int master_key_size);

/*
@@ -405,12 +401,10 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
#define HKDF_CONTEXT_KEY_IDENTIFIER_FOR_HW_WRAPPED_KEY \
					8 /* info=<empty>		*/

int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
			 const u8 *info, unsigned int infolen,
			 u8 *okm, unsigned int okmlen);

void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);

/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
@@ -517,7 +511,7 @@ struct fscrypt_master_key_secret {
	 * ->is_hw_wrapped=false, or by the "software secret" that hardware
	 * derived from this master key if ->is_hw_wrapped=true.
	 */
	struct fscrypt_hkdf	hkdf;
	struct hmac_sha512_key	hkdf;

	/*
	 * True if this key is a hardware-wrapped key; false if this key is a
@@ -696,7 +690,7 @@ struct fscrypt_master_key *
fscrypt_find_master_key(struct super_block *sb,
			const struct fscrypt_key_specifier *mk_spec);

int fscrypt_get_test_dummy_key_identifier(
void fscrypt_get_test_dummy_key_identifier(
			  u8 key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]);

int fscrypt_add_test_dummy_key(struct super_block *sb,
@@ -732,7 +726,7 @@ void fscrypt_destroy_prepared_key(struct super_block *sb,
int fscrypt_set_per_file_enc_key(struct fscrypt_inode_info *ci,
				 const u8 *raw_key);

int fscrypt_derive_dirhash_key(struct fscrypt_inode_info *ci,
void fscrypt_derive_dirhash_key(struct fscrypt_inode_info *ci,
				const struct fscrypt_master_key *mk);

void fscrypt_hash_inode_number(struct fscrypt_inode_info *ci,
+40 −69
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Implementation of HKDF ("HMAC-based Extract-and-Expand Key Derivation
 * Function"), aka RFC 5869.  See also the original paper (Krawczyk 2010):
 * "Cryptographic Extraction and Key Derivation: The HKDF Scheme".
 *
 * This is used to derive keys from the fscrypt master keys (or from the
 * "software secrets" which hardware derives from the fscrypt master keys, in
 * the case that the fscrypt master keys are hardware-wrapped keys).
@@ -7,10 +11,6 @@
 * Copyright 2019 Google LLC
 */

#include <crypto/hash.h>
#include <crypto/hkdf.h>
#include <crypto/sha2.h>

#include "fscrypt_private.h"

/*
@@ -24,7 +24,6 @@
 * HKDF-SHA512 being much faster than HKDF-SHA256, as the longer digest size of
 * SHA-512 causes HKDF-Expand to only need to do one iteration rather than two.
 */
#define HKDF_HMAC_ALG		"hmac(sha512)"
#define HKDF_HASHLEN		SHA512_DIGEST_SIZE

/*
@@ -44,54 +43,24 @@
 */

/*
 * Compute HKDF-Extract using the given master key as the input keying material,
 * and prepare an HMAC transform object keyed by the resulting pseudorandom key.
 *
 * Afterwards, the keyed HMAC transform object can be used for HKDF-Expand many
 * times without having to recompute HKDF-Extract each time.
 * Compute HKDF-Extract using 'master_key' as the input keying material, and
 * prepare the resulting HMAC key in 'hkdf'.  Afterwards, 'hkdf' can be used for
 * HKDF-Expand many times without having to recompute HKDF-Extract each time.
 */
int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
void fscrypt_init_hkdf(struct hmac_sha512_key *hkdf, const u8 *master_key,
		       unsigned int master_key_size)
{
	struct crypto_shash *hmac_tfm;
	static const u8 default_salt[HKDF_HASHLEN];
	u8 prk[HKDF_HASHLEN];
	int err;

	hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, FSCRYPT_CRYPTOAPI_MASK);
	if (IS_ERR(hmac_tfm)) {
		fscrypt_err(NULL, "Error allocating " HKDF_HMAC_ALG ": %ld",
			    PTR_ERR(hmac_tfm));
		return PTR_ERR(hmac_tfm);
	}

	if (WARN_ON_ONCE(crypto_shash_digestsize(hmac_tfm) != sizeof(prk))) {
		err = -EINVAL;
		goto err_free_tfm;
	}

	err = hkdf_extract(hmac_tfm, master_key, master_key_size,
			   default_salt, HKDF_HASHLEN, prk);
	if (err)
		goto err_free_tfm;

	err = crypto_shash_setkey(hmac_tfm, prk, sizeof(prk));
	if (err)
		goto err_free_tfm;

	hkdf->hmac_tfm = hmac_tfm;
	goto out;

err_free_tfm:
	crypto_free_shash(hmac_tfm);
out:
	hmac_sha512_usingrawkey(default_salt, sizeof(default_salt),
				master_key, master_key_size, prk);
	hmac_sha512_preparekey(hkdf, prk, sizeof(prk));
	memzero_explicit(prk, sizeof(prk));
	return err;
}

/*
 * HKDF-Expand (RFC 5869 section 2.3).  This expands the pseudorandom key, which
 * was already keyed into 'hkdf->hmac_tfm' by fscrypt_init_hkdf(), into 'okmlen'
 * HKDF-Expand (RFC 5869 section 2.3).  Expand the HMAC key 'hkdf' into 'okmlen'
 * bytes of output keying material parameterized by the application-specific
 * 'info' of length 'infolen' bytes, prefixed by "fscrypt\0" and the 'context'
 * byte.  This is thread-safe and may be called by multiple threads in parallel.
@@ -100,30 +69,32 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
 * adds to its application-specific info strings to guarantee that it doesn't
 * accidentally repeat an info string when using HKDF for different purposes.)
 */
int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
			 const u8 *info, unsigned int infolen,
			 u8 *okm, unsigned int okmlen)
{
	SHASH_DESC_ON_STACK(desc, hkdf->hmac_tfm);
	u8 *full_info;
	int err;

	full_info = kzalloc(infolen + 9, GFP_KERNEL);
	if (!full_info)
		return -ENOMEM;
	desc->tfm = hkdf->hmac_tfm;

	memcpy(full_info, "fscrypt\0", 8);
	full_info[8] = context;
	memcpy(full_info + 9, info, infolen);

	err = hkdf_expand(hkdf->hmac_tfm, full_info, infolen + 9,
			  okm, okmlen);
	kfree_sensitive(full_info);
	return err;
	struct hmac_sha512_ctx ctx;
	u8 counter = 1;
	u8 tmp[HKDF_HASHLEN];

	WARN_ON_ONCE(okmlen > 255 * HKDF_HASHLEN);

	for (unsigned int i = 0; i < okmlen; i += HKDF_HASHLEN) {
		hmac_sha512_init(&ctx, hkdf);
		if (i != 0)
			hmac_sha512_update(&ctx, &okm[i - HKDF_HASHLEN],
					   HKDF_HASHLEN);
		hmac_sha512_update(&ctx, "fscrypt\0", 8);
		hmac_sha512_update(&ctx, &context, 1);
		hmac_sha512_update(&ctx, info, infolen);
		hmac_sha512_update(&ctx, &counter, 1);
		if (okmlen - i < HKDF_HASHLEN) {
			hmac_sha512_final(&ctx, tmp);
			memcpy(&okm[i], tmp, okmlen - i);
			memzero_explicit(tmp, sizeof(tmp));
		} else {
			hmac_sha512_final(&ctx, &okm[i]);
		}
		counter++;
	}

void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf)
{
	crypto_free_shash(hkdf->hmac_tfm);
}
Loading