Skip to content

Commit c9deb6c

Browse files
committed
Add support for creating and preparing hardware-wrapped keys
1 parent 217ca22 commit c9deb6c

File tree

2 files changed

+203
-3
lines changed

2 files changed

+203
-3
lines changed

fscryptctl.1.md

Lines changed: 39 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

@@ -148,6 +151,41 @@ Options accepted by **fscryptctl set_policy**:
148151
: Select the crypto data unit size, i.e. the granularity of file contents
149152
encryption, in bytes.
150153

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

153191
* [**fscryptctl** README

fscryptctl.c

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,37 @@
4141
#define VERSION "v1.2.0"
4242
#endif
4343

44+
#ifndef BLKCRYPTOIMPORTKEY
45+
46+
struct blk_crypto_import_key_arg {
47+
__u64 raw_key_ptr;
48+
__u64 raw_key_size;
49+
__u64 lt_key_ptr;
50+
__u64 lt_key_size;
51+
__u64 reserved[4];
52+
};
53+
54+
struct blk_crypto_generate_key_arg {
55+
__u64 lt_key_ptr;
56+
__u64 lt_key_size;
57+
__u64 reserved[4];
58+
};
59+
60+
struct blk_crypto_prepare_key_arg {
61+
__u64 lt_key_ptr;
62+
__u64 lt_key_size;
63+
__u64 eph_key_ptr;
64+
__u64 eph_key_size;
65+
__u64 reserved[4];
66+
};
67+
68+
#define BLKCRYPTOIMPORTKEY _IOWR(0x12, 137, struct blk_crypto_import_key_arg)
69+
#define BLKCRYPTOGENERATEKEY \
70+
_IOWR(0x12, 138, struct blk_crypto_generate_key_arg)
71+
#define BLKCRYPTOPREPAREKEY _IOWR(0x12, 139, struct blk_crypto_prepare_key_arg)
72+
73+
#endif /* BLKCRYPTOIMPORTKEY */
74+
4475
#define MAX_WRAPPED_KEY_SIZE 128
4576

4677
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
@@ -133,6 +164,13 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
133164
" fscryptctl set_policy <key identifier> <directory>\n"
134165
" Set up an encryption policy on the specified directory with the\n"
135166
" specified key identifier.\n"
167+
" fscryptctl import_hw_wrapped_key <block device>\n"
168+
" Create a hardware-wrapped key by importing a raw key.\n"
169+
" fscryptctl generate_hw_wrapped_key <block device>\n"
170+
" Create a hardware-wrapped key by generating one in hardware.\n"
171+
" fscryptctl prepare_hw_wrapped_key <block device>\n"
172+
" Prepare a hardware-wrapped key to be used by converting it from\n"
173+
" long-term wrapped form to ephemerally-wrapped form.\n"
136174
"\nOptions:\n"
137175
" -h, --help\n"
138176
" print this help screen\n"
@@ -778,6 +816,125 @@ static int cmd_set_policy(int argc, char *const argv[]) {
778816
return EXIT_SUCCESS;
779817
}
780818

819+
static int cmd_import_hw_wrapped_key(int argc, char *const argv[]) {
820+
handle_no_options(&argc, &argv);
821+
if (argc != 1) {
822+
fputs("error: must specify a block device\n", stderr);
823+
return EXIT_FAILURE;
824+
}
825+
const char *blkdev = argv[0];
826+
int status = EXIT_FAILURE;
827+
828+
struct blk_crypto_import_key_arg arg = {0};
829+
uint8_t *raw_key = xzalloc(FSCRYPT_MAX_KEY_SIZE);
830+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
831+
arg.raw_key_ptr = (uintptr_t)raw_key;
832+
arg.raw_key_size = read_key(raw_key, FSCRYPT_MAX_KEY_SIZE);
833+
if (arg.raw_key_size == 0) {
834+
goto cleanup;
835+
}
836+
arg.lt_key_ptr = (uintptr_t)lt_key;
837+
arg.lt_key_size = MAX_WRAPPED_KEY_SIZE;
838+
839+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
840+
if (fd < 0) {
841+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
842+
goto cleanup;
843+
}
844+
if (ioctl(fd, BLKCRYPTOIMPORTKEY, &arg) != 0) {
845+
fprintf(stderr, "error: importing hardware-wrapped key: %s\n",
846+
strerror(errno));
847+
close(fd);
848+
goto cleanup;
849+
}
850+
close(fd);
851+
if (!full_write(STDOUT_FILENO, lt_key, arg.lt_key_size)) {
852+
goto cleanup;
853+
}
854+
status = EXIT_SUCCESS;
855+
cleanup:
856+
wipe_and_free(raw_key, FSCRYPT_MAX_KEY_SIZE);
857+
wipe_and_free(lt_key, MAX_WRAPPED_KEY_SIZE);
858+
return status;
859+
}
860+
861+
static int cmd_generate_hw_wrapped_key(int argc, char *const argv[]) {
862+
handle_no_options(&argc, &argv);
863+
if (argc != 1) {
864+
fputs("error: must specify a block device\n", stderr);
865+
return EXIT_FAILURE;
866+
}
867+
const char *blkdev = argv[0];
868+
int status = EXIT_FAILURE;
869+
870+
struct blk_crypto_generate_key_arg arg = {0};
871+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
872+
arg.lt_key_ptr = (uintptr_t)lt_key;
873+
arg.lt_key_size = MAX_WRAPPED_KEY_SIZE;
874+
875+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
876+
if (fd < 0) {
877+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
878+
goto cleanup;
879+
}
880+
if (ioctl(fd, BLKCRYPTOGENERATEKEY, &arg) != 0) {
881+
fprintf(stderr, "error: generating hardware-wrapped key: %s\n",
882+
strerror(errno));
883+
close(fd);
884+
goto cleanup;
885+
}
886+
close(fd);
887+
if (!full_write(STDOUT_FILENO, lt_key, arg.lt_key_size)) {
888+
goto cleanup;
889+
}
890+
status = EXIT_SUCCESS;
891+
cleanup:
892+
wipe_and_free(lt_key, MAX_WRAPPED_KEY_SIZE);
893+
return status;
894+
}
895+
896+
static int cmd_prepare_hw_wrapped_key(int argc, char *const argv[]) {
897+
handle_no_options(&argc, &argv);
898+
if (argc != 1) {
899+
fputs("error: must specify a block device\n", stderr);
900+
return EXIT_FAILURE;
901+
}
902+
const char *blkdev = argv[0];
903+
int status = EXIT_FAILURE;
904+
905+
struct blk_crypto_prepare_key_arg arg = {0};
906+
uint8_t *lt_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
907+
uint8_t *eph_key = xzalloc(MAX_WRAPPED_KEY_SIZE);
908+
arg.lt_key_ptr = (uintptr_t)lt_key;
909+
arg.lt_key_size = read_key(lt_key, MAX_WRAPPED_KEY_SIZE);
910+
if (arg.lt_key_size == 0) {
911+
goto cleanup;
912+
}
913+
arg.eph_key_ptr = (uintptr_t)eph_key;
914+
arg.eph_key_size = MAX_WRAPPED_KEY_SIZE;
915+
916+
int fd = open(blkdev, O_RDONLY | O_CLOEXEC);
917+
if (fd < 0) {
918+
fprintf(stderr, "error: opening %s: %s\n", blkdev, strerror(errno));
919+
goto cleanup;
920+
}
921+
if (ioctl(fd, BLKCRYPTOPREPAREKEY, &arg) != 0) {
922+
fprintf(stderr, "error: preparing hardware-wrapped key: %s\n",
923+
strerror(errno));
924+
close(fd);
925+
goto cleanup;
926+
}
927+
close(fd);
928+
if (!full_write(STDOUT_FILENO, eph_key, arg.eph_key_size)) {
929+
goto cleanup;
930+
}
931+
status = EXIT_SUCCESS;
932+
cleanup:
933+
wipe_and_free(lt_key, FSCRYPT_MAX_KEY_SIZE);
934+
wipe_and_free(eph_key, MAX_WRAPPED_KEY_SIZE);
935+
return status;
936+
}
937+
781938
// -----------------------------------------------------------------------------
782939
// The main() function
783940
// -----------------------------------------------------------------------------
@@ -786,9 +943,14 @@ static const struct {
786943
const char *name;
787944
int (*func)(int argc, char *const argv[]);
788945
} commands[] = {
789-
{"add_key", cmd_add_key}, {"remove_key", cmd_remove_key},
790-
{"key_status", cmd_key_status}, {"get_policy", cmd_get_policy},
946+
{"add_key", cmd_add_key},
947+
{"remove_key", cmd_remove_key},
948+
{"key_status", cmd_key_status},
949+
{"get_policy", cmd_get_policy},
791950
{"set_policy", cmd_set_policy},
951+
{"import_hw_wrapped_key", cmd_import_hw_wrapped_key},
952+
{"generate_hw_wrapped_key", cmd_generate_hw_wrapped_key},
953+
{"prepare_hw_wrapped_key", cmd_prepare_hw_wrapped_key},
792954
};
793955

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

0 commit comments

Comments
 (0)