@@ -46,7 +46,7 @@
static void usage(FILE *fp)
{
fputs(
-"Usage: " PROGRAM_NAME " [OPTION]... CIPHER MASTER_KEY\n"
+"Usage: " PROGRAM_NAME " [OPTION]... [CIPHER | --dump-key-identifier] MASTER_KEY\n"
"\n"
"Utility for verifying fscrypt-encrypted data. This program encrypts\n"
"(or decrypts) the data on stdin using the given CIPHER with the given\n"
@@ -66,6 +66,8 @@ static void usage(FILE *fp)
" --decrypt Decrypt instead of encrypt\n"
" --direct-key Use the format where the IVs include the file\n"
" nonce and the same key is shared across files.\n"
+" --dump-key-identifier Instead of encrypting/decrypting data, just\n"
+" compute and dump the key identifier.\n"
" --file-nonce=NONCE File's nonce as a 32-character hex string\n"
" --fs-uuid=UUID The filesystem UUID as a 32-character hex string.\n"
" Required for --iv-ino-lblk-32 and\n"
@@ -1946,11 +1948,31 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
generate_iv(params, iv);
}
+static void do_dump_key_identifier(const struct key_and_iv_params *params)
+{
+ u8 info[9] = "fscrypt";
+ u8 key_identifier[16];
+ int i;
+
+ if (params->kdf != KDF_HKDF_SHA512)
+ die("--dump-key-identifier requires --kdf=HKDF-SHA512");
+
+ info[8] = HKDF_CONTEXT_KEY_IDENTIFIER;
+
+ hkdf_sha512(params->master_key, params->master_key_size,
+ NULL, 0, info, sizeof(info), key_identifier,
+ sizeof(key_identifier));
+
+ for (i = 0; i < sizeof(key_identifier); i++)
+ printf("%02x", key_identifier[i]);
+}
+
enum {
OPT_BLOCK_NUMBER,
OPT_BLOCK_SIZE,
OPT_DECRYPT,
OPT_DIRECT_KEY,
+ OPT_DUMP_KEY_IDENTIFIER,
OPT_FILE_NONCE,
OPT_FS_UUID,
OPT_HELP,
@@ -1967,6 +1989,7 @@ static const struct option longopts[] = {
{ "block-size", required_argument, NULL, OPT_BLOCK_SIZE },
{ "decrypt", no_argument, NULL, OPT_DECRYPT },
{ "direct-key", no_argument, NULL, OPT_DIRECT_KEY },
+ { "dump-key-identifier", no_argument, NULL, OPT_DUMP_KEY_IDENTIFIER },
{ "file-nonce", required_argument, NULL, OPT_FILE_NONCE },
{ "fs-uuid", required_argument, NULL, OPT_FS_UUID },
{ "help", no_argument, NULL, OPT_HELP },
@@ -1983,9 +2006,10 @@ int main(int argc, char *argv[])
{
size_t block_size = 4096;
bool decrypting = false;
+ bool dump_key_identifier = false;
struct key_and_iv_params params;
size_t padding = 0;
- const struct fscrypt_cipher *cipher;
+ const struct fscrypt_cipher *cipher = NULL;
u8 real_key[MAX_KEY_SIZE];
union fscrypt_iv iv;
char *tmp;
@@ -2024,6 +2048,9 @@ int main(int argc, char *argv[])
case OPT_DIRECT_KEY:
params.direct_key = true;
break;
+ case OPT_DUMP_KEY_IDENTIFIER:
+ dump_key_identifier = true;
+ break;
case OPT_FILE_NONCE:
if (hex2bin(optarg, params.file_nonce, FILE_NONCE_SIZE)
!= FILE_NONCE_SIZE)
@@ -2071,29 +2098,40 @@ int main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (argc != 2) {
- usage(stderr);
- return 2;
+ if (dump_key_identifier) {
+ if (argc != 1) {
+ usage(stderr);
+ return 2;
+ }
+ } else {
+ if (argc != 2) {
+ usage(stderr);
+ return 2;
+ }
+ cipher = find_fscrypt_cipher(*argv);
+ if (cipher == NULL)
+ die("Unknown cipher: %s", *argv);
+
+ if (block_size < cipher->min_input_size)
+ die("Block size of %zu bytes is too small for cipher %s",
+ block_size, cipher->name);
+ argv++;
}
-
- cipher = find_fscrypt_cipher(argv[0]);
- if (cipher == NULL)
- die("Unknown cipher: %s", argv[0]);
-
- if (block_size < cipher->min_input_size)
- die("Block size of %zu bytes is too small for cipher %s",
- block_size, cipher->name);
-
- params.master_key_size = hex2bin(argv[1], params.master_key,
+ params.master_key_size = hex2bin(*argv, params.master_key,
MAX_KEY_SIZE);
if (params.master_key_size < 0)
- die("Invalid master_key: %s", argv[1]);
- if (params.master_key_size < cipher->keysize)
- die("Master key is too short for cipher %s", cipher->name);
+ die("Invalid master_key: %s", *argv);
- get_key_and_iv(¶ms, real_key, cipher->keysize, &iv);
-
- crypt_loop(cipher, real_key, &iv, decrypting, block_size, padding,
- params.iv_ino_lblk_64 || params.iv_ino_lblk_32);
+ if (dump_key_identifier) {
+ do_dump_key_identifier(¶ms);
+ } else {
+ if (params.master_key_size < cipher->keysize)
+ die("Master key is too short for cipher %s",
+ cipher->name);
+ get_key_and_iv(¶ms, real_key, cipher->keysize, &iv);
+ crypt_loop(cipher, real_key, &iv, decrypting, block_size,
+ padding,
+ params.iv_ino_lblk_64 || params.iv_ino_lblk_32);
+ }
return 0;
}