Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,17 @@ tips](https://github.com/google/fscrypt#getting-encryption-not-enabled-on-an-ext
For full usage details, see the manual page (`man fscryptctl`), or alternatively
run `fscryptctl --help`.

The `add_key` command accepts the encryption key in binary on standard input.
The `add_key` command, by default, accepts the encryption key in binary on
standard input.
It is critical that this be a real cryptographic key (and not a passphrase, for
example), since `fscryptctl` doesn't do key stretching itself. Obviously, don't
store the raw encryption key alongside the encrypted files. (If you need
support for passphrases, use `fscrypt` instead of `fscryptctl`.)

Alternatively, `add_key --serial=$serial` will instruct the kernel to
extract the kernel material from an existing key of type "fscrypt-provisioning"
with the specified $serial (The ID returned and used by keyctl(1)).

After running the `add_key` command to add an encryption key to a filesystem,
you can use the `set_policy` command to create an encrypted directory on that
filesystem. The encryption key is specified by the 32-character hex "key
Expand Down
10 changes: 8 additions & 2 deletions fscryptctl.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ feature, see the references at the end of this page.

# SUBCOMMANDS

## **fscryptctl add_key** *MOUNTPOINT*
## **fscryptctl add_key** [*OPTION*..] *MOUNTPOINT*

Add an encryption key to the given mounted filesystem. This will "unlock" any
files and directories that are protected by the given key on the given
Expand All @@ -54,7 +54,13 @@ If successful, **fscryptctl add_key** will print the key identifier of the newly
added key; this will be a 32-character hex string which can be passed to other
**fscryptctl** commands.

**fscryptctl add_key** does not accept any options.
Options accepted by **fscryptctl add_key**:

**\-\-serial**=*SERIAL*
: Don't read raw key material from standard input. Instead, instruct the
kernel to extract key material from an existing key of type
`fscrypt-provisioning` with specified SERIAL. SERIAL is the ID returned
and used by keyctl(1).

## **fscryptctl remove_key** [*OPTION*...] *KEY_IDENTIFIER* *MOUNTPOINT*

Expand Down
57 changes: 50 additions & 7 deletions fscryptctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -78,6 +79,7 @@ static const char *const mode_strings[] = {
static const int padding_values[] = {4, 8, 16, 32};

enum {
OPT_KEY_SERIAL,
OPT_ALL_USERS,
OPT_CONTENTS,
OPT_DIRECT_KEY,
Expand All @@ -94,8 +96,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
" fscryptctl <command> [arguments] [options]\n"
"\nCommands:\n"
" fscryptctl add_key <mountpoint>\n"
" Read a key from stdin, add it to the specified mounted filesystem,\n"
" and print its identifier.\n"
" Add a key add to the specified mounted filesystem and print its\n"
" identifier. Raw key is read from stdin by default.\n"
" fscryptctl remove_key <key identifier> <mountpoint>\n"
" Remove the key with the specified identifier from the specified\n"
" mounted filesystem.\n"
Expand All @@ -112,6 +114,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
" print this help screen\n"
" -v, --version\n"
" print the version of fscrypt\n"
" add_key\n"
" --serial=<serial>\n"
" Instead of reading raw key material over stdin, use the\n"
" payload of an existing \"fscrypt-provisioning\" key.\n"
" remove_key\n"
" --all-users\n"
" force-remove all users' claims to the key (requires root)\n"
Expand All @@ -129,7 +135,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
" --iv-ino-lblk-32\n"
" optimize for eMMC inline crypto hardware (not recommended)\n"
"\nNotes:\n"
" Keys are identified by 32-character hex strings (key identifiers).\n"
" fscrypt keys are identified by 32-character hex strings\n"
" (key identifiers).\n"
"\n"
" Key serials are specified as decimal integers that fit into 31 bits.\n"
"\n"
" Raw keys are given on stdin in binary and usually must be 64 bytes.\n"
"\n"
Expand Down Expand Up @@ -267,6 +276,16 @@ static bool hex_to_bytes(const char *hex, uint8_t *bytes, size_t num_bytes) {
return true;
}

// Converts a decimal string to a kernel key_serial_t
static int32_t str_to_keyserial(const char *dec) {
char *endp;
unsigned long ret = strtoul(dec, &endp, 10);
if (ret < 1 || ret > INT32_MAX || *endp) {
return -1;
}
return ret;
}

// Builds a 'struct fscrypt_key_specifier' for passing to the kernel, given a
// key identifier hex string.
static bool build_key_specifier(const char *identifier_hex,
Expand Down Expand Up @@ -372,7 +391,27 @@ static bool set_policy(const char *path,
// -----------------------------------------------------------------------------

static int cmd_add_key(int argc, char *const argv[]) {
handle_no_options(&argc, &argv);
int32_t serial = 0;

static const struct option add_key_options[] = {
{"serial", required_argument, NULL, OPT_KEY_SERIAL}, {NULL, 0, NULL, 0}};

int ch;
while ((ch = getopt_long(argc, argv, "", add_key_options, NULL)) != -1) {
switch (ch) {
case OPT_KEY_SERIAL:
serial = str_to_keyserial(optarg);
if (serial < 0) {
fputs("error: must specify valid key id\n", stderr);
return EXIT_FAILURE;
}
break;
default:
usage(stderr);
}
}
argc -= optind;
argv += optind;
if (argc != 1) {
fputs("error: must specify a single mountpoint\n", stderr);
return EXIT_FAILURE;
Expand All @@ -387,9 +426,13 @@ static int cmd_add_key(int argc, char *const argv[]) {
}

int status = EXIT_FAILURE;
arg->raw_size = read_key(arg->raw);
if (arg->raw_size == 0) {
goto cleanup;
if (serial) {
arg->key_id = serial;
} else {
arg->raw_size = read_key(arg->raw);
if (arg->raw_size == 0) {
goto cleanup;
}
}
arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;

Expand Down