Add commands for changing and removing passphrase

This commit is contained in:
Kent Overstreet 2017-11-08 16:03:59 -09:00
parent b984559329
commit 097fd2a5e6
9 changed files with 159 additions and 72 deletions

View File

@ -36,7 +36,6 @@ static void usage(void)
" fsck Check an existing filesystem for errors\n" " fsck Check an existing filesystem for errors\n"
"\n" "\n"
"Startup/shutdown, assembly of multi device filesystems:\n" "Startup/shutdown, assembly of multi device filesystems:\n"
" unlock Unlock an encrypted filesystem prior to running/mounting\n"
" assemble Assemble an existing multi device filesystem\n" " assemble Assemble an existing multi device filesystem\n"
" incremental Incrementally assemble an existing multi device filesystem\n" " incremental Incrementally assemble an existing multi device filesystem\n"
" run Start a partially assembled filesystem\n" " run Start a partially assembled filesystem\n"
@ -54,6 +53,11 @@ static void usage(void)
" device evacuate Migrate data off of a specific device\n" " device evacuate Migrate data off of a specific device\n"
" device set-state Mark a device as failed\n" " device set-state Mark a device as failed\n"
"\n" "\n"
"Encryption:\n"
" unlock Unlock an encrypted filesystem prior to running/mounting\n"
" set-passphrase Change passphrase on an existing (unmounted) filesystem\n"
" remove-passphrase Remove passphrase on an existing (unmounted) filesystem\n"
"\n"
"Migrate:\n" "Migrate:\n"
" migrate Migrate an existing filesystem to bcachefs, in place\n" " migrate Migrate an existing filesystem to bcachefs, in place\n"
" migrate-superblock\n" " migrate-superblock\n"
@ -133,8 +137,6 @@ int main(int argc, char *argv[])
if (!strcmp(cmd, "fsck")) if (!strcmp(cmd, "fsck"))
return cmd_fsck(argc, argv); return cmd_fsck(argc, argv);
if (!strcmp(cmd, "unlock"))
return cmd_unlock(argc, argv);
if (!strcmp(cmd, "assemble")) if (!strcmp(cmd, "assemble"))
return cmd_assemble(argc, argv); return cmd_assemble(argc, argv);
if (!strcmp(cmd, "incremental")) if (!strcmp(cmd, "incremental"))
@ -150,6 +152,13 @@ int main(int argc, char *argv[])
if (!strcmp(cmd, "device")) if (!strcmp(cmd, "device"))
return device_cmds(argc, argv); return device_cmds(argc, argv);
if (!strcmp(cmd, "unlock"))
return cmd_unlock(argc, argv);
if (!strcmp(cmd, "set-passphrase"))
return cmd_set_passphrase(argc, argv);
if (!strcmp(cmd, "remove-passphrase"))
return cmd_remove_passphrase(argc, argv);
if (!strcmp(cmd, "migrate")) if (!strcmp(cmd, "migrate"))
return cmd_migrate(argc, argv); return cmd_migrate(argc, argv);
if (!strcmp(cmd, "migrate-superblock")) if (!strcmp(cmd, "migrate-superblock"))

View File

@ -25,6 +25,7 @@
#include "libbcachefs.h" #include "libbcachefs.h"
#include "crypto.h" #include "crypto.h"
#include "opts.h" #include "opts.h"
#include "super-io.h"
#include "util.h" #include "util.h"
#define OPTS \ #define OPTS \
@ -250,24 +251,8 @@ int cmd_format(int argc, char *argv[])
if (!darray_size(devices)) if (!darray_size(devices))
die("Please supply a device"); die("Please supply a device");
if (opts.encrypted && !no_passphrase) { if (opts.encrypted && !no_passphrase)
opts.passphrase = read_passphrase("Enter passphrase: "); opts.passphrase = read_passphrase_twice("Enter passphrase: ");
if (isatty(STDIN_FILENO)) {
char *pass2 =
read_passphrase("Enter same passphrase again: ");
if (strcmp(opts.passphrase, pass2)) {
memzero_explicit(opts.passphrase,
strlen(opts.passphrase));
memzero_explicit(pass2, strlen(pass2));
die("Passphrases do not match");
}
memzero_explicit(pass2, strlen(pass2));
free(pass2);
}
}
darray_foreach(dev, devices) darray_foreach(dev, devices)
dev->fd = open_for_format(dev->path, force); dev->fd = open_for_format(dev->path, force);
@ -289,12 +274,16 @@ int cmd_format(int argc, char *argv[])
int cmd_show_super(int argc, char *argv[]) int cmd_show_super(int argc, char *argv[])
{ {
struct bch_sb *sb; struct bch_sb_handle sb;
const char *err;
if (argc != 2) if (argc != 2)
die("please supply a single device"); die("please supply a single device");
sb = bch2_super_read(argv[1]); err = bch2_read_super(argv[1], bch2_opts_empty(), &sb);
bch2_super_print(sb, HUMAN_READABLE); if (err)
die("Error opening %s: %s", argv[1], err);
bch2_super_print(sb.sb, HUMAN_READABLE);
return 0; return 0;
} }

