162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/hash.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2002 by Theodore Ts'o 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci#include <linux/unicode.h> 1062306a36Sopenharmony_ci#include <linux/compiler.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include "ext4.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define DELTA 0x9E3779B9 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void TEA_transform(__u32 buf[4], __u32 const in[]) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci __u32 sum = 0; 1962306a36Sopenharmony_ci __u32 b0 = buf[0], b1 = buf[1]; 2062306a36Sopenharmony_ci __u32 a = in[0], b = in[1], c = in[2], d = in[3]; 2162306a36Sopenharmony_ci int n = 16; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci do { 2462306a36Sopenharmony_ci sum += DELTA; 2562306a36Sopenharmony_ci b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); 2662306a36Sopenharmony_ci b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); 2762306a36Sopenharmony_ci } while (--n); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci buf[0] += b0; 3062306a36Sopenharmony_ci buf[1] += b1; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* F, G and H are basic MD4 functions: selection, majority, parity */ 3462306a36Sopenharmony_ci#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 3562306a36Sopenharmony_ci#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) 3662306a36Sopenharmony_ci#define H(x, y, z) ((x) ^ (y) ^ (z)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * The generic round function. The application is so specific that 4062306a36Sopenharmony_ci * we don't bother protecting all the arguments with parens, as is generally 4162306a36Sopenharmony_ci * good macro practice, in favor of extra legibility. 4262306a36Sopenharmony_ci * Rotation is separate from addition to prevent recomputation 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci#define ROUND(f, a, b, c, d, x, s) \ 4562306a36Sopenharmony_ci (a += f(b, c, d) + x, a = rol32(a, s)) 4662306a36Sopenharmony_ci#define K1 0 4762306a36Sopenharmony_ci#define K2 013240474631UL 4862306a36Sopenharmony_ci#define K3 015666365641UL 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Basic cut-down MD4 transform. Returns only 32 bits of result. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_cistatic __u32 half_md4_transform(__u32 buf[4], __u32 const in[8]) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* Round 1 */ 5862306a36Sopenharmony_ci ROUND(F, a, b, c, d, in[0] + K1, 3); 5962306a36Sopenharmony_ci ROUND(F, d, a, b, c, in[1] + K1, 7); 6062306a36Sopenharmony_ci ROUND(F, c, d, a, b, in[2] + K1, 11); 6162306a36Sopenharmony_ci ROUND(F, b, c, d, a, in[3] + K1, 19); 6262306a36Sopenharmony_ci ROUND(F, a, b, c, d, in[4] + K1, 3); 6362306a36Sopenharmony_ci ROUND(F, d, a, b, c, in[5] + K1, 7); 6462306a36Sopenharmony_ci ROUND(F, c, d, a, b, in[6] + K1, 11); 6562306a36Sopenharmony_ci ROUND(F, b, c, d, a, in[7] + K1, 19); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* Round 2 */ 6862306a36Sopenharmony_ci ROUND(G, a, b, c, d, in[1] + K2, 3); 6962306a36Sopenharmony_ci ROUND(G, d, a, b, c, in[3] + K2, 5); 7062306a36Sopenharmony_ci ROUND(G, c, d, a, b, in[5] + K2, 9); 7162306a36Sopenharmony_ci ROUND(G, b, c, d, a, in[7] + K2, 13); 7262306a36Sopenharmony_ci ROUND(G, a, b, c, d, in[0] + K2, 3); 7362306a36Sopenharmony_ci ROUND(G, d, a, b, c, in[2] + K2, 5); 7462306a36Sopenharmony_ci ROUND(G, c, d, a, b, in[4] + K2, 9); 7562306a36Sopenharmony_ci ROUND(G, b, c, d, a, in[6] + K2, 13); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Round 3 */ 7862306a36Sopenharmony_ci ROUND(H, a, b, c, d, in[3] + K3, 3); 7962306a36Sopenharmony_ci ROUND(H, d, a, b, c, in[7] + K3, 9); 8062306a36Sopenharmony_ci ROUND(H, c, d, a, b, in[2] + K3, 11); 8162306a36Sopenharmony_ci ROUND(H, b, c, d, a, in[6] + K3, 15); 8262306a36Sopenharmony_ci ROUND(H, a, b, c, d, in[1] + K3, 3); 8362306a36Sopenharmony_ci ROUND(H, d, a, b, c, in[5] + K3, 9); 8462306a36Sopenharmony_ci ROUND(H, c, d, a, b, in[0] + K3, 11); 8562306a36Sopenharmony_ci ROUND(H, b, c, d, a, in[4] + K3, 15); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci buf[0] += a; 8862306a36Sopenharmony_ci buf[1] += b; 8962306a36Sopenharmony_ci buf[2] += c; 9062306a36Sopenharmony_ci buf[3] += d; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return buf[1]; /* "most hashed" word */ 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci#undef ROUND 9562306a36Sopenharmony_ci#undef K1 9662306a36Sopenharmony_ci#undef K2 9762306a36Sopenharmony_ci#undef K3 9862306a36Sopenharmony_ci#undef F 9962306a36Sopenharmony_ci#undef G 10062306a36Sopenharmony_ci#undef H 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* The old legacy hash */ 10362306a36Sopenharmony_cistatic __u32 dx_hack_hash_unsigned(const char *name, int len) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; 10662306a36Sopenharmony_ci const unsigned char *ucp = (const unsigned char *) name; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci while (len--) { 10962306a36Sopenharmony_ci hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (hash & 0x80000000) 11262306a36Sopenharmony_ci hash -= 0x7fffffff; 11362306a36Sopenharmony_ci hash1 = hash0; 11462306a36Sopenharmony_ci hash0 = hash; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci return hash0 << 1; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic __u32 dx_hack_hash_signed(const char *name, int len) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; 12262306a36Sopenharmony_ci const signed char *scp = (const signed char *) name; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci while (len--) { 12562306a36Sopenharmony_ci hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (hash & 0x80000000) 12862306a36Sopenharmony_ci hash -= 0x7fffffff; 12962306a36Sopenharmony_ci hash1 = hash0; 13062306a36Sopenharmony_ci hash0 = hash; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci return hash0 << 1; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci __u32 pad, val; 13862306a36Sopenharmony_ci int i; 13962306a36Sopenharmony_ci const signed char *scp = (const signed char *) msg; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci pad = (__u32)len | ((__u32)len << 8); 14262306a36Sopenharmony_ci pad |= pad << 16; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci val = pad; 14562306a36Sopenharmony_ci if (len > num*4) 14662306a36Sopenharmony_ci len = num * 4; 14762306a36Sopenharmony_ci for (i = 0; i < len; i++) { 14862306a36Sopenharmony_ci val = ((int) scp[i]) + (val << 8); 14962306a36Sopenharmony_ci if ((i % 4) == 3) { 15062306a36Sopenharmony_ci *buf++ = val; 15162306a36Sopenharmony_ci val = pad; 15262306a36Sopenharmony_ci num--; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci if (--num >= 0) 15662306a36Sopenharmony_ci *buf++ = val; 15762306a36Sopenharmony_ci while (--num >= 0) 15862306a36Sopenharmony_ci *buf++ = pad; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci __u32 pad, val; 16462306a36Sopenharmony_ci int i; 16562306a36Sopenharmony_ci const unsigned char *ucp = (const unsigned char *) msg; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci pad = (__u32)len | ((__u32)len << 8); 16862306a36Sopenharmony_ci pad |= pad << 16; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci val = pad; 17162306a36Sopenharmony_ci if (len > num*4) 17262306a36Sopenharmony_ci len = num * 4; 17362306a36Sopenharmony_ci for (i = 0; i < len; i++) { 17462306a36Sopenharmony_ci val = ((int) ucp[i]) + (val << 8); 17562306a36Sopenharmony_ci if ((i % 4) == 3) { 17662306a36Sopenharmony_ci *buf++ = val; 17762306a36Sopenharmony_ci val = pad; 17862306a36Sopenharmony_ci num--; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci if (--num >= 0) 18262306a36Sopenharmony_ci *buf++ = val; 18362306a36Sopenharmony_ci while (--num >= 0) 18462306a36Sopenharmony_ci *buf++ = pad; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * Returns the hash of a filename. If len is 0 and name is NULL, then 18962306a36Sopenharmony_ci * this function can be used to test whether or not a hash version is 19062306a36Sopenharmony_ci * supported. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * The seed is an 4 longword (32 bits) "secret" which can be used to 19362306a36Sopenharmony_ci * uniquify a hash. If the seed is all zero's, then some default seed 19462306a36Sopenharmony_ci * may be used. 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * A particular hash version specifies whether or not the seed is 19762306a36Sopenharmony_ci * represented, and whether or not the returned hash is 32 bits or 64 19862306a36Sopenharmony_ci * bits. 32 bit hashes will return 0 for the minor hash. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_cistatic int __ext4fs_dirhash(const struct inode *dir, const char *name, int len, 20162306a36Sopenharmony_ci struct dx_hash_info *hinfo) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci __u32 hash; 20462306a36Sopenharmony_ci __u32 minor_hash = 0; 20562306a36Sopenharmony_ci const char *p; 20662306a36Sopenharmony_ci int i; 20762306a36Sopenharmony_ci __u32 in[8], buf[4]; 20862306a36Sopenharmony_ci void (*str2hashbuf)(const char *, int, __u32 *, int) = 20962306a36Sopenharmony_ci str2hashbuf_signed; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Initialize the default seed for the hash checksum functions */ 21262306a36Sopenharmony_ci buf[0] = 0x67452301; 21362306a36Sopenharmony_ci buf[1] = 0xefcdab89; 21462306a36Sopenharmony_ci buf[2] = 0x98badcfe; 21562306a36Sopenharmony_ci buf[3] = 0x10325476; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Check to see if the seed is all zero's */ 21862306a36Sopenharmony_ci if (hinfo->seed) { 21962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 22062306a36Sopenharmony_ci if (hinfo->seed[i]) { 22162306a36Sopenharmony_ci memcpy(buf, hinfo->seed, sizeof(buf)); 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci switch (hinfo->hash_version) { 22862306a36Sopenharmony_ci case DX_HASH_LEGACY_UNSIGNED: 22962306a36Sopenharmony_ci hash = dx_hack_hash_unsigned(name, len); 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case DX_HASH_LEGACY: 23262306a36Sopenharmony_ci hash = dx_hack_hash_signed(name, len); 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case DX_HASH_HALF_MD4_UNSIGNED: 23562306a36Sopenharmony_ci str2hashbuf = str2hashbuf_unsigned; 23662306a36Sopenharmony_ci fallthrough; 23762306a36Sopenharmony_ci case DX_HASH_HALF_MD4: 23862306a36Sopenharmony_ci p = name; 23962306a36Sopenharmony_ci while (len > 0) { 24062306a36Sopenharmony_ci (*str2hashbuf)(p, len, in, 8); 24162306a36Sopenharmony_ci half_md4_transform(buf, in); 24262306a36Sopenharmony_ci len -= 32; 24362306a36Sopenharmony_ci p += 32; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci minor_hash = buf[2]; 24662306a36Sopenharmony_ci hash = buf[1]; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case DX_HASH_TEA_UNSIGNED: 24962306a36Sopenharmony_ci str2hashbuf = str2hashbuf_unsigned; 25062306a36Sopenharmony_ci fallthrough; 25162306a36Sopenharmony_ci case DX_HASH_TEA: 25262306a36Sopenharmony_ci p = name; 25362306a36Sopenharmony_ci while (len > 0) { 25462306a36Sopenharmony_ci (*str2hashbuf)(p, len, in, 4); 25562306a36Sopenharmony_ci TEA_transform(buf, in); 25662306a36Sopenharmony_ci len -= 16; 25762306a36Sopenharmony_ci p += 16; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci hash = buf[0]; 26062306a36Sopenharmony_ci minor_hash = buf[1]; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case DX_HASH_SIPHASH: 26362306a36Sopenharmony_ci { 26462306a36Sopenharmony_ci struct qstr qname = QSTR_INIT(name, len); 26562306a36Sopenharmony_ci __u64 combined_hash; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (fscrypt_has_encryption_key(dir)) { 26862306a36Sopenharmony_ci combined_hash = fscrypt_fname_siphash(dir, &qname); 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci ext4_warning_inode(dir, "Siphash requires key"); 27162306a36Sopenharmony_ci return -1; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci hash = (__u32)(combined_hash >> 32); 27562306a36Sopenharmony_ci minor_hash = (__u32)combined_hash; 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci default: 27962306a36Sopenharmony_ci hinfo->hash = 0; 28062306a36Sopenharmony_ci hinfo->minor_hash = 0; 28162306a36Sopenharmony_ci ext4_warning(dir->i_sb, 28262306a36Sopenharmony_ci "invalid/unsupported hash tree version %u", 28362306a36Sopenharmony_ci hinfo->hash_version); 28462306a36Sopenharmony_ci return -EINVAL; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci hash = hash & ~1; 28762306a36Sopenharmony_ci if (hash == (EXT4_HTREE_EOF_32BIT << 1)) 28862306a36Sopenharmony_ci hash = (EXT4_HTREE_EOF_32BIT - 1) << 1; 28962306a36Sopenharmony_ci hinfo->hash = hash; 29062306a36Sopenharmony_ci hinfo->minor_hash = minor_hash; 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ciint ext4fs_dirhash(const struct inode *dir, const char *name, int len, 29562306a36Sopenharmony_ci struct dx_hash_info *hinfo) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 29862306a36Sopenharmony_ci const struct unicode_map *um = dir->i_sb->s_encoding; 29962306a36Sopenharmony_ci int r, dlen; 30062306a36Sopenharmony_ci unsigned char *buff; 30162306a36Sopenharmony_ci struct qstr qstr = {.name = name, .len = len }; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (len && IS_CASEFOLDED(dir) && 30462306a36Sopenharmony_ci (!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir))) { 30562306a36Sopenharmony_ci buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); 30662306a36Sopenharmony_ci if (!buff) 30762306a36Sopenharmony_ci return -ENOMEM; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci dlen = utf8_casefold(um, &qstr, buff, PATH_MAX); 31062306a36Sopenharmony_ci if (dlen < 0) { 31162306a36Sopenharmony_ci kfree(buff); 31262306a36Sopenharmony_ci goto opaque_seq; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci r = __ext4fs_dirhash(dir, buff, dlen, hinfo); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci kfree(buff); 31862306a36Sopenharmony_ci return r; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ciopaque_seq: 32162306a36Sopenharmony_ci#endif 32262306a36Sopenharmony_ci return __ext4fs_dirhash(dir, name, len, hinfo); 32362306a36Sopenharmony_ci} 324