X-Git-Url: http://git.apps.os.sepia.ceph.com/?p=xfstests-dev.git;a=blobdiff_plain;f=src%2Ffscrypt-crypt-util.c;h=03cc3c4a12997734195a455c1bfd2ba249525c5c;hp=d9189346cbbce3594e93a493ddb3dd518513b5a6;hb=609bb3562241f9fc877aff7309d62af6cb10795d;hpb=fa650493ef9f8f9aa4cdae0cc5c27f470293f2c0;ds=sidebyside diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c index d9189346..03cc3c4a 100644 --- a/src/fscrypt-crypt-util.c +++ b/src/fscrypt-crypt-util.c @@ -59,6 +59,8 @@ static void usage(FILE *fp) "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" +" Default: 0\n" " --block-size=BLOCK_SIZE Encrypt each BLOCK_SIZE bytes independently.\n" " Default: 4096 bytes\n" " --decrypt Decrypt instead of encrypt\n" @@ -1640,6 +1642,7 @@ static u64 siphash_1u64(const u64 key[2], u64 data) #define FILE_NONCE_SIZE 16 #define UUID_SIZE 16 #define MAX_KEY_SIZE 64 +#define MAX_IV_SIZE ADIANTUM_IV_SIZE static const struct fscrypt_cipher { const char *name; @@ -1692,16 +1695,34 @@ static const struct fscrypt_cipher *find_fscrypt_cipher(const char *name) return NULL; } -struct fscrypt_iv { - union { - __le64 block_num; - u8 bytes[32]; +union fscrypt_iv { + /* usual IV format */ + struct { + /* logical block number within the file */ + __le64 block_number; + + /* 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 + */ + __le32 block_number32; + + /* 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, - struct fscrypt_iv *iv, bool decrypting, - size_t block_size, size_t padding) + union fscrypt_iv *iv, bool decrypting, + size_t block_size, size_t padding, bool is_bnum_32bit) { u8 *buf = xmalloc(block_size); size_t res; @@ -1724,7 +1745,12 @@ static void crypt_loop(const struct fscrypt_cipher *cipher, const u8 *key, full_write(STDOUT_FILENO, buf, crypt_len); - iv->block_num = cpu_to_le64(le64_to_cpu(iv->block_num) + 1); + if (is_bnum_32bit) + iv->block_number32 = cpu_to_le32( + le32_to_cpu(iv->block_number32) + 1); + else + iv->block_number = cpu_to_le64( + le64_to_cpu(iv->block_number) + 1); } free(buf); } @@ -1766,6 +1792,7 @@ struct key_and_iv_params { bool file_nonce_specified; bool iv_ino_lblk_64; bool iv_ino_lblk_32; + u64 block_number; u64 inode_number; u8 fs_uuid[UUID_SIZE]; bool fs_uuid_specified; @@ -1806,7 +1833,7 @@ static u32 hash_inode_number(const struct key_and_iv_params *params) */ static void get_key_and_iv(const struct key_and_iv_params *params, u8 *real_key, size_t real_key_size, - struct fscrypt_iv *iv) + union fscrypt_iv *iv) { bool file_nonce_in_iv = false; struct aes_key aes_key; @@ -1818,6 +1845,9 @@ static void get_key_and_iv(const struct key_and_iv_params *params, memset(iv, 0, sizeof(*iv)); + /* 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) { const char *opt = params->iv_ino_lblk_64 ? "--iv-ino-lblk-64" : "--iv-ino-lblk-32"; @@ -1831,6 +1861,8 @@ static void get_key_and_iv(const struct key_and_iv_params *params, die("%s requires --inode-number", opt); if (params->mode_num == 0) die("%s requires --mode-num", opt); + if (params->block_number > UINT32_MAX) + die("%s can't use --block-number > UINT32_MAX", opt); if (params->inode_number > UINT32_MAX) die("%s can't use --inode-number > UINT32_MAX", opt); } @@ -1860,14 +1892,17 @@ static void get_key_and_iv(const struct key_and_iv_params *params, info[infolen++] = params->mode_num; memcpy(&info[infolen], params->fs_uuid, UUID_SIZE); infolen += UUID_SIZE; - put_unaligned_le32(params->inode_number, &iv->bytes[4]); + iv->block_number32 = cpu_to_le32(params->block_number); + iv->inode_number = cpu_to_le32(params->inode_number); } else if (params->iv_ino_lblk_32) { info[infolen++] = HKDF_CONTEXT_IV_INO_LBLK_32_KEY; info[infolen++] = params->mode_num; memcpy(&info[infolen], params->fs_uuid, UUID_SIZE); infolen += UUID_SIZE; - put_unaligned_le32(hash_inode_number(params), - iv->bytes); + iv->block_number32 = + 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; @@ -1888,10 +1923,11 @@ static void get_key_and_iv(const struct key_and_iv_params *params, } if (file_nonce_in_iv && params->file_nonce_specified) - memcpy(&iv->bytes[8], params->file_nonce, FILE_NONCE_SIZE); + memcpy(iv->nonce, params->file_nonce, FILE_NONCE_SIZE); } enum { + OPT_BLOCK_NUMBER, OPT_BLOCK_SIZE, OPT_DECRYPT, OPT_FILE_NONCE, @@ -1906,6 +1942,7 @@ enum { }; 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 }, { "file-nonce", required_argument, NULL, OPT_FILE_NONCE }, @@ -1928,7 +1965,7 @@ int main(int argc, char *argv[]) size_t padding = 0; const struct fscrypt_cipher *cipher; u8 real_key[MAX_KEY_SIZE]; - struct fscrypt_iv iv; + union fscrypt_iv iv; char *tmp; int c; @@ -1947,6 +1984,12 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { switch (c) { + case OPT_BLOCK_NUMBER: + errno = 0; + params.block_number = strtoull(optarg, &tmp, 10); + if (*tmp || errno) + die("Invalid block number: %s", optarg); + break; case OPT_BLOCK_SIZE: errno = 0; block_size = strtoul(optarg, &tmp, 10); @@ -2025,6 +2068,7 @@ int main(int argc, char *argv[]) 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, block_size, padding, + params.iv_ino_lblk_64 || params.iv_ino_lblk_32); return 0; }