View File

@ -9,19 +9,92 @@
int cmd_unlock(int argc, char *argv[]) int cmd_unlock(int argc, char *argv[])
{ {
struct bch_sb *sb; struct bch_sb_handle sb;
const char *err;
char *passphrase; char *passphrase;
if (argc != 2) if (argc != 2)
die("please supply a single device"); die("Please supply a single device");
sb = bch2_super_read(argv[1]); err = bch2_read_super(argv[1], bch2_opts_empty(), &sb);
if (err)
die("Error opening %s: %s", argv[1], err);
passphrase = read_passphrase("Enter passphrase: "); passphrase = read_passphrase("Enter passphrase: ");
bch2_add_key(sb, passphrase); bch2_add_key(sb.sb, passphrase);
memzero_explicit(passphrase, strlen(passphrase)); memzero_explicit(passphrase, strlen(passphrase));
free(passphrase); free(passphrase);
return 0; return 0;
} }
int cmd_set_passphrase(int argc, char *argv[])
{
struct bch_opts opts = bch2_opts_empty();
struct bch_fs *c = NULL;
const char *err;
if (argc < 2)
die("Please supply one or more devices");
opt_set(opts, nostart, true);
err = bch2_fs_open(argv + 1, argc - 1, opts, &c);
if (err)
die("Error opening %s: %s", argv[1], err);
struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(c->disk_sb);
if (!crypt)
die("Filesystem does not have encryption enabled");
struct bch_encrypted_key new_key;
new_key.magic = BCH_KEY_MAGIC;
int ret = bch2_decrypt_sb_key(c, crypt, &new_key.key);
if (ret)
die("Error getting current key");
char *new_passphrase = read_passphrase_twice("Enter new passphrase: ");
struct bch_key passphrase_key = derive_passphrase(crypt, new_passphrase);
if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(c->disk_sb),
&new_key, sizeof(new_key)))
die("error encrypting key");
crypt->key = new_key;
bch2_write_super(c);
bch2_fs_stop(c);
return 0;
}
int cmd_remove_passphrase(int argc, char *argv[])
{
struct bch_opts opts = bch2_opts_empty();
struct bch_fs *c = NULL;
const char *err;
if (argc < 2)
die("Please supply one or more devices");
opt_set(opts, nostart, true);
err = bch2_fs_open(argv + 1, argc - 1, opts, &c);
if (err)
die("Error opening %s: %s", argv[1], err);
struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(c->disk_sb);
if (!crypt)
die("Filesystem does not have encryption enabled");
struct bch_encrypted_key new_key;
new_key.magic = BCH_KEY_MAGIC;
int ret = bch2_decrypt_sb_key(c, crypt, &new_key.key);
if (ret)
die("Error getting current key");
crypt->key = new_key;
bch2_write_super(c);
bch2_fs_stop(c);
return 0;
}

View File

@ -701,24 +701,8 @@ int cmd_migrate(int argc, char *argv[])
find_superblock_space(extents, &dev); find_superblock_space(extents, &dev);
if (format_opts.encrypted && !no_passphrase) { if (format_opts.encrypted && !no_passphrase)
format_opts.passphrase = read_passphrase("Enter passphrase: "); format_opts.passphrase = read_passphrase_twice("Enter passphrase: ");
if (isatty(STDIN_FILENO)) {
char *pass2 =
read_passphrase("Enter same passphrase again: ");
if (strcmp(format_opts.passphrase, pass2)) {
memzero_explicit(format_opts.passphrase,
strlen(format_opts.passphrase));
memzero_explicit(pass2, strlen(pass2));
die("Passphrases do not match");
}
memzero_explicit(pass2, strlen(pass2));
free(pass2);
}
}
struct bch_sb *sb = bch2_format(format_opts, &dev, 1); struct bch_sb *sb = bch2_format(format_opts, &dev, 1);
u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]); u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);

