1 ext4 crypto: simplify and speed up filename encryption
3 Avoid using SHA-1 when calculating the user-visible filename when the
4 encryption key is available, and avoid decrypting lots of filenames
5 when searching for a directory entry in a directory block.
7 Change-Id: If4655f144784978ba0305b597bfa1c8d7bb69e63
8 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
10 fs/ext4/crypto_fname.c | 268 +++++++++++++++++++++++++------------------------
13 fs/ext4/namei.c | 72 ++-----------
14 fs/ext4/symlink.c | 2 +-
15 5 files changed, 149 insertions(+), 204 deletions(-)
17 diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c
18 index ca2f594..7a877e6 100644
19 --- a/fs/ext4/crypto_fname.c
20 +++ b/fs/ext4/crypto_fname.c
21 @@ -198,106 +198,57 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
25 +static const char *lookup_table =
26 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
29 * ext4_fname_encode_digest() -
31 * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
32 * The encoded string is roughly 4/3 times the size of the input string.
34 -int ext4_fname_encode_digest(char *dst, char *src, u32 len)
35 +static int digest_encode(const char *src, int len, char *dst)
37 - static const char *lookup_table =
38 - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+";
39 - u32 current_chunk, num_chunks, i;
45 - for (i = 0; i < num_chunks; i++) {
46 - c0 = src[3*i] & 0x3f;
47 - c1 = (((src[3*i]>>6)&0x3) | ((src[3*i+1] & 0xf)<<2)) & 0x3f;
48 - c2 = (((src[3*i+1]>>4)&0xf) | ((src[3*i+2] & 0x3)<<4)) & 0x3f;
49 - c3 = (src[3*i+2]>>2) & 0x3f;
50 - dst[4*i] = lookup_table[c0];
51 - dst[4*i+1] = lookup_table[c1];
52 - dst[4*i+2] = lookup_table[c2];
53 - dst[4*i+3] = lookup_table[c3];
56 - memset(tmp_buf, 0, 3);
57 - memcpy(tmp_buf, &src[3*i], len-3*i);
58 - c0 = tmp_buf[0] & 0x3f;
59 - c1 = (((tmp_buf[0]>>6)&0x3) | ((tmp_buf[1] & 0xf)<<2)) & 0x3f;
60 - c2 = (((tmp_buf[1]>>4)&0xf) | ((tmp_buf[2] & 0x3)<<4)) & 0x3f;
61 - c3 = (tmp_buf[2]>>2) & 0x3f;
62 - dst[4*i] = lookup_table[c0];
63 - dst[4*i+1] = lookup_table[c1];
64 - dst[4*i+2] = lookup_table[c2];
65 - dst[4*i+3] = lookup_table[c3];
66 + int i = 0, bits = 0, ac = 0;
70 + ac += (((unsigned char) src[i]) << bits);
73 + *cp++ = lookup_table[ac & 0x3f];
76 + } while (bits >= 6);
81 + *cp++ = lookup_table[ac & 0x3f];
86 - * ext4_fname_hash() -
88 - * This function computes the hash of the input filename, and sets the output
89 - * buffer to the *encoded* digest. It returns the length of the digest as its
90 - * return value. Errors are returned as negative numbers. We trust the caller
91 - * to allocate sufficient memory to oname string.
93 -static int ext4_fname_hash(struct ext4_fname_crypto_ctx *ctx,
94 - const struct ext4_str *iname,
95 - struct ext4_str *oname)
96 +static int digest_decode(const char *src, int len, char *dst)
98 - struct scatterlist sg;
99 - struct hash_desc desc = {
100 - .tfm = (struct crypto_hash *)ctx->htfm,
101 - .flags = CRYPTO_TFM_REQ_MAY_SLEEP
105 - if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
106 - res = ext4_fname_encode_digest(oname->name, iname->name,
112 - sg_init_one(&sg, iname->name, iname->len);
113 - res = crypto_hash_init(&desc);
116 - "%s: Error initializing crypto hash; res = [%d]\n",
120 - res = crypto_hash_update(&desc, &sg, iname->len);
123 - "%s: Error updating crypto hash; res = [%d]\n",
127 - res = crypto_hash_final(&desc,
128 - &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE]);
131 - "%s: Error finalizing crypto hash; res = [%d]\n",
134 + int i = 0, bits = 0, ac = 0;
139 + p = strchr(lookup_table, src[i]);
140 + if (p == NULL || src[i] == 0)
142 + ac += (p - lookup_table) << bits;
151 - /* Encode the digest as a printable string--this will increase the
152 - * size of the digest */
153 - oname->name[0] = 'I';
154 - res = ext4_fname_encode_digest(oname->name+1,
155 - &oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE],
156 - EXT4_FNAME_CRYPTO_DIGEST_SIZE) + 1;
166 @@ -571,9 +522,13 @@ void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str)
167 * ext4_fname_disk_to_usr() - converts a filename from disk space to user space
169 int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
170 - const struct ext4_str *iname,
171 - struct ext4_str *oname)
172 + struct dx_hash_info *hinfo,
173 + const struct ext4_str *iname,
174 + struct ext4_str *oname)
181 if (iname->len < 3) {
182 @@ -587,18 +542,33 @@ int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
184 if (ctx->has_valid_key)
185 return ext4_fname_decrypt(ctx, iname, oname);
187 - return ext4_fname_hash(ctx, iname, oname);
189 + if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
190 + ret = digest_encode(iname->name, iname->len, oname->name);
195 + memcpy(buf, &hinfo->hash, 4);
196 + memcpy(buf+4, &hinfo->minor_hash, 4);
199 + memcpy(buf + 8, iname->name + iname->len - 16, 16);
200 + oname->name[0] = '_';
201 + ret = digest_encode(buf, 24, oname->name+1);
202 + oname->len = ret + 1;
206 int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
207 + struct dx_hash_info *hinfo,
208 const struct ext4_dir_entry_2 *de,
209 struct ext4_str *oname)
211 struct ext4_str iname = {.name = (unsigned char *) de->name,
212 .len = de->name_len };
214 - return _ext4_fname_disk_to_usr(ctx, &iname, oname);
215 + return _ext4_fname_disk_to_usr(ctx, hinfo, &iname, oname);
219 @@ -640,10 +610,11 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
220 const struct qstr *iname,
221 struct dx_hash_info *hinfo)
223 - struct ext4_str tmp, tmp2;
224 + struct ext4_str tmp;
226 + char buf[EXT4_FNAME_CRYPTO_DIGEST_SIZE+1];
228 - if (!ctx || !ctx->has_valid_key ||
230 ((iname->name[0] == '.') &&
231 ((iname->len == 1) ||
232 ((iname->name[1] == '.') && (iname->len == 2))))) {
233 @@ -651,59 +622,90 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
237 + if (!ctx->has_valid_key && iname->name[0] == '_') {
238 + if (iname->len != 33)
240 + ret = digest_decode(iname->name+1, iname->len, buf);
243 + memcpy(&hinfo->hash, buf, 4);
244 + memcpy(&hinfo->minor_hash, buf + 4, 4);
248 + if (!ctx->has_valid_key && iname->name[0] != '_') {
249 + if (iname->len > 43)
251 + ret = digest_decode(iname->name, iname->len, buf);
252 + ext4fs_dirhash(buf, ret, hinfo);
256 /* First encrypt the plaintext name */
257 ret = ext4_fname_crypto_alloc_buffer(ctx, iname->len, &tmp);
261 ret = ext4_fname_encrypt(ctx, iname, &tmp);
265 - tmp2.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1;
266 - tmp2.name = kmalloc(tmp2.len + 1, GFP_KERNEL);
267 - if (tmp2.name == NULL) {
271 + ext4fs_dirhash(tmp.name, tmp.len, hinfo);
275 - ret = ext4_fname_hash(ctx, &tmp, &tmp2);
277 - ext4fs_dirhash(tmp2.name, tmp2.len, hinfo);
278 - ext4_fname_crypto_free_buffer(&tmp2);
280 ext4_fname_crypto_free_buffer(&tmp);
285 - * ext4_fname_disk_to_htree() - converts a filename from disk space to htree-access string
287 -int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
288 - const struct ext4_dir_entry_2 *de,
289 - struct dx_hash_info *hinfo)
290 +int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
291 + int len, const char * const name,
292 + struct ext4_dir_entry_2 *de)
294 - struct ext4_str iname = {.name = (unsigned char *) de->name,
295 - .len = de->name_len};
296 - struct ext4_str tmp;
299 + int bigname = (*name == '_');
302 - ((iname.name[0] == '.') &&
303 - ((iname.len == 1) ||
304 - ((iname.name[1] == '.') && (iname.len == 2))))) {
305 - ext4fs_dirhash(iname.name, iname.len, hinfo);
307 + if (ctx->has_valid_key) {
308 + if (cstr->name == NULL) {
311 + ret = ext4_fname_crypto_alloc_buffer(ctx, len, cstr);
316 + ret = ext4_fname_encrypt(ctx, &istr, cstr);
321 + if (cstr->name == NULL) {
322 + cstr->name = kmalloc(32, GFP_KERNEL);
323 + if (cstr->name == NULL)
325 + if ((bigname && (len != 33)) ||
326 + (!bigname && (len > 43)))
328 + ret = digest_decode(name+bigname, len-bigname,
337 + if (de->name_len < 16)
339 + ret = memcmp(de->name + de->name_len - 16,
340 + cstr->name + 8, 16);
341 + return (ret == 0) ? 1 : 0;
345 - tmp.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1;
346 - tmp.name = kmalloc(tmp.len + 1, GFP_KERNEL);
347 - if (tmp.name == NULL)
350 - ret = ext4_fname_hash(ctx, &iname, &tmp);
352 - ext4fs_dirhash(tmp.name, tmp.len, hinfo);
353 - ext4_fname_crypto_free_buffer(&tmp);
354 + if (de->name_len != cstr->len)
356 + ret = memcmp(de->name, cstr->name, cstr->len);
357 + return (ret == 0) ? 1 : 0;
363 diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
364 index 61db51a5..5665d82 100644
367 @@ -249,7 +249,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
369 /* Directory is encrypted */
370 err = ext4_fname_disk_to_usr(enc_ctx,
371 - de, &fname_crypto_str);
372 + NULL, de, &fname_crypto_str);
376 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
377 index 0179654f..dfb1138 100644
380 @@ -2093,9 +2093,11 @@ u32 ext4_fname_crypto_round_up(u32 size, u32 blksize);
381 int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
382 u32 ilen, struct ext4_str *crypto_str);
383 int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
384 + struct dx_hash_info *hinfo,
385 const struct ext4_str *iname,
386 struct ext4_str *oname);
387 int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
388 + struct dx_hash_info *hinfo,
389 const struct ext4_dir_entry_2 *de,
390 struct ext4_str *oname);
391 int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
392 @@ -2104,11 +2106,12 @@ int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
393 int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
394 const struct qstr *iname,
395 struct dx_hash_info *hinfo);
396 -int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
397 - const struct ext4_dir_entry_2 *de,
398 - struct dx_hash_info *hinfo);
399 int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
401 +int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
402 + int len, const char * const name,
403 + struct ext4_dir_entry_2 *de);
406 #ifdef CONFIG_EXT4_FS_ENCRYPTION
407 void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx);
408 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
409 index 4f87127..5ea7371 100644
410 --- a/fs/ext4/namei.c
411 +++ b/fs/ext4/namei.c
412 @@ -640,7 +640,7 @@ static struct stats dx_show_leaf(struct inode *dir,
413 ext4_put_fname_crypto_ctx(&ctx);
416 - res = ext4_fname_disk_to_usr(ctx, de,
417 + res = ext4_fname_disk_to_usr(ctx, NULL, de,
420 printk(KERN_WARNING "Error "
421 @@ -653,15 +653,8 @@ static struct stats dx_show_leaf(struct inode *dir,
422 name = fname_crypto_str.name;
423 len = fname_crypto_str.len;
425 - res = ext4_fname_disk_to_hash(ctx, de,
428 - printk(KERN_WARNING "Error "
429 - "converting filename "
430 - "from disk to htree"
432 - h.hash = 0xDEADBEEF;
434 + ext4fs_dirhash(de->name, de->name_len,
436 printk("%*.s:(E)%x.%u ", len, name,
437 h.hash, (unsigned) ((char *) de
439 @@ -1008,15 +1001,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
440 /* silently ignore the rest of the block */
443 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
444 - err = ext4_fname_disk_to_hash(ctx, de, hinfo);
450 ext4fs_dirhash(de->name, de->name_len, hinfo);
452 if ((hinfo->hash < start_hash) ||
453 ((hinfo->hash == start_hash) &&
454 (hinfo->minor_hash < start_minor_hash)))
455 @@ -1032,7 +1017,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
458 /* Directory is encrypted */
459 - err = ext4_fname_disk_to_usr(ctx, de,
460 + err = ext4_fname_disk_to_usr(ctx, hinfo, de,
464 @@ -1193,26 +1178,10 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
466 char *base = (char *) de;
467 struct dx_hash_info h = *hinfo;
468 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
469 - struct ext4_fname_crypto_ctx *ctx = NULL;
472 - ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
474 - return PTR_ERR(ctx);
477 while ((char *) de < base + blocksize) {
478 if (de->name_len && de->inode) {
479 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
480 - err = ext4_fname_disk_to_hash(ctx, de, &h);
482 - ext4_put_fname_crypto_ctx(&ctx);
486 ext4fs_dirhash(de->name, de->name_len, &h);
489 map_tail->hash = h.hash;
490 map_tail->offs = ((char *) de - base)>>2;
491 @@ -1223,9 +1192,6 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
492 /* XXX: do we need to check rec_len == 0 case? -Chris */
493 de = ext4_next_entry(de, blocksize);
495 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
496 - ext4_put_fname_crypto_ctx(&ctx);
501 @@ -1287,16 +1253,8 @@ static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx,
504 #ifdef CONFIG_EXT4_FS_ENCRYPTION
506 - /* Directory is encrypted */
507 - res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
512 - res = memcmp(name, fname_crypto_str->name, len);
513 - return (res == 0) ? 1 : 0;
516 + return ext4_fname_match(ctx, fname_crypto_str, len, name, de);
518 if (len != de->name_len)
520 @@ -1324,16 +1282,6 @@ int search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
525 - /* Allocate buffer to hold maximum name length */
526 - res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
527 - &fname_crypto_str);
529 - ext4_put_fname_crypto_ctx(&ctx);
534 de = (struct ext4_dir_entry_2 *)search_buf;
535 dlimit = search_buf + buf_size;
536 while ((char *) de < dlimit) {
537 @@ -1872,14 +1820,6 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
540 reclen = EXT4_DIR_REC_LEN(res);
542 - /* Allocate buffer to hold maximum name length */
543 - res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
544 - &fname_crypto_str);
546 - ext4_put_fname_crypto_ctx(&ctx);
551 de = (struct ext4_dir_entry_2 *)buf;
552 diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
553 index 136ca0e..ce2ed28 100644
554 --- a/fs/ext4/symlink.c
555 +++ b/fs/ext4/symlink.c
556 @@ -74,7 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
560 - res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
561 + res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
564 /* Null-terminate the name */