btrfs-progs: Add HMAC(SHA256) support

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>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Johannes Thumshirn 2020-05-14 11:34:31 +02:00 committed by David Sterba
parent bbf56a44a4
commit 067454f955
11 changed files with 83 additions and 4 deletions

View file

@ -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]");

View file

@ -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);

View file

@ -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])

View file

@ -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

View file

@ -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

View file

@ -47,6 +47,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)

View file

@ -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
@ -1213,6 +1214,8 @@ struct btrfs_fs_info {
u32 nodesize;
u32 sectorsize;
u32 stripesize;
char *auth_key;
};
/*

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -344,6 +344,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");
@ -951,14 +952,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 },
@ -1064,6 +1072,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);
@ -1091,6 +1102,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;
@ -1309,6 +1326,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) {
@ -1525,6 +1543,7 @@ out:
btrfs_close_all_devices();
free(label);
free(auth_key);
return !!ret;
error:
@ -1532,6 +1551,7 @@ error:
close(fd);
free(label);
free(auth_key);
exit(1);
success:
exit(0);