@@ -756,51 +756,51 @@ _do_verify_ciphertext_for_encryption_policy()
# Now unmount the filesystem and verify the ciphertext we just wrote.
_scratch_unmount
echo "Verifying encrypted file contents" >> $seqres.full
for f in "${test_contents_files[@]}"; do
read -r src inode blocklist <<< "$f"
nonce=$(_get_encryption_nonce $SCRATCH_DEV $inode)
_dump_ciphertext_blocks $SCRATCH_DEV $blocklist > $tmp.actual_contents
$crypt_contents_cmd $contents_encryption_mode $raw_key_hex \
- --file-nonce=$nonce --block-size=$blocksize \
+ --file-nonce=$nonce --data-unit-size=$blocksize \
--inode-number=$inode < $src > $tmp.expected_contents
if ! cmp $tmp.expected_contents $tmp.actual_contents; then
_fail "Expected encrypted contents != actual encrypted contents. File: $f"
fi
$crypt_contents_cmd $contents_encryption_mode $raw_key_hex \
- --decrypt --file-nonce=$nonce --block-size=$blocksize \
- --inode-number=$inode \
+ --decrypt --file-nonce=$nonce \
+ --data-unit-size=$blocksize --inode-number=$inode \
< $tmp.actual_contents > $tmp.decrypted_contents
if ! cmp $src $tmp.decrypted_contents; then
_fail "Contents decryption sanity check failed. File: $f"
fi
done
echo "Verifying encrypted file names" >> $seqres.full
for f in "${test_filenames_files[@]}"; do
read -r name inode dir_inode padding <<< "$f"
nonce=$(_get_encryption_nonce $SCRATCH_DEV $dir_inode)
_get_ciphertext_filename $SCRATCH_DEV $inode $dir_inode \
> $tmp.actual_name
echo -n "$name" | \
$crypt_filename_cmd $filenames_encryption_mode \
$raw_key_hex --file-nonce=$nonce --padding=$padding \
- --block-size=255 --inode-number=$dir_inode \
+ --data-unit-size=255 --inode-number=$dir_inode \
> $tmp.expected_name
if ! cmp $tmp.expected_name $tmp.actual_name; then
_fail "Expected encrypted filename != actual encrypted filename. File: $f"
fi
$crypt_filename_cmd $filenames_encryption_mode $raw_key_hex \
--decrypt --file-nonce=$nonce --padding=$padding \
- --block-size=255 --inode-number=$dir_inode \
+ --data-unit-size=255 --inode-number=$dir_inode \
< $tmp.actual_name > $tmp.decrypted_name
decrypted_name=$(tr -d '\0' < $tmp.decrypted_name)
if [ "$name" != "$decrypted_name" ]; then
_fail "Filename decryption sanity check failed ($name != $decrypted_name). File: $f"
fi
done
}
# fscrypt UAPI constants (see <linux/fscrypt.h>)
@@ -54,23 +54,23 @@ static void usage(FILE *fp)
"MASTER_KEY (or a key derived from it, if a KDF is specified), and writes the\n"
"resulting ciphertext (or plaintext) to stdout.\n"
"\n"
"CIPHER can be AES-256-XTS, AES-256-CTS-CBC, AES-128-CBC-ESSIV, AES-128-CTS-CBC,\n"
"Adiantum, or AES-256-HCTR2. MASTER_KEY must be a hex string long enough for\n"
"the cipher.\n"
"\n"
"WARNING: this program is only meant for testing, not for \"real\" use!\n"
"\n"
"Options:\n"
-" --block-number=BNUM Starting block number for IV generation.\n"
+" --data-unit-index=DUIDX Starting data unit index for IV generation.\n"
" Default: 0\n"
-" --block-size=BLOCK_SIZE Encrypt each BLOCK_SIZE bytes independently.\n"
+" --data-unit-size=DUSIZE Encrypt each DUSIZE 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"
" --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"
" --iv-ino-lblk-64; otherwise is unused.\n"
@@ -79,22 +79,22 @@ static void usage(FILE *fp)
" --iv-ino-lblk-32 and --iv-ino-lblk-64;\n"
" otherwise is unused.\n"
" --iv-ino-lblk-32 Similar to --iv-ino-lblk-64, but selects the\n"
" 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"
" --kdf=KDF Key derivation function to use: AES-128-ECB,\n"
" HKDF-SHA512, or none. Default: none\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"
+" --padding=PADDING If last data unit is partial, zero-pad it to next\n"
+" PADDING-byte boundary. Default: DUSIZE\n"
, fp);
}
/*----------------------------------------------------------------------------*
* Utilities *
*----------------------------------------------------------------------------*/
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
@@ -1968,73 +1968,74 @@ static const struct fscrypt_cipher *find_fscrypt_cipher(const char *name)
for (i = 0; i < ARRAY_SIZE(fscrypt_ciphers); i++) {
if (strcmp(fscrypt_ciphers[i].name, name) == 0)
return &fscrypt_ciphers[i];
}
return NULL;
}
union fscrypt_iv {
/* usual IV format */
struct {
- /* logical block number within the file */
- __le64 block_number;
+ /* data unit index within the file */
+ __le64 data_unit_index;
/* per-file nonce; only set in DIRECT_KEY mode */
u8 nonce[FILE_NONCE_SIZE];
};
/* IV format for IV_INO_LBLK_* modes */
struct {
/*
- * IV_INO_LBLK_64: logical block number within the file
- * IV_INO_LBLK_32: hashed inode number + logical block number
- * within the file, mod 2^32
+ * IV_INO_LBLK_64: data unit index within the file
+ * IV_INO_LBLK_32: hashed inode number + data unit index within
+ * the file, mod 2^32
*/
- __le32 block_number32;
+ __le32 data_unit_index32;
/* IV_INO_LBLK_64: inode number */
__le32 inode_number;
};
/* Any extra bytes up to the algorithm's IV size must be zeroed */
u8 bytes[MAX_IV_SIZE];
};
static void crypt_loop(const struct fscrypt_cipher *cipher, const u8 *key,
union fscrypt_iv *iv, bool decrypting,
- size_t block_size, size_t padding, bool is_bnum_32bit)
+ size_t data_unit_size, size_t padding,
+ bool is_data_unit_index_32bit)
{
- u8 *buf = xmalloc(block_size);
+ u8 *buf = xmalloc(data_unit_size);
size_t res;
- while ((res = xread(STDIN_FILENO, buf, block_size)) > 0) {
- size_t crypt_len = block_size;
+ while ((res = xread(STDIN_FILENO, buf, data_unit_size)) > 0) {
+ size_t crypt_len = data_unit_size;
if (padding > 0) {
crypt_len = MAX(res, cipher->min_input_size);
crypt_len = ROUND_UP(crypt_len, padding);
- crypt_len = MIN(crypt_len, block_size);
+ crypt_len = MIN(crypt_len, data_unit_size);
}
ASSERT(crypt_len >= res);
memset(&buf[res], 0, crypt_len - res);
if (decrypting)
cipher->decrypt(key, iv->bytes, buf, buf, crypt_len);
else
cipher->encrypt(key, iv->bytes, buf, buf, crypt_len);
full_write(STDOUT_FILENO, buf, crypt_len);
- if (is_bnum_32bit)
- iv->block_number32 = cpu_to_le32(
- le32_to_cpu(iv->block_number32) + 1);
+ if (is_data_unit_index_32bit)
+ iv->data_unit_index32 = cpu_to_le32(
+ le32_to_cpu(iv->data_unit_index32) + 1);
else
- iv->block_number = cpu_to_le64(
- le64_to_cpu(iv->block_number) + 1);
+ iv->data_unit_index = cpu_to_le64(
+ le64_to_cpu(iv->data_unit_index) + 1);
}
free(buf);
}
/* The supported key derivation functions */
enum kdf_algorithm {
KDF_NONE,
KDF_AES_128_ECB,
KDF_HKDF_SHA512,
};
@@ -2063,21 +2064,21 @@ static u8 parse_mode_number(const char *arg)
struct key_and_iv_params {
u8 master_key[MAX_KEY_SIZE];
int master_key_size;
enum kdf_algorithm kdf;
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;
+ u64 data_unit_index;
u64 inode_number;
u8 fs_uuid[UUID_SIZE];
bool fs_uuid_specified;
};
#define HKDF_CONTEXT_KEY_IDENTIFIER 1
#define HKDF_CONTEXT_PER_FILE_ENC_KEY 2
#define HKDF_CONTEXT_DIRECT_KEY 3
#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4
#define HKDF_CONTEXT_DIRHASH_KEY 5
@@ -2171,40 +2172,40 @@ static void derive_real_key(const struct key_and_iv_params *params,
}
}
static void generate_iv(const struct key_and_iv_params *params,
union fscrypt_iv *iv)
{
memset(iv, 0, sizeof(*iv));
if (params->direct_key) {
if (!params->file_nonce_specified)
die("--direct-key requires --file-nonce");
- iv->block_number = cpu_to_le64(params->block_number);
+ iv->data_unit_index = cpu_to_le64(params->data_unit_index);
memcpy(iv->nonce, params->file_nonce, FILE_NONCE_SIZE);
} else if (params->iv_ino_lblk_64) {
- if (params->block_number > UINT32_MAX)
- die("iv-ino-lblk-64 can't use --block-number > UINT32_MAX");
+ if (params->data_unit_index > UINT32_MAX)
+ die("iv-ino-lblk-64 can't use --data-unit-index > UINT32_MAX");
if (params->inode_number == 0)
die("iv-ino-lblk-64 requires --inode-number");
if (params->inode_number > UINT32_MAX)
die("iv-ino-lblk-64 can't use --inode-number > UINT32_MAX");
- iv->block_number32 = cpu_to_le32(params->block_number);
+ iv->data_unit_index32 = cpu_to_le32(params->data_unit_index);
iv->inode_number = cpu_to_le32(params->inode_number);
} else if (params->iv_ino_lblk_32) {
- if (params->block_number > UINT32_MAX)
- die("iv-ino-lblk-32 can't use --block-number > UINT32_MAX");
+ if (params->data_unit_index > UINT32_MAX)
+ die("iv-ino-lblk-32 can't use --data-unit-index > UINT32_MAX");
if (params->inode_number == 0)
die("iv-ino-lblk-32 requires --inode-number");
- iv->block_number32 = cpu_to_le32(hash_inode_number(params) +
- params->block_number);
+ iv->data_unit_index32 = cpu_to_le32(hash_inode_number(params) +
+ params->data_unit_index);
} else {
- iv->block_number = cpu_to_le64(params->block_number);
+ iv->data_unit_index = cpu_to_le64(params->data_unit_index);
}
}
/*
* Get the key and starting IV with which the encryption will actually be done.
* If a KDF was specified, then a subkey is derived from the master key.
* Otherwise, the master key is used directly.
*/
static void get_key_and_iv(const struct key_and_iv_params *params,
u8 *real_key, size_t real_key_size,
@@ -2245,57 +2246,57 @@ static void do_dump_key_identifier(const struct key_and_iv_params *params)
static void parse_master_key(const char *arg, struct key_and_iv_params *params)
{
params->master_key_size = hex2bin(arg, params->master_key,
MAX_KEY_SIZE);
if (params->master_key_size < 0)
die("Invalid master_key: %s", arg);
}
enum {
- OPT_BLOCK_NUMBER,
- OPT_BLOCK_SIZE,
+ OPT_DATA_UNIT_INDEX,
+ OPT_DATA_UNIT_SIZE,
OPT_DECRYPT,
OPT_DIRECT_KEY,
OPT_DUMP_KEY_IDENTIFIER,
OPT_FILE_NONCE,
OPT_FS_UUID,
OPT_HELP,
OPT_INODE_NUMBER,
OPT_IV_INO_LBLK_32,
OPT_IV_INO_LBLK_64,
OPT_KDF,
OPT_MODE_NUM,
OPT_PADDING,
};
static const struct option longopts[] = {
- { "block-number", required_argument, NULL, OPT_BLOCK_NUMBER },
- { "block-size", required_argument, NULL, OPT_BLOCK_SIZE },
+ { "data-unit-index", required_argument, NULL, OPT_DATA_UNIT_INDEX },
+ { "data-unit-size", required_argument, NULL, OPT_DATA_UNIT_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 },
{ "inode-number", required_argument, NULL, OPT_INODE_NUMBER },
{ "iv-ino-lblk-32", no_argument, NULL, OPT_IV_INO_LBLK_32 },
{ "iv-ino-lblk-64", no_argument, NULL, OPT_IV_INO_LBLK_64 },
{ "kdf", required_argument, NULL, OPT_KDF },
{ "mode-num", required_argument, NULL, OPT_MODE_NUM },
{ "padding", required_argument, NULL, OPT_PADDING },
{ NULL, 0, NULL, 0 },
};
int main(int argc, char *argv[])
{
- size_t block_size = 4096;
+ size_t data_unit_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;
u8 real_key[MAX_KEY_SIZE];
union fscrypt_iv iv;
char *tmp;
int c;
@@ -2308,31 +2309,31 @@ int main(int argc, char *argv[])
test_sha2();
test_hkdf_sha512();
test_aes_256_xts();
test_aes_256_cts_cbc();
test_adiantum();
test_aes_256_hctr2();
#endif
while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
switch (c) {
- case OPT_BLOCK_NUMBER:
+ case OPT_DATA_UNIT_INDEX:
errno = 0;
- params.block_number = strtoull(optarg, &tmp, 10);
+ params.data_unit_index = strtoull(optarg, &tmp, 10);
if (*tmp || errno)
- die("Invalid block number: %s", optarg);
+ die("Invalid data unit index: %s", optarg);
break;
- case OPT_BLOCK_SIZE:
+ case OPT_DATA_UNIT_SIZE:
errno = 0;
- block_size = strtoul(optarg, &tmp, 10);
- if (block_size <= 0 || *tmp || errno)
- die("Invalid block size: %s", optarg);
+ data_unit_size = strtoul(optarg, &tmp, 10);
+ if (data_unit_size <= 0 || *tmp || errno)
+ die("Invalid data unit size: %s", optarg);
break;
case OPT_DECRYPT:
decrypting = true;
break;
case OPT_DIRECT_KEY:
params.direct_key = true;
break;
case OPT_DUMP_KEY_IDENTIFIER:
dump_key_identifier = true;
break;
@@ -2394,25 +2395,25 @@ int main(int argc, char *argv[])
}
if (argc != 2) {
usage(stderr);
return 2;
}
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);
+ if (data_unit_size < cipher->min_input_size)
+ die("Data unit size of %zu bytes is too small for cipher %s",
+ data_unit_size, cipher->name);
parse_master_key(argv[1], ¶ms);
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,
+ crypt_loop(cipher, real_key, &iv, decrypting, data_unit_size, padding,
params.iv_ino_lblk_64 || params.iv_ino_lblk_32);
return 0;
}
@@ -133,30 +133,30 @@ nonce=$(_get_encryption_nonce $SCRATCH_DEV $inode)
echo -e "\n# Dumping the file's raw data"
_dump_ciphertext_blocks $SCRATCH_DEV $blocklist > $tmp.raw
echo -e "\n# Decrypting the file's data"
TEST_RAW_KEY_HEX=$(echo "$TEST_RAW_KEY" | tr -d '\\x')
decrypt_blocks()
{
$here/src/fscrypt-crypt-util "$@" \
--decrypt \
- --block-size=$block_size \
+ --data-unit-size=$block_size \
--file-nonce=$nonce \
--kdf=HKDF-SHA512 \
AES-256-XTS \
$TEST_RAW_KEY_HEX
}
head -c $num_compressible_bytes $tmp.raw \
- | decrypt_blocks --block-number=1 > $tmp.decrypted
+ | decrypt_blocks --data-unit-index=1 > $tmp.decrypted
dd if=$tmp.raw bs=$cluster_bytes skip=$num_compressible_clusters status=none \
- | decrypt_blocks --block-number=$num_compressible_blocks \
+ | decrypt_blocks --data-unit-index=$num_compressible_blocks \
>> $tmp.decrypted
# Decompress the compressed clusters using the lz4 command-line tool.
#
# Each f2fs compressed cluster begins with a 24-byte header, starting with the
# compressed size in bytes (excluding the header) as a __le32. The header is
# followed by the actual compressed data; for LZ4, that means an LZ4 block.
#
# Unfortunately, the lz4 command-line tool only deals with LZ4 *frames*
# (https://github.com/lz4/lz4/blob/master/doc/lz4_Frame_format.md) and can't