All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johannes Thumshirn <jth@kernel.org>
To: David Sterba <dsterba@suse.cz>
Cc: "linux-btrfs @ vger . kernel . org" <linux-btrfs@vger.kernel.org>,
	Johannes Thumshirn <johannes.thumshirn@wdc.com>
Subject: [PATCH v2 3/5] btrfs-progs: Add HMAC(SHA256) support
Date: Thu, 14 May 2020 11:34:31 +0200	[thread overview]
Message-ID: <20200514093433.6818-4-jth@kernel.org> (raw)
In-Reply-To: <20200514093433.6818-1-jth@kernel.org>

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

Add support for authenticated file systems using HMAC(SHA256) as
checksumming algorithm.

Example:
mkfs.btrfs --csum hmac-sha256 --auth-key 0123456789 -f test.img

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
 cmds/inspect-dump-super.c |  5 ++++-
 common/utils.c            |  3 +++
 configure.ac              |  1 -
 crypto/hash.c             | 30 ++++++++++++++++++++++++++++++
 crypto/hash.h             |  2 ++
 ctree.c                   |  1 +
 ctree.h                   |  3 +++
 disk-io.c                 |  7 ++++++-
 mkfs/common.c             | 10 ++++++++++
 mkfs/common.h             |  3 +++
 mkfs/main.c               | 22 +++++++++++++++++++++-
 11 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/cmds/inspect-dump-super.c b/cmds/inspect-dump-super.c
index 99f35def..dd42d180 100644
--- a/cmds/inspect-dump-super.c
+++ b/cmds/inspect-dump-super.c
@@ -319,6 +319,7 @@ static bool is_valid_csum_type(u16 csum_type)
 	case BTRFS_CSUM_TYPE_XXHASH:
 	case BTRFS_CSUM_TYPE_SHA256:
 	case BTRFS_CSUM_TYPE_BLAKE2:
+	case BTRFS_CSUM_TYPE_HMAC_SHA256:
 		return true;
 	default:
 		return false;
@@ -352,7 +353,9 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
 	printf("csum\t\t\t0x");
 	for (i = 0, p = sb->csum; i < csum_size; i++)
 		printf("%02x", p[i]);
-	if (!is_valid_csum_type(csum_type))
+	if (csum_type == BTRFS_CSUM_TYPE_HMAC_SHA256)
+		printf(" [NO KEY FOR HMAC]");
+	else if (!is_valid_csum_type(csum_type))
 		printf(" [UNKNOWN CSUM TYPE OR SIZE]");
 	else if (check_csum_sblock(sb, csum_size, csum_type))
 		printf(" [match]");
diff --git a/common/utils.c b/common/utils.c
index 2517bb34..9c1d9a1b 100644
--- a/common/utils.c
+++ b/common/utils.c
@@ -774,6 +774,9 @@ enum btrfs_csum_type parse_csum_type(const char *s)
 	} else if (strcasecmp(s, "blake2b") == 0 ||
 		   strcasecmp(s, "blake2") == 0) {
 		return BTRFS_CSUM_TYPE_BLAKE2;
+	} else if (strcasecmp(s, "hmac-sha256") == 0 ||
+		   strcasecmp(s, "hmac(sha256)") == 0) {
+		return BTRFS_CSUM_TYPE_HMAC_SHA256;
 	} else {
 		error("unknown csum type %s", s);
 		exit(1);
diff --git a/configure.ac b/configure.ac
index 24b1641f..c842570c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -295,7 +295,6 @@ AC_SUBST([LZO2_LIBS])
 AC_SUBST([LZO2_LIBS_STATIC])
 AC_SUBST([LZO2_CFLAGS])
 
-
 dnl library stuff
 AC_SUBST([LIBBTRFS_MAJOR])
 AC_SUBST([LIBBTRFS_MINOR])
diff --git a/crypto/hash.c b/crypto/hash.c
index fc658475..b1cdfe67 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -1,3 +1,7 @@
+#include <gcrypt.h>
+
+#include "ctree.h"
+
 #include "crypto/hash.h"
 #include "crypto/crc32c.h"
 #include "crypto/xxhash.h"
@@ -72,12 +76,25 @@ int hash_blake2b(const u8 *buf, size_t len, u8 *out)
 	return 0;
 }
 
