blob: 5e18d14666dc1f395d8dca53d3631e8eb28f360b [file] [log] [blame]
Theodore Ts'o52783e02002-03-11 15:04:45 -05001/*
2 * dirhash.c -- Calculate the hash of a directory entry
3 *
4 * Copyright (c) 2001 Daniel Phillips
5 *
6 * Copyright (c) 2002 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15
16#include "ext2_fs.h"
17#include "ext2fs.h"
18
Theodore Ts'ob33278c2002-08-17 10:52:51 -040019/*
20 * Keyed 32-bit hash function using TEA in a Davis-Meyer function
21 * H0 = Key
22 * Hi = E Mi(Hi-1) + Hi-1
23 *
24 * (see Applied Cryptography, 2nd edition, p448).
25 *
26 * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
27 *
28 * This code is made available under the terms of the GPL
29 */
30#define DELTA 0x9E3779B9
31
32static void TEA_transform(__u32 buf[4], __u32 const in[])
33{
34 __u32 sum = 0;
35 __u32 b0 = buf[0], b1 = buf[1];
36 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
37 int n = 16;
38
39 do {
40 sum += DELTA;
41 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
42 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
43 } while(--n);
44
45 buf[0] += b0;
46 buf[1] += b1;
47}
48
Theodore Ts'o503f9e72002-06-26 16:52:10 -040049/* F, G and H are basic MD4 functions: selection, majority, parity */
50#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
51#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
52#define H(x, y, z) ((x) ^ (y) ^ (z))
53
54/*
55 * The generic round function. The application is so specific that
56 * we don't bother protecting all the arguments with parens, as is generally
57 * good macro practice, in favor of extra legibility.
58 * Rotation is separate from addition to prevent recomputation
59 */
60#define ROUND(f, a, b, c, d, x, s) \
61 (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
62#define K1 0
63#define K2 013240474631UL
64#define K3 015666365641UL
65
66/*
67 * Basic cut-down MD4 transform. Returns only 32 bits of result.
68 */
Theodore Ts'ob33278c2002-08-17 10:52:51 -040069static void halfMD4Transform (__u32 buf[4], __u32 const in[])
Theodore Ts'o503f9e72002-06-26 16:52:10 -040070{
71 __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
72
73 /* Round 1 */
74 ROUND(F, a, b, c, d, in[0] + K1, 3);
75 ROUND(F, d, a, b, c, in[1] + K1, 7);
76 ROUND(F, c, d, a, b, in[2] + K1, 11);
77 ROUND(F, b, c, d, a, in[3] + K1, 19);
78 ROUND(F, a, b, c, d, in[4] + K1, 3);
79 ROUND(F, d, a, b, c, in[5] + K1, 7);
80 ROUND(F, c, d, a, b, in[6] + K1, 11);
81 ROUND(F, b, c, d, a, in[7] + K1, 19);
82
83 /* Round 2 */
84 ROUND(G, a, b, c, d, in[1] + K2, 3);
85 ROUND(G, d, a, b, c, in[3] + K2, 5);
86 ROUND(G, c, d, a, b, in[5] + K2, 9);
87 ROUND(G, b, c, d, a, in[7] + K2, 13);
88 ROUND(G, a, b, c, d, in[0] + K2, 3);
89 ROUND(G, d, a, b, c, in[2] + K2, 5);
90 ROUND(G, c, d, a, b, in[4] + K2, 9);
91 ROUND(G, b, c, d, a, in[6] + K2, 13);
92
93 /* Round 3 */
94 ROUND(H, a, b, c, d, in[3] + K3, 3);
95 ROUND(H, d, a, b, c, in[7] + K3, 9);
96 ROUND(H, c, d, a, b, in[2] + K3, 11);
97 ROUND(H, b, c, d, a, in[6] + K3, 15);
98 ROUND(H, a, b, c, d, in[1] + K3, 3);
99 ROUND(H, d, a, b, c, in[5] + K3, 9);
100 ROUND(H, c, d, a, b, in[0] + K3, 11);
101 ROUND(H, b, c, d, a, in[4] + K3, 15);
102
103 buf[0] += a;
104 buf[1] += b;
105 buf[2] += c;
106 buf[3] += d;
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400107}
108
109#undef ROUND
110#undef F
111#undef G
112#undef H
113#undef K1
114#undef K2
115#undef K3
116
117/* The old legacy hash */
Theodore Ts'o52783e02002-03-11 15:04:45 -0500118static ext2_dirhash_t dx_hack_hash (const char *name, int len)
119{
120 __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
121 while (len--) {
122 __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
123
124 if (hash & 0x80000000) hash -= 0x7fffffff;
125 hash1 = hash0;
126 hash0 = hash;
127 }
Theodore Ts'o1acb01b2002-03-12 13:41:31 -0500128 return (hash0 << 1);
Theodore Ts'o52783e02002-03-11 15:04:45 -0500129}
130
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400131static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
132{
133 __u32 pad, val;
134 int i;
135
136 pad = (__u32)len | ((__u32)len << 8);
137 pad |= pad << 16;
138
139 val = pad;
140 if (len > num*4)
141 len = num * 4;
142 for (i=0; i < len; i++) {
143 if ((i % 4) == 0)
144 val = pad;
145 val = msg[i] + (val << 8);
146 if ((i % 4) == 3) {
147 *buf++ = val;
148 val = pad;
149 num--;
150 }
151 }
152 if (--num >= 0)
153 *buf++ = val;
154 while (--num >= 0)
155 *buf++ = pad;
156}
157
Theodore Ts'o52783e02002-03-11 15:04:45 -0500158/*
159 * Returns the hash of a filename. If len is 0 and name is NULL, then
160 * this function can be used to test whether or not a hash version is
161 * supported.
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400162 *
163 * The seed is an 4 longword (32 bits) "secret" which can be used to
164 * uniquify a hash. If the seed is all zero's, then some default seed
165 * may be used.
166 *
167 * A particular hash version specifies whether or not the seed is
168 * represented, and whether or not the returned hash is 32 bits or 64
169 * bits. 32 bit hashes will return 0 for the minor hash.
Theodore Ts'o52783e02002-03-11 15:04:45 -0500170 */
171errcode_t ext2fs_dirhash(int version, const char *name, int len,
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400172 const __u32 *seed,
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400173 ext2_dirhash_t *ret_hash,
174 ext2_dirhash_t *ret_minor_hash)
Theodore Ts'o52783e02002-03-11 15:04:45 -0500175{
176 __u32 hash;
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400177 __u32 minor_hash = 0;
Theodore Ts'occ90bdf2002-07-23 13:11:53 -0400178 const char *p;
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400179 int i;
180 __u32 in[8], buf[4];
181
182 /* Initialize the default seed for the hash checksum functions */
183 buf[0] = 0x67452301;
184 buf[1] = 0xefcdab89;
185 buf[2] = 0x98badcfe;
186 buf[3] = 0x10325476;
Theodore Ts'o52783e02002-03-11 15:04:45 -0500187
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400188 /* Check to see if the seed is all zero's */
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400189 if (seed) {
190 for (i=0; i < 4; i++) {
191 if (seed[i])
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400192 break;
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400193 }
194 if (i < 4)
195 memcpy(buf, seed, sizeof(buf));
196 }
197
198 switch (version) {
199 case EXT2_HASH_LEGACY:
200 hash = dx_hack_hash(name, len);
201 break;
202 case EXT2_HASH_HALF_MD4:
203 p = name;
204 while (len > 0) {
205 str2hashbuf(p, len, in, 8);
206 halfMD4Transform(buf, in);
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400207 len -= 32;
208 p += 32;
209 }
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400210 minor_hash = buf[2];
211 hash = buf[1];
212 break;
213 case EXT2_HASH_TEA:
214 p = name;
215 while (len > 0) {
216 str2hashbuf(p, len, in, 4);
217 TEA_transform(buf, in);
218 len -= 16;
219 p += 16;
220 }
221 hash = buf[0];
222 minor_hash = buf[1];
223 break;
224 default:
Theodore Ts'o52783e02002-03-11 15:04:45 -0500225 *ret_hash = 0;
226 return EXT2_ET_DIRHASH_UNSUPP;
227 }
Theodore Ts'ob33278c2002-08-17 10:52:51 -0400228 *ret_hash = hash & ~1;
Theodore Ts'o503f9e72002-06-26 16:52:10 -0400229 if (ret_minor_hash)
230 *ret_minor_hash = minor_hash;
Theodore Ts'o52783e02002-03-11 15:04:45 -0500231 return 0;
Theodore Ts'o52783e02002-03-11 15:04:45 -0500232}