summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2022-03-12 17:05:55 -0800
committerEryu Guan <guaneryu@gmail.com>2022-04-10 20:40:39 +0800
commitcd81e731261d0d062ad8ed8216deb51b110e4fd7 (patch)
tree6239610391a125762ec4bc5a343ca45fcfbbfa59 /src
parent407ef6b96cc84758cc9791fd87703f2414907861 (diff)
fscrypt-crypt-util: use an explicit --direct-key option
Make fscrypt-crypt-util use an option --direct-key to specify the use of the DIRECT_KEY method for key derivation and IV generation. Previously, this method was implicitly detected via --mode-num being given without either --iv-ino-lblk-64 or --iv-ino-lblk-32, or --kdf=none being given in combination with --file-nonce. The benefit of this change is that it makes the various options to fscrypt-crypt-util behave more consistently. --direct-key, --iv-ino-lblk-64, and --iv-ino-lblk-32 now all work similarly (they select a key derivation and IV generation method); likewise, --mode-num, --file-nonce, --inode-number, and --fs-uuid now all work similarly (they provide information that key derivation and IV generation may need). Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/fscrypt-crypt-util.c52
1 files changed, 32 insertions, 20 deletions
diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c
index 03cc3c4a..e5992275 100644
--- a/src/fscrypt-crypt-util.c
+++ b/src/fscrypt-crypt-util.c
@@ -64,6 +64,8 @@ static void usage(FILE *fp)
" --block-size=BLOCK_SIZE Encrypt each BLOCK_SIZE bytes independently.\n"
" Default: 4096 bytes\n"
" --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"
" --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"
@@ -76,11 +78,10 @@ static void usage(FILE *fp)
" 32-bit variant.\n"
" --iv-ino-lblk-64 Use the format where the IVs include the inode\n"
" number and the same key is shared across files.\n"
-" Requires --kdf=HKDF-SHA512, --fs-uuid,\n"
-" --inode-number, and --mode-num.\n"
" --kdf=KDF Key derivation function to use: AES-128-ECB,\n"
" HKDF-SHA512, or none. Default: none\n"
-" --mode-num=NUM Derive per-mode key using mode number NUM\n"
+" --mode-num=NUM The encryption mode number. This may be required\n"
+" for key derivation, depending on other options.\n"
" --padding=PADDING If last block is partial, zero-pad it to next\n"
" PADDING-byte boundary. Default: BLOCK_SIZE\n"
, fp);
@@ -1790,6 +1791,7 @@ struct key_and_iv_params {
u8 mode_num;
u8 file_nonce[FILE_NONCE_SIZE];
bool file_nonce_specified;
+ bool direct_key;
bool iv_ino_lblk_64;
bool iv_ino_lblk_32;
u64 block_number;
@@ -1835,7 +1837,7 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
u8 *real_key, size_t real_key_size,
union fscrypt_iv *iv)
{
- bool file_nonce_in_iv = false;
+ int iv_methods = 0;
struct aes_key aes_key;
u8 info[8 + 1 + 1 + UUID_SIZE] = "fscrypt";
size_t infolen = 8;
@@ -1848,11 +1850,22 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
/* Overridden later for iv_ino_lblk_{64,32} */
iv->block_number = cpu_to_le64(params->block_number);
- if (params->iv_ino_lblk_64 || params->iv_ino_lblk_32) {
+ iv_methods += params->direct_key;
+ iv_methods += params->iv_ino_lblk_64;
+ iv_methods += params->iv_ino_lblk_32;
+ if (iv_methods > 1)
+ die("Conflicting IV methods specified");
+ if (iv_methods > 0 && params->kdf == KDF_AES_128_ECB)
+ die("--kdf=AES-128-ECB is incompatible with IV method options");
+
+ if (params->direct_key) {
+ if (!params->file_nonce_specified)
+ die("--direct-key requires --file-nonce");
+ if (params->kdf != KDF_NONE && params->mode_num == 0)
+ die("--direct-key with KDF requires --mode-num");
+ } else if (params->iv_ino_lblk_64 || params->iv_ino_lblk_32) {
const char *opt = params->iv_ino_lblk_64 ? "--iv-ino-lblk-64" :
"--iv-ino-lblk-32";
- if (params->iv_ino_lblk_64 && params->iv_ino_lblk_32)
- die("--iv-ino-lblk-64 and --iv-ino-lblk-32 are mutually exclusive");
if (params->kdf != KDF_HKDF_SHA512)
die("%s requires --kdf=HKDF-SHA512", opt);
if (!params->fs_uuid_specified)
@@ -1869,16 +1882,11 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
switch (params->kdf) {
case KDF_NONE:
- if (params->mode_num != 0)
- die("--mode-num isn't supported with --kdf=none");
memcpy(real_key, params->master_key, real_key_size);
- file_nonce_in_iv = true;
break;
case KDF_AES_128_ECB:
if (!params->file_nonce_specified)
- die("--file-nonce is required with --kdf=AES-128-ECB");
- if (params->mode_num != 0)
- die("--mode-num isn't supported with --kdf=AES-128-ECB");
+ die("--kdf=AES-128-ECB requires --file-nonce");
STATIC_ASSERT(FILE_NONCE_SIZE == AES_128_KEY_SIZE);
ASSERT(real_key_size % AES_BLOCK_SIZE == 0);
aes_setkey(&aes_key, params->file_nonce, AES_128_KEY_SIZE);
@@ -1887,7 +1895,10 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
&real_key[i]);
break;
case KDF_HKDF_SHA512:
- if (params->iv_ino_lblk_64) {
+ if (params->direct_key) {
+ info[infolen++] = HKDF_CONTEXT_DIRECT_KEY;
+ info[infolen++] = params->mode_num;
+ } else if (params->iv_ino_lblk_64) {
info[infolen++] = HKDF_CONTEXT_IV_INO_LBLK_64_KEY;
info[infolen++] = params->mode_num;
memcpy(&info[infolen], params->fs_uuid, UUID_SIZE);
@@ -1903,17 +1914,13 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
cpu_to_le32(hash_inode_number(params) +
params->block_number);
iv->inode_number = 0;
- } else if (params->mode_num != 0) {
- info[infolen++] = HKDF_CONTEXT_DIRECT_KEY;
- info[infolen++] = params->mode_num;
- file_nonce_in_iv = true;
} else if (params->file_nonce_specified) {
info[infolen++] = HKDF_CONTEXT_PER_FILE_ENC_KEY;
memcpy(&info[infolen], params->file_nonce,
FILE_NONCE_SIZE);
infolen += FILE_NONCE_SIZE;
} else {
- die("With --kdf=HKDF-SHA512, at least one of --file-nonce and --mode-num must be specified");
+ die("--kdf=HKDF-SHA512 requires --file-nonce or --iv-ino-lblk-{64,32}");
}
hkdf_sha512(params->master_key, params->master_key_size,
NULL, 0, info, infolen, real_key, real_key_size);
@@ -1922,7 +1929,7 @@ static void get_key_and_iv(const struct key_and_iv_params *params,
ASSERT(0);
}
- if (file_nonce_in_iv && params->file_nonce_specified)
+ if (params->direct_key)
memcpy(iv->nonce, params->file_nonce, FILE_NONCE_SIZE);
}
@@ -1930,6 +1937,7 @@ enum {
OPT_BLOCK_NUMBER,
OPT_BLOCK_SIZE,
OPT_DECRYPT,
+ OPT_DIRECT_KEY,
OPT_FILE_NONCE,
OPT_FS_UUID,
OPT_HELP,
@@ -1945,6 +1953,7 @@ static const struct option longopts[] = {
{ "block-number", required_argument, NULL, OPT_BLOCK_NUMBER },
{ "block-size", required_argument, NULL, OPT_BLOCK_SIZE },
{ "decrypt", no_argument, NULL, OPT_DECRYPT },
+ { "direct-key", no_argument, NULL, OPT_DIRECT_KEY },
{ "file-nonce", required_argument, NULL, OPT_FILE_NONCE },
{ "fs-uuid", required_argument, NULL, OPT_FS_UUID },
{ "help", no_argument, NULL, OPT_HELP },
@@ -1999,6 +2008,9 @@ int main(int argc, char *argv[])
case OPT_DECRYPT:
decrypting = true;
break;
+ case OPT_DIRECT_KEY:
+ params.direct_key = true;
+ break;
case OPT_FILE_NONCE:
if (hex2bin(optarg, params.file_nonce, FILE_NONCE_SIZE)
!= FILE_NONCE_SIZE)