5
cmds.h
View File

@ -12,7 +12,6 @@
int cmd_format(int argc, char *argv[]); int cmd_format(int argc, char *argv[]);
int cmd_show_super(int argc, char *argv[]); int cmd_show_super(int argc, char *argv[]);
int cmd_unlock(int argc, char *argv[]);
int cmd_assemble(int argc, char *argv[]); int cmd_assemble(int argc, char *argv[]);
int cmd_incremental(int argc, char *argv[]); int cmd_incremental(int argc, char *argv[]);
int cmd_run(int argc, char *argv[]); int cmd_run(int argc, char *argv[]);
@ -28,6 +27,10 @@ int cmd_device_offline(int argc, char *argv[]);
int cmd_device_evacuate(int argc, char *argv[]); int cmd_device_evacuate(int argc, char *argv[]);
int cmd_device_set_state(int argc, char *argv[]); int cmd_device_set_state(int argc, char *argv[]);
int cmd_unlock(int argc, char *argv[]);
int cmd_set_passphrase(int argc, char *argv[]);
int cmd_remove_passphrase(int argc, char *argv[]);
int cmd_fsck(int argc, char *argv[]); int cmd_fsck(int argc, char *argv[]);
int cmd_dump(int argc, char *argv[]); int cmd_dump(int argc, char *argv[]);

View File

@ -54,11 +54,32 @@ char *read_passphrase(const char *prompt)
return buf; return buf;
} }
void derive_passphrase(struct bch_sb_field_crypt *crypt, char *read_passphrase_twice(const char *prompt)
struct bch_key *key, {
const char *passphrase) char *pass = read_passphrase(prompt);
if (!isatty(STDIN_FILENO))
return pass;
char *pass2 = read_passphrase("Enter same passphrase again: ");
if (strcmp(pass, pass2)) {
memzero_explicit(pass, strlen(pass));
memzero_explicit(pass2, strlen(pass2));
die("Passphrases do not match");
}
memzero_explicit(pass2, strlen(pass2));
free(pass2);
return pass;
}
struct bch_key derive_passphrase(struct bch_sb_field_crypt *crypt,
const char *passphrase)
{ {
const unsigned char salt[] = "bcache"; const unsigned char salt[] = "bcache";
struct bch_key key;
int ret; int ret;
switch (BCH_CRYPT_KDF_TYPE(crypt)) { switch (BCH_CRYPT_KDF_TYPE(crypt)) {
@ -68,35 +89,49 @@ void derive_passphrase(struct bch_sb_field_crypt *crypt,
1ULL << BCH_KDF_SCRYPT_N(crypt), 1ULL << BCH_KDF_SCRYPT_N(crypt),
1ULL << BCH_KDF_SCRYPT_R(crypt), 1ULL << BCH_KDF_SCRYPT_R(crypt),
1ULL << BCH_KDF_SCRYPT_P(crypt), 1ULL << BCH_KDF_SCRYPT_P(crypt),
(void *) key, sizeof(*key)); (void *) &key, sizeof(key));
if (ret) if (ret)
die("scrypt error: %i", ret); die("scrypt error: %i", ret);
break; break;
default: default:
die("unknown kdf type %llu", BCH_CRYPT_KDF_TYPE(crypt)); die("unknown kdf type %llu", BCH_CRYPT_KDF_TYPE(crypt));
} }
return key;
} }
void bch2_add_key(struct bch_sb *sb, const char *passphrase) void bch2_passphrase_check(struct bch_sb *sb, const char *passphrase,
struct bch_key *passphrase_key,
struct bch_encrypted_key *sb_key)
{ {
struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(sb); struct bch_sb_field_crypt *crypt = bch2_sb_get_crypt(sb);
if (!crypt) if (!crypt)
die("filesystem is not encrypted"); die("filesystem is not encrypted");
struct bch_encrypted_key sb_key = crypt->key; *sb_key = crypt->key;
if (!bch2_key_is_encrypted(&sb_key))
if (!bch2_key_is_encrypted(sb_key))
die("filesystem does not have encryption key"); die("filesystem does not have encryption key");
struct bch_key passphrase_key; *passphrase_key = derive_passphrase(crypt, passphrase);
derive_passphrase(crypt, &passphrase_key, passphrase);
/* Check if the user supplied the correct passphrase: */ /* Check if the user supplied the correct passphrase: */
if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb), if (bch2_chacha_encrypt_key(passphrase_key, __bch2_sb_key_nonce(sb),
&sb_key, sizeof(sb_key))) sb_key, sizeof(*sb_key)))
die("error encrypting key"); die("error encrypting key");
if (bch2_key_is_encrypted(&sb_key)) if (bch2_key_is_encrypted(sb_key))
die("incorrect passphrase"); die("incorrect passphrase");
}
void bch2_add_key(struct bch_sb *sb, const char *passphrase)
{
struct bch_key passphrase_key;
struct bch_encrypted_key sb_key;
bch2_passphrase_check(sb, passphrase,
&passphrase_key,
&sb_key);
char uuid[40]; char uuid[40];
uuid_unparse_lower(sb->user_uuid.b, uuid); uuid_unparse_lower(sb->user_uuid.b, uuid);
@ -125,14 +160,13 @@ void bch_sb_crypt_init(struct bch_sb *sb,
get_random_bytes(&crypt->key.key, sizeof(crypt->key.key)); get_random_bytes(&crypt->key.key, sizeof(crypt->key.key));
if (passphrase) { if (passphrase) {
struct bch_key passphrase_key;
SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT); SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT);
SET_BCH_KDF_SCRYPT_N(crypt, ilog2(SCRYPT_N)); SET_BCH_KDF_SCRYPT_N(crypt, ilog2(SCRYPT_N));
SET_BCH_KDF_SCRYPT_R(crypt, ilog2(SCRYPT_r)); SET_BCH_KDF_SCRYPT_R(crypt, ilog2(SCRYPT_r));
SET_BCH_KDF_SCRYPT_P(crypt, ilog2(SCRYPT_p)); SET_BCH_KDF_SCRYPT_P(crypt, ilog2(SCRYPT_p));
derive_passphrase(crypt, &passphrase_key, passphrase); struct bch_key passphrase_key = derive_passphrase(crypt, passphrase);
assert(!bch2_key_is_encrypted(&crypt->key)); assert(!bch2_key_is_encrypted(&crypt->key));

View File

@ -6,10 +6,14 @@
struct bch_sb; struct bch_sb;
struct bch_sb_field_crypt; struct bch_sb_field_crypt;
struct bch_key; struct bch_key;
struct bch_encrypted_key;
char *read_passphrase(const char *); char *read_passphrase(const char *);
void derive_passphrase(struct bch_sb_field_crypt *, char *read_passphrase_twice(const char *);
struct bch_key *, const char *);
struct bch_key derive_passphrase(struct bch_sb_field_crypt *, const char *);
void bch2_passphrase_check(struct bch_sb *, const char *,
struct bch_key *, struct bch_encrypted_key *);
void bch2_add_key(struct bch_sb *, const char *); void bch2_add_key(struct bch_sb *, const char *);
void bch_sb_crypt_init(struct bch_sb *sb, struct bch_sb_field_crypt *, void bch_sb_crypt_init(struct bch_sb *sb, struct bch_sb_field_crypt *,
const char *); const char *);

View File

@ -293,14 +293,6 @@ struct bch_sb *__bch2_super_read(int fd, u64 sector)
return ret; return ret;
} }
struct bch_sb *bch2_super_read(const char *path)
{
int fd = xopen(path, O_RDONLY);
struct bch_sb *sb = __bch2_super_read(fd, BCH_SB_SECTOR);
close(fd);
return sb;
}
static unsigned get_dev_has_data(struct bch_sb *sb, unsigned dev) static unsigned get_dev_has_data(struct bch_sb *sb, unsigned dev)
{ {
struct bch_sb_field_replicas *replicas; struct bch_sb_field_replicas *replicas;

View File

@ -73,7 +73,6 @@ struct bch_sb *bch2_format(struct format_opts, struct dev_opts *, size_t);
void bch2_super_write(int, struct bch_sb *); void bch2_super_write(int, struct bch_sb *);
struct bch_sb *__bch2_super_read(int, u64); struct bch_sb *__bch2_super_read(int, u64);
struct bch_sb *bch2_super_read(const char *);
void bch2_super_print(struct bch_sb *, int); void bch2_super_print(struct bch_sb *, int);