+int hash_hmac_sha256(struct btrfs_fs_info *fs_info, const u8 *buf,
+		     size_t length, u8 *out)
+{
+	gcry_mac_hd_t mac;
+	gcry_mac_open(&mac, GCRY_MAC_HMAC_SHA256, 0, NULL);
+	gcry_mac_setkey(mac, fs_info->auth_key, strlen(fs_info->auth_key));
+	gcry_mac_write(mac, buf, length);
+	gcry_mac_read(mac, out, &length);
+
+	return 0;
+}
+
 #endif
 
 #if CRYPTOPROVIDER_LIBSODIUM == 1
 
 #include <sodium/crypto_hash_sha256.h>
 #include <sodium/crypto_generichash_blake2b.h>
+#include <sodium/crypto_auth_hmacsha256.h>
 
 int hash_sha256(const u8 *buf, size_t len, u8 *out)
 {
@@ -90,4 +107,17 @@ int hash_blake2b(const u8 *buf, size_t len, u8 *out)
 			NULL, 0);
 }
 
+int hash_hmac_sha256(struct btrfs_fs_info *fs_info, const u8 *buf,
+		     size_t length, u8 *out)
+{
+	crypto_auth_hmacsha256_state state;
+
+	crypto_auth_hmacsha256_init(&state, (unsigned char *)fs_info->auth_key,
+				    strlen(fs_info->auth_key));
+	crypto_auth_hmacsha256_update(&state, buf, length);
+	crypto_auth_hmacsha256_final(&state, out);
+
+	return 0;
+}
+
 #endif
diff --git a/crypto/hash.h b/crypto/hash.h
index fefccbd5..252ce9f9 100644
--- a/crypto/hash.h
+++ b/crypto/hash.h
@@ -9,5 +9,7 @@ int hash_crc32c(const u8 *buf, size_t length, u8 *out);
 int hash_xxhash(const u8 *buf, size_t length, u8 *out);
 int hash_sha256(const u8 *buf, size_t length, u8 *out);
 int hash_blake2b(const u8 *buf, size_t length, u8 *out);
+int hash_hmac_sha256(struct btrfs_fs_info *fs_info, const u8 *buf,
+		     size_t length, u8 *out);
 
 #endif
diff --git a/ctree.c b/ctree.c
index 3559680f..25a1e865 100644
--- a/ctree.c
+++ b/ctree.c
@@ -46,6 +46,7 @@ static const struct btrfs_csum {
 	[BTRFS_CSUM_TYPE_XXHASH]	= {  8, "xxhash64" },
 	[BTRFS_CSUM_TYPE_SHA256]	= { 32, "sha256" },
 	[BTRFS_CSUM_TYPE_BLAKE2]	= { 32, "blake2" },
+	[BTRFS_CSUM_TYPE_HMAC_SHA256]	= { 32, "hmac-sha256" },
 };
 
 u16 btrfs_super_csum_size(const struct btrfs_super_block *sb)
diff --git a/ctree.h b/ctree.h
index 2a871187..c8482596 100644
--- a/ctree.h
+++ b/ctree.h
@@ -172,6 +172,7 @@ enum btrfs_csum_type {
 	BTRFS_CSUM_TYPE_XXHASH		= 1,
 	BTRFS_CSUM_TYPE_SHA256		= 2,
 	BTRFS_CSUM_TYPE_BLAKE2		= 3,
+	BTRFS_CSUM_TYPE_HMAC_SHA256	= 4,
 };
 
 #define BTRFS_EMPTY_DIR_SIZE 0
@@ -1212,6 +1213,8 @@ struct btrfs_fs_info {
 	u32 nodesize;
 	u32 sectorsize;
 	u32 stripesize;
+
+	char *auth_key;
 };
 
 /*
diff --git a/disk-io.c b/disk-io.c
index 6221c3ce..5fa1f0c3 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -153,6 +153,10 @@ int btrfs_csum_data(struct btrfs_fs_info *fs_info, u16 csum_type,
 		return hash_sha256(data, len, out);
 	case BTRFS_CSUM_TYPE_BLAKE2:
 		return hash_blake2b(data, len, out);
+	case BTRFS_CSUM_TYPE_HMAC_SHA256:
+		if (!fs_info || !fs_info->auth_key)
+			return 0;
+		return hash_hmac_sha256(fs_info, data, len, out);
 	default:
 		fprintf(stderr, "ERROR: unknown csum type: %d\n", csum_type);
 		ASSERT(0);
@@ -837,6 +841,7 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr,
 	fs_info->data_alloc_profile = (u64)-1;
 	fs_info->metadata_alloc_profile = (u64)-1;
 	fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
+	fs_info->auth_key = auth_key;
 	return fs_info;
 free_all:
 	btrfs_free_fs_info(fs_info);
@@ -1418,7 +1423,7 @@ int btrfs_check_super(struct btrfs_super_block *sb, unsigned sbflags)
 	btrfs_csum_data(NULL, csum_type, (u8 *)sb + BTRFS_CSUM_SIZE,
 			result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
 
-	if (memcmp(result, sb->csum, csum_size)) {
+	if (memcmp(result, sb->csum, csum_size) && csum_type != BTRFS_CSUM_TYPE_HMAC_SHA256) {
 		error("superblock checksum mismatch");
 		return -EIO;
 	}
diff --git a/mkfs/common.c b/mkfs/common.c
index 469b88d6..81d0b5c1 100644
--- a/mkfs/common.c
+++ b/mkfs/common.c
@@ -160,6 +160,13 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
 	if (!buf)
 		return -ENOMEM;
 
+	buf->fs_info = calloc(1, sizeof(struct btrfs_fs_info));
+	if (!buf->fs_info) {
+		free(buf);
+		return -ENOMEM;
+	}
+
+
 	first_free = BTRFS_SUPER_INFO_OFFSET + cfg->sectorsize * 2 - 1;
 	first_free &= ~((u64)cfg->sectorsize - 1);
 
@@ -224,6 +231,8 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
 			    btrfs_header_chunk_tree_uuid(buf),
 			    BTRFS_UUID_SIZE);
 
+	buf->fs_info->auth_key = cfg->auth_key;
+
 	ret = btrfs_create_tree_root(fd, cfg, buf);
 	if (ret < 0)
 		goto out;
@@ -474,6 +483,7 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
 	ret = 0;
 
 out:
+	free(buf->fs_info);
 	free(buf);
 	return ret;
 }
diff --git a/mkfs/common.h b/mkfs/common.h
index 426852be..7aea13cd 100644
--- a/mkfs/common.h
+++ b/mkfs/common.h
@@ -65,6 +65,9 @@ struct btrfs_mkfs_config {
 
 	/* Superblock offset after make_btrfs */
 	u64 super_bytenr;
+
+	/* authentication key */
+	char *auth_key;
 };
 
 int make_btrfs(int fd, struct btrfs_mkfs_config *cfg);
diff --git a/mkfs/main.c b/mkfs/main.c
index e830de4e..9f783cc1 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -343,6 +343,7 @@ static void print_usage(int ret)
 	printf("  features:\n");
 	printf("\t--csum TYPE\n");
 	printf("\t--checksum TYPE         checksum algorithm to use (default: crc32c)\n");
+	printf("\t--auth-key KEY          authentication key to use for authenticated file-systems\n");
 	printf("\t-n|--nodesize SIZE      size of btree nodes\n");
 	printf("\t-s|--sectorsize SIZE    data block size (may not be mountable by current kernel)\n");
 	printf("\t-O|--features LIST      comma separated list of filesystem features (use '-O list-all' to list features)\n");
@@ -839,14 +840,21 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	struct mkfs_allocation allocation = { 0 };
 	struct btrfs_mkfs_config mkfs_cfg;
 	enum btrfs_csum_type csum_type = BTRFS_CSUM_TYPE_CRC32;
+	char *auth_key = NULL;
 
 	crc32c_optimization_init();
 
 	while(1) {
 		int c;
-		enum { GETOPT_VAL_SHRINK = 257, GETOPT_VAL_CHECKSUM };
+		enum {
+			GETOPT_VAL_SHRINK = 257,
+			GETOPT_VAL_CHECKSUM,
+			GETOPT_VAL_AUTHKEY,
+		};
 		static const struct option long_options[] = {
 			{ "alloc-start", required_argument, NULL, 'A'},
+			{ "auth-key", required_argument, NULL,
+				GETOPT_VAL_AUTHKEY },
 			{ "byte-count", required_argument, NULL, 'b' },
 			{ "csum", required_argument, NULL,
 				GETOPT_VAL_CHECKSUM },
@@ -952,6 +960,9 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 			case GETOPT_VAL_CHECKSUM:
 				csum_type = parse_csum_type(optarg);
 				break;
+			case GETOPT_VAL_AUTHKEY:
+				auth_key = strdup(optarg);
+				break;
 			case GETOPT_VAL_HELP:
 			default:
 				print_usage(c != GETOPT_VAL_HELP);
@@ -979,6 +990,12 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 		goto error;
 	}
 
+	if ((auth_key && csum_type != BTRFS_CSUM_TYPE_HMAC_SHA256) ||
+	    (csum_type == BTRFS_CSUM_TYPE_HMAC_SHA256 && !auth_key)) {
+		error("the option --auth-key must be used with --csum hmac(sha256)");
+		goto error;
+	}
+
 	if (*fs_uuid) {
 		uuid_t dummy_uuid;
 
@@ -1197,6 +1214,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	mkfs_cfg.stripesize = stripesize;
 	mkfs_cfg.features = features;
 	mkfs_cfg.csum_type = csum_type;
+	mkfs_cfg.auth_key = auth_key;
 
 	ret = make_btrfs(fd, &mkfs_cfg);
 	if (ret) {
@@ -1413,6 +1431,7 @@ out:
 
 	btrfs_close_all_devices();
 	free(label);
+	free(auth_key);
 
 	return !!ret;
 error:
@@ -1420,6 +1439,7 @@ error:
 		close(fd);
 
 	free(label);
+	free(auth_key);
 	exit(1);
 success:
 	exit(0);
-- 
2.26.1


  parent reply	other threads:[~2020-05-14  9:35 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-14  9:34 [PATCH v2 0/5] btrfs-progs: support creating authenticated file-systems Johannes Thumshirn
2020-05-14  9:34 ` [PATCH v2 1/5] btrfs-progs: pass in fs_info to btrfs_csum_data Johannes Thumshirn
2020-05-14  9:34 ` [PATCH v2 2/5] btrfs-progs: add auth_key argument to open_ctree_fs_info Johannes Thumshirn
2020-05-14  9:34 ` Johannes Thumshirn [this message]
2020-06-05  8:10   ` [PATCH v2 3/5] btrfs-progs: Add HMAC(SHA256) support Anand Jain
2020-05-14  9:34 ` [PATCH v2 4/5] btrfs-progs: add --auth-key to dump-super Johannes Thumshirn
2020-05-14  9:34 ` [PATCH v2 5/5] btrfs-progs: add auth key to check Johannes Thumshirn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200514093433.6818-4-jth@kernel.org \
    --to=jth@kernel.org \
    --cc=dsterba@suse.cz \
    --cc=johannes.thumshirn@wdc.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.