Skip to content

Commit 8ebbd97

Browse files
committed
Add support for creating and preparing hardware-wrapped keys
Add fscryptctl commands that wrap the BLKCRYPTOIMPORTKEY, BLKCRYPTOGENERATEKEY, and BLKCRYPTOPREPAREKEY ioctls that were added in Linux 6.15. These are needed to use hardware-wrapped keys.
1 parent e9ef440 commit 8ebbd97

File tree

4 files changed

+194
-3
lines changed

4 files changed

+194
-3
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
* `fscryptctl add_key` now supports the `--hw-wrapped-key` option.
66

7+
* Added new commands `fscryptctl import_hw_wrapped_key`,
8+
`fscryptctl generate_hw_wrapped_key`, and `fscryptctl prepare_hw_wrapped_key`.
9+
710
## Version 1.2.0
811

912
* `fscryptctl set_policy` now accepts the `--data-unit-size` option.

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ For the release notes, see the [NEWS file](NEWS.md).
2929
- [Runtime Dependencies](#runtime-dependencies)
3030
- [Features](#features)
3131
- [Example Usage](#example-usage)
32+
- [Example Usage with Hardware-Wrapped Key](#example-usage-with-hardware-wrapped-key)
3233
- [Contributing](#contributing)
3334
- [Legal](#legal)
3435

@@ -72,6 +73,9 @@ tips](https://github.com/google/fscrypt#getting-encryption-not-enabled-on-an-ext
7273
* `fscryptctl key_status` - get the status of an encryption key on a filesystem
7374
* `fscryptctl get_policy` - get the encryption policy of a file or directory
7475
* `fscryptctl set_policy` - set the encryption policy of an empty directory
76+
* `fscryptctl import_hw_wrapped_key` - import a hardware-wrapped key
77+
* `fscryptctl generate_hw_wrapped_key` - generate a hardware-wrapped key
78+
* `fscryptctl prepare_hw_wrapped_key` - prepare a hardware-wrapped key
7579

7680
For full usage details, see the manual page (`man fscryptctl`), or alternatively
7781
run `fscryptctl --help`.
@@ -154,6 +158,18 @@ bar foo
154158
foo
155159
```
156160

161+
## Example Usage with Hardware-Wrapped Key
162+
163+
```shell
164+
> mkfs.ext4 -O encrypt /dev/vdb
165+
> mount /dev/vdb -o inlinecrypt /mnt
166+
> head -c 32 /dev/urandom | fscryptctl import_hw_wrapped_key /dev/vdb > /tmp/lt_key
167+
> fscryptctl prepare_hw_wrapped_key /dev/vdb < /tmp/lt_key | fscryptctl add_key --hw-wrapped-key /mnt
168+
f12fccad977328d20a16c79627787a1c
169+
> mkdir /mnt/dir
170+
> fscryptctl set_policy f12fccad977328d20a16c79627787a1c /mnt/dir
171+
```
172+
157173
## Contributing
158174

159175
We would love to accept your contributions to `fscryptctl`. See the

fscryptctl.1.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ fscryptctl - low-level userspace tool for Linux filesystem encryption
99
**fscryptctl remove_key** [*OPTION*...] *KEY_IDENTIFIER* *MOUNTPOINT* \
1010
**fscryptctl key_status** *KEY_IDENTIFIER* *MOUNTPOINT* \
1111
**fscryptctl get_policy** *PATH* \
12-
**fscryptctl set_policy** [*OPTION*...] *KEY_IDENTIFIER* *DIRECTORY*
12+
**fscryptctl set_policy** [*OPTION*...] *KEY_IDENTIFIER* *DIRECTORY* \
13+
**fscryptctl import_hw_wrapped_key** *BLOCK_DEVICE* \
14+
**fscryptctl generate_hw_wrapped_key** *BLOCK_DEVICE* \
15+
**fscryptctl prepare_hw_wrapped_key** *BLOCK_DEVICE*
1316

1417
# DESCRIPTION
1518

@@ -147,6 +150,40 @@ Options accepted by **fscryptctl set_policy**:
147150
: Select the crypto data unit size, i.e. the granularity of file contents
148151
encryption, in bytes.
149152

153+
## **fscryptctl import_hw_wrapped_key** *BLOCK_DEVICE*
154+
155+
Create a hardware-wrapped inline encryption key by importing a raw key, turning
156+
it into a long-term wrapped key. The raw key is read from standard input and
157+
the long-term wrapped key blob is written to standard output, both in binary.
158+
159+
This subcommand is a thin wrapper around the **BLKCRYPTOIMPORTKEY** ioctl. For
160+
more information, see the kernel documentation.
161+
162+
**fscryptctl import_hw_wrapped_key** does not accept any options.
163+
164+
## **fscryptctl generate_hw_wrapped_key** *BLOCK_DEVICE*
165+
166+
Create a hardware-wrapped inline encryption key by having the hardware generate
167+
one. The new long-term wrapped key blob is written to standard output in
168+
binary.
169+
170+
This subcommand is a thin wrapper around the **BLKCRYPTOGENERATEKEY** ioctl.
171+
For more information, see the kernel documentation.
172+
173+
**fscryptctl generate_hw_wrapped_key** does not accept any options.
174+
175+
## **fscryptctl prepare_hw_wrapped_key** *BLOCK_DEVICE*
176+
177+
Prepares a hardware-wrapped inline encryption key to be used by converting it
178+
from long-term wrapped form to ephemerally-wrapped form. The long-term wrapped
179+
key blob is read from standard input and the ephemerally-wrapped key blob is
180+
written to standard output, both in binary.
181+
182+
This subcommand is a thin wrapper around the **BLKCRYPTOPREPAREKEY** ioctl. For
183+
more information, see the kernel documentation.
184+
185+
**fscryptctl prepare_hw_wrapped_key** does not accept any options.
186+
150187
# SEE ALSO
151188

152189
* [**fscryptctl** README
@@ -157,3 +194,6 @@ Options accepted by **fscryptctl set_policy**:
157194

158195
* [**fscrypt** tool, recommended for most users over
159196
fscryptctl](https://github.com/google/fscrypt)
197+
198+
* [Linux kernel documentation for hardware-wrapped
199+
keys](https://docs.kernel.org/block/inline-encryption.html#hardware-wrapped-keys)

fscryptctl.c

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <sys/utsname.h>
3535
#include <unistd.h>
3636

37+
#include "blk-crypto_uapi.h"
3738
#include "fscrypt_uapi.h"
3839

3940
#ifndef VERSION
@@ -134,6 +135,13 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
134135
" fscryptctl set_policy <key identifier> <directory>\n"
135136
" Set up an encryption policy on the specified directory with the\n"
136137
" specified key identifier.\n"
138+
" fscryptctl import_hw_wrapped_key <block device>\n"
139+
" Create a hardware-wrapped key by importing a raw key.\n"
140+
" fscryptctl generate_hw_wrapped_key <block device>\n"
141+
" Create a hardware-wrapped key by generating one in hardware.\n"
142+
" fscryptctl prepare_hw_wrapped_key <block device>\n"
143+
" Prepare a hardware-wrapped key to be used by converting it from\n"
144+
" long-term wrapped form to ephemerally-wrapped form.\n"
137145
"\nOptions:\n"
138146
" -h, --help\n"
139147
" print this help screen\n"
@@ -778,6 +786,125 @@ static int cmd_set_policy(int argc, char *const argv[]) {
778786
return EXIT_SUCCESS;
779787
}
780788

789+
static int cmd_import_hw_wrapped_key(int argc, char *const argv[]) {
790+
handle_no_options(&argc, &argv);
791+
if (argc != 1) {
792+
fputs("error: must specify a single block device\n", stderr);
793+
return EXIT_FAILURE;
794+
}
795+
const char *blkdev = argv[0];
796+
int status = EXIT_FAILURE;
797+
798+
struct blk_crypto_import_key_arg arg = {0};
799+
uint8_t *raw_key = xzalloc(FSCRYPT_MAX_KEY_SIZE);
800+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
801+
arg.raw_key_ptr = (uintptr_t)raw_key;
802+
arg.raw_key_size = read_key(raw_key, FSCRYPT_MAX_KEY_SIZE);
803+
if (arg.raw_key_size == 0) {
804+
goto cleanup;
805+
}
806+
arg.lt_key_ptr = (uintptr_t)lt_key;
807+
arg.lt_key_size = MAX_WRAPPED_KEY_SIZE;
808+
809+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
810+
if (fd < 0) {
811+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
812+
goto cleanup;
813+
}
814+
if (ioctl(fd, BLKCRYPTOIMPORTKEY, &arg) != 0) {
815+
fprintf(stderr, "error: importing hardware-wrapped key: %s\n",
816+
strerror(errno));
817+
close(fd);
818+
goto cleanup;
819+
}
820+
close(fd);
821+
if (!full_write(STDOUT_FILENO, lt_key, arg.lt_key_size)) {
822+
goto cleanup;
823+
}
824+
status = EXIT_SUCCESS;
825+
cleanup:
826+
wipe_and_free(raw_key, FSCRYPT_MAX_KEY_SIZE);
827+
wipe_and_free(lt_key, MAX_WRAPPED_KEY_SIZE);
828+
return status;
829+
}
830+
831+
static int cmd_generate_hw_wrapped_key(int argc, char *const argv[]) {
832+
handle_no_options(&argc, &argv);
833+
if (argc != 1) {
834+
fputs("error: must specify a single block device\n", stderr);
835+
return EXIT_FAILURE;
836+
}
837+
const char *blkdev = argv[0];
838+
int status = EXIT_FAILURE;
839+
840+
struct blk_crypto_generate_key_arg arg = {0};
841+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
842+
arg.lt_key_ptr = (uintptr_t)lt_key;
843+
arg.lt_key_size = MAX_WRAPPED_KEY_SIZE;
844+
845+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
846+
if (fd < 0) {
847+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
848+
goto cleanup;
849+
}
850+
if (ioctl(fd, BLKCRYPTOGENERATEKEY, &arg) != 0) {
851+
fprintf(stderr, "error: generating hardware-wrapped key: %s\n",
852+
strerror(errno));
853+
close(fd);
854+
goto cleanup;
855+
}
856+
close(fd);
857+
if (!full_write(STDOUT_FILENO, lt_key, arg.lt_key_size)) {
858+
goto cleanup;
859+
}
860+
status = EXIT_SUCCESS;
861+
cleanup:
862+
wipe_and_free(lt_key, MAX_WRAPPED_KEY_SIZE);
863+
return status;
864+
}
865+
866+
static int cmd_prepare_hw_wrapped_key(int argc, char *const argv[]) {
867+
handle_no_options(&argc, &argv);
868+
if (argc != 1) {
869+
fputs("error: must specify a single block device\n", stderr);
870+
return EXIT_FAILURE;
871+
}
872+
const char *blkdev = argv[0];
873+
int status = EXIT_FAILURE;
874+
875+
struct blk_crypto_prepare_key_arg arg = {0};
876+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
877+
uint8_t *eph_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
878+
arg.lt_key_ptr = (uintptr_t)lt_key;
879+
arg.lt_key_size = read_key(lt_key, MAX_WRAPPED_KEY_SIZE);
880+
if (arg.lt_key_size == 0) {
881+
goto cleanup;
882+
}
883+
arg.eph_key_ptr = (uintptr_t)eph_key;
884+
arg.eph_key_size = MAX_WRAPPED_KEY_SIZE;
885+
886+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
887+
if (fd < 0) {
888+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
889+
goto cleanup;
890+
}
891+
if (ioctl(fd, BLKCRYPTOPREPAREKEY, &arg) != 0) {
892+
fprintf(stderr, "error: preparing hardware-wrapped key: %s\n",
893+
strerror(errno));
894+
close(fd);
895+
goto cleanup;
896+
}
897+
close(fd);
898+
if (!full_write(STDOUT_FILENO, eph_key, arg.eph_key_size)) {
899+
goto cleanup;
900+
}
901+
status = EXIT_SUCCESS;
902+
cleanup:
903+
wipe_and_free(lt_key, MAX_WRAPPED_KEY_SIZE);
904+
wipe_and_free(eph_key, MAX_WRAPPED_KEY_SIZE);
905+
return status;
906+
}
907+
781908
// -----------------------------------------------------------------------------
782909
// The main() function
783910
// -----------------------------------------------------------------------------
@@ -786,9 +913,14 @@ static const struct {
786913
const char *name;
787914
int (*func)(int argc, char *const argv[]);
788915
} commands[] = {
789-
{"add_key", cmd_add_key}, {"remove_key", cmd_remove_key},
790-
{"key_status", cmd_key_status}, {"get_policy", cmd_get_policy},
916+
{"add_key", cmd_add_key},
917+
{"remove_key", cmd_remove_key},
918+
{"key_status", cmd_key_status},
919+
{"get_policy", cmd_get_policy},
791920
{"set_policy", cmd_set_policy},
921+
{"import_hw_wrapped_key", cmd_import_hw_wrapped_key},
922+
{"generate_hw_wrapped_key", cmd_generate_hw_wrapped_key},
923+
{"prepare_hw_wrapped_key", cmd_prepare_hw_wrapped_key},
792924
};
793925

794926
int main(int argc, char *const argv[]) {

0 commit comments

Comments
 (0)