From: Theodore Ts'o Date: Sun, 3 May 2015 18:48:25 +0000 (-0400) Subject: Update ext4 encryption format to final v4.1 version X-Git-Tag: v1.43-WIP-2015-05-18~35 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=437651ad234e125e2ef9c9f213cb3f5c92e67307;p=tools%2Fe2fsprogs.git Update ext4 encryption format to final v4.1 version The directory hash is now calculated using the on-disk encrypted filename, and we no longer use the digest encoding or the SHA-256 encoding, so remove them from the ext2fs library until there is some reason we need them. Signed-off-by: Theodore Ts'o --- diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index d795c06..ecc0aaa 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -855,32 +855,6 @@ err: return retval; } -int get_filename_hash(ext2_filsys fs, int encrypted, int version, - const char *name, int len, ext2_dirhash_t *ret_hash, - ext2_dirhash_t *ret_minor_hash) -{ - char buf[2*EXT2FS_DIGEST_SIZE]; - int buf_len; - - if (!encrypted) - return ext2fs_dirhash(version, name, len, - fs->super->s_hash_seed, - ret_hash, ret_minor_hash); - - if (len <= EXT2FS_DIGEST_SIZE) - buf_len = ext2fs_digest_encode(name, len, buf); - else { - ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE); - buf[0] = 'I'; - buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE, - EXT2FS_DIGEST_SIZE, buf + 1); - buf_len++; - } - return ext2fs_dirhash(version, buf, buf_len, - fs->super->s_hash_seed, - ret_hash, ret_minor_hash); -} - static int check_dir_block2(ext2_filsys fs, struct ext2_db_entry2 *db, void *priv_data) @@ -1422,10 +1396,9 @@ skip_checksum: #ifdef ENABLE_HTREE if (dx_db) { - get_filename_hash(fs, encrypted, dx_dir->hashversion, - dirent->name, - ext2fs_dirent_name_len(dirent), - &hash, 0); + ext2fs_dirhash(dx_dir->hashversion, dirent->name, + ext2fs_dirent_name_len(dirent), + fs->super->s_hash_seed, &hash, 0); if (hash < dx_db->min_hash) dx_db->min_hash = hash; if (hash > dx_db->max_hash) diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index 3efa114..bddbe19 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -112,9 +112,6 @@ static int fill_dir_block(ext2_filsys fs, char *dir; unsigned int offset, dir_offset, rec_len, name_len; int hash_alg; - int encrypted = 0; - char processed_filename[2*EXT2FS_DIGEST_SIZE]; - int processed_filename_len; if (blockcnt < 0) return 0; @@ -125,11 +122,6 @@ static int fill_dir_block(ext2_filsys fs, return BLOCK_ABORT; } - /* Determine if the directory is encrypted */ - if (fd->ctx->encrypted_dirs) - encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs, - fd->ino); - dir = (fd->buf+offset); if (*block_nr == 0) { memset(dir, 0, fs->blocksize); @@ -190,10 +182,10 @@ static int fill_dir_block(ext2_filsys fs, if (fd->compress) ent->hash = ent->minor_hash = 0; else { - fd->err = get_filename_hash(fs, encrypted, - hash_alg, dirent->name, - ext2fs_dirent_name_len(dirent), - &ent->hash, &ent->minor_hash); + fd->err = ext2fs_dirhash(hash_alg, dirent->name, + name_len, + fs->super->s_hash_seed, + &ent->hash, &ent->minor_hash); if (fd->err) return BLOCK_ABORT; } @@ -378,9 +370,6 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, char new_name[256]; unsigned int new_len; int hash_alg; - int encrypted = 0; - char processed_filename[2*EXT2FS_DIGEST_SIZE]; - int processed_filename_len; clear_problem_context(&pctx); pctx.ino = ino; @@ -390,10 +379,6 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) hash_alg += 3; - /* Determine if the directory is encrypted */ - if (fd->ctx->encrypted_dirs) - encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs, - fd->ino); for (i=1; i < fd->num_array; i++) { ent = fd->harray + i; prev = ent - 1; @@ -429,9 +414,9 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) { memcpy(ent->dir->name, new_name, new_len); ext2fs_dirent_set_name_len(ent->dir, new_len); - get_filename_hash(fs, encrypted, - hash_alg, new_name, new_len, - &ent->hash, &ent->minor_hash); + ext2fs_dirhash(hash_alg, new_name, new_len, + fs->super->s_hash_seed, + &ent->hash, &ent->minor_hash); fixed++; } } diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index 8a7f8ca..2146979 100644 --- a/lib/ext2fs/Makefile.in +++ b/lib/ext2fs/Makefile.in @@ -73,7 +73,6 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ csum.o \ dblist.o \ dblist_dir.o \ - digest_encode.o \ dirblock.o \ dirhash.o \ dir_iterate.o \ @@ -116,7 +115,6 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ read_bb_file.o \ res_gdt.o \ rw_bitmaps.o \ - sha256.o \ sha512.o \ swapfs.o \ symlink.o \ diff --git a/lib/ext2fs/digest_encode.c b/lib/ext2fs/digest_encode.c index a24ba6c..d90b300 100644 --- a/lib/ext2fs/digest_encode.c +++ b/lib/ext2fs/digest_encode.c @@ -20,47 +20,60 @@ #endif #include "ext2fs.h" +static const char *lookup_table = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + /** * ext2fs_digest_encode() - * * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. * The encoded string is roughly 4/3 times the size of the input string. */ -int ext2fs_digest_encode(const char *src, unsigned long len, char *dst) +int ext2fs_digest_encode(const char *src, int len, char *dst) { - static const char *lookup_table = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+"; - unsigned num_chunks, i; - char tmp_buf[3]; - unsigned c0, c1, c2, c3; + int i = 0, bits = 0, ac = 0; + char *cp = dst; - num_chunks = len/3; - for (i = 0; i < num_chunks; i++) { - c0 = src[3*i] & 0x3f; - c1 = (((src[3*i]>>6)&0x3) | ((src[3*i+1] & 0xf)<<2)) & 0x3f; - c2 = (((src[3*i+1]>>4)&0xf) | ((src[3*i+2] & 0x3)<<4)) & 0x3f; - c3 = (src[3*i+2]>>2) & 0x3f; - dst[4*i] = lookup_table[c0]; - dst[4*i+1] = lookup_table[c1]; - dst[4*i+2] = lookup_table[c2]; - dst[4*i+3] = lookup_table[c3]; + while (i < len) { + ac += (((unsigned char) src[i]) << bits); + bits += 8; + do { + *cp++ = lookup_table[ac & 0x3f]; + ac >>= 6; + bits -= 6; + } while (bits >= 6); + i++; } - if (i*3 < len) { - memset(tmp_buf, 0, 3); - memcpy(tmp_buf, &src[3*i], len-3*i); - c0 = tmp_buf[0] & 0x3f; - c1 = (((tmp_buf[0]>>6)&0x3) | ((tmp_buf[1] & 0xf)<<2)) & 0x3f; - c2 = (((tmp_buf[1]>>4)&0xf) | ((tmp_buf[2] & 0x3)<<4)) & 0x3f; - c3 = (tmp_buf[2]>>2) & 0x3f; - dst[4*i] = lookup_table[c0]; - dst[4*i+1] = lookup_table[c1]; - dst[4*i+2] = lookup_table[c2]; - dst[4*i+3] = lookup_table[c3]; + if (bits) + *cp++ = lookup_table[ac & 0x3f]; + return cp - dst; +} + +int ext2fs_digest_decode(const char *src, int len, char *dst) +{ + int i = 0, bits = 0, ac = 0; + const char *p; + char *cp = dst; + + while (i < len) { + p = strchr(lookup_table, src[i]); + if (p == NULL || src[i] == 0) + return -1; + ac += (p - lookup_table) << bits; + bits += 6; + if (bits >= 8) { + *cp++ = ac & 0xff; + ac >>= 8; + bits -= 8; + } i++; } - return (i * 4); + if (ac) + return -1; + return cp - dst; } + #ifdef UNITTEST static const struct { unsigned char d[32]; @@ -71,52 +84,65 @@ static const struct { 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32, - "JdlXcHj+CqHM7tpYz_wUKCIRbrozBojtKwzMBGNu4wfa" + "jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF" }, { { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32, - "6INf+_yapREqbbK3D5QiJa7aHnQLxOhN0cX+Hjpav0ka" + "6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K" }, { { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32, - "K0OAHjTb4GB5aBYKm4dy5mkpKNfz+hYz2ZE7uNX2gema" + "k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM" }, { { 0x00, }, 1, - "aaaa" + "AA" }, { { 0x01, }, 1, - "baaa" + "BA" }, { { 0x01, 0x02 }, 2, - "biaa" + "BIA" }, { { 0x01, 0x02, 0x03 }, 3, - "biWa" + "BIwA" }, { { 0x01, 0x02, 0x03, 0x04 }, 4, - "biWaeaaa" + "BIwAEA" }, { { 0x01, 0x02, 0x03, 0x04, 0xff }, 5, - "biWae8pa" + "BIwAE8P" }, { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6, - "biWae8V+" + "BIwAE8v," }, { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7, - "biWae8V+9daa" + "BIwAE8v,9D" }, }; int main(int argc, char **argv) { - int i, ret, len; + int i, ret, len, len2; int errors = 0; - unsigned char tmp[1024]; + unsigned char tmp[1024], tmp2[1024]; + if (argc == 3 && !strcmp(argv[1], "encode")) { + memset(tmp, 0, sizeof(tmp)); + ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp); + puts(tmp); + exit(0); + } + if (argc == 3 && !strcmp(argv[1], "decode")) { + memset(tmp, 0, sizeof(tmp)); + ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp); + puts(tmp); + fprintf(stderr, "returned %d\n", ret); + exit(0); + } for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { memset(tmp, 0, sizeof(tmp)); ret = ext2fs_digest_encode(tests[i].d, tests[i].len, tmp); @@ -126,12 +152,26 @@ int main(int argc, char **argv) printf("FAILED returned %d, string length was %d\n", ret, len); errors++; - } else if (memcmp(tmp, tests[i].ed, ret) != 0) { + continue; + } else if (strcmp(tmp, tests[i].ed) != 0) { printf("FAILED: got %s, expected %s\n", tmp, tests[i].ed); errors++; - } else - printf("OK\n"); + continue; + } + ret = ext2fs_digest_decode(tmp, len, tmp2); + if (ret != tests[i].len) { + printf("FAILED decode returned %d, expected %d\n", + ret, tests[i].len); + errors++; + continue; + } + if (memcmp(tmp2, tests[i].d, ret) != 0) { + puts("FAILED: decode mismatched"); + errors++; + continue; + } + printf("OK\n"); } for (i = 1; i < argc; i++) { memset(tmp, 0, sizeof(tmp)); diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h index a755cfa..918ae70 100644 --- a/lib/ext2fs/ext2_fs.h +++ b/lib/ext2fs/ext2_fs.h @@ -593,6 +593,7 @@ struct ext4_encryption_policy { char version; char contents_encryption_mode; char filenames_encryption_mode; + char flags; char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; } __attribute__((__packed__)); diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 560b148..17a4590 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -1071,9 +1071,12 @@ extern errcode_t void *priv_data), void *priv_data); +#if 0 /* digest_encode.c */ #define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH -extern int ext2fs_digest_encode(const char *src, unsigned long len, char *dst); +extern int ext2fs_digest_encode(const char *src, int len, char *dst); +extern int ext2fs_digest_decode(const char *src, int len, char *dst); +#endif /* dirblock.c */ extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, @@ -1564,10 +1567,12 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, /* res_gdt.c */ extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); +#if 0 /*sha256.c */ #define EXT2FS_SHA256_LENGTH 32 extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, unsigned char out[EXT2FS_SHA256_LENGTH]); +#endif /* sha512.c */ #define EXT2FS_SHA512_LENGTH 64 diff --git a/misc/e4crypt.c b/misc/e4crypt.c index f2b30cd..b99421a 100644 --- a/misc/e4crypt.c +++ b/misc/e4crypt.c @@ -95,6 +95,18 @@ static const size_t hexchars_size = 16; #define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) #define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) +static int int_log2(int arg) +{ + int l = 0; + + arg >>= 1; + while (arg) { + l++; + arg >>= 1; + } + return l; +} + static void validate_paths(int argc, char *argv[], int path_start_index) { int x; @@ -313,7 +325,7 @@ static void parse_salt(char *salt_str, int flags) add_salt(salt_buf, salt_len); } -static void set_policy(struct salt *set_salt, +static void set_policy(struct salt *set_salt, int pad, int argc, char *argv[], int path_start_index) { struct salt *salt; @@ -323,6 +335,12 @@ static void set_policy(struct salt *set_salt, int x; int rc; + if ((pad != 4) && (pad != 8) && + (pad != 16) && (pad != 32)) { + fprintf(stderr, "Invalid padding %d\n", pad); + exit(1); + } + for (x = path_start_index; x < argc; x++) { fd = open(argv[x], O_DIRECTORY); if (fd == -1) { @@ -348,6 +366,7 @@ static void set_policy(struct salt *set_salt, EXT4_ENCRYPTION_MODE_AES_256_XTS; policy.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS; + policy.flags = int_log2(pad >> 2); memcpy(policy.master_key_descriptor, salt->key_desc, EXT4_KEY_DESCRIPTOR_SIZE); rc = ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy); @@ -610,14 +629,17 @@ void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) { struct salt *salt; char *keyring = NULL; - int i, opt; + int i, opt, pad = 4; - while ((opt = getopt(argc, argv, "k:S:vq")) != -1) { + while ((opt = getopt(argc, argv, "k:S:p:vq")) != -1) { switch (opt) { case 'k': /* Specify a keyring. */ keyring = optarg; break; + case 'p': + pad = atoi(optarg); + break; case 'S': /* Salt value for passphrase. */ parse_salt(optarg, 0); @@ -654,7 +676,7 @@ void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) insert_key_into_keyring(keyring, salt); } if (optind != argc) - set_policy(NULL, argc, argv, optind); + set_policy(NULL, pad, argc, argv, optind); clear_secrets(); exit(0); } @@ -674,27 +696,38 @@ void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) char *key_ref_str = NULL; char *keyring = NULL; int add_passphrase = 0; - int i, opt; + int i, c, opt, pad = 4; - if (argc < 3) { + while ((c = getopt (argc, argv, "p:")) != EOF) { + switch (c) { + case 'p': + pad = atoi(optarg); + break; + } + } + + if (argc < optind + 2) { fprintf(stderr, "Missing required argument(s).\n\n"); fputs("USAGE:\n ", stderr); fputs(cmd->cmd_help, stderr); exit(1); } - strcpy(saltbuf.key_ref_str, argv[1]); - if ((strlen(argv[1]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || - hex2byte(argv[1], (EXT4_KEY_DESCRIPTOR_SIZE * 2), + printf("arg %s\n", argv[optind]); + exit(0); + + strcpy(saltbuf.key_ref_str, argv[optind]); + if ((strlen(argv[optind]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || + hex2byte(argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2), saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) { printf("Invalid key descriptor [%s]. Valid characters " "are 0-9 and a-f, lower case. " "Length must be %d.\n", - argv[1], (EXT4_KEY_DESCRIPTOR_SIZE * 2)); + argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2)); exit(1); } - validate_paths(argc, argv, 2); - set_policy(&saltbuf, argc, argv, 2); + validate_paths(argc, argv, optind+1); + set_policy(&saltbuf, pad, argc, argv, optind+1); exit(0); }