Contents of /trunk/mkinitrd-magellan/busybox/libbb/pw_encrypt_sha.c
Parent Directory | Revision Log
Revision 1000 -
(show annotations)
(download)
Sun May 30 12:27:29 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 9430 byte(s)
Sun May 30 12:27:29 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 9430 byte(s)
-added missing files
1 | /* SHA256 and SHA512-based Unix crypt implementation. |
2 | * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. |
3 | */ |
4 | |
5 | /* Prefix for optional rounds specification. */ |
6 | static const char str_rounds[] = "rounds=%u$"; |
7 | |
8 | /* Maximum salt string length. */ |
9 | #define SALT_LEN_MAX 16 |
10 | /* Default number of rounds if not explicitly specified. */ |
11 | #define ROUNDS_DEFAULT 5000 |
12 | /* Minimum number of rounds. */ |
13 | #define ROUNDS_MIN 1000 |
14 | /* Maximum number of rounds. */ |
15 | #define ROUNDS_MAX 999999999 |
16 | |
17 | static char * |
18 | NOINLINE |
19 | sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) |
20 | { |
21 | void (*sha_begin)(void *ctx) FAST_FUNC; |
22 | void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC; |
23 | void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC; |
24 | int _32or64; |
25 | |
26 | char *result, *resptr; |
27 | |
28 | /* btw, sha256 needs [32] and uint32_t only */ |
29 | struct { |
30 | unsigned char alt_result[64]; |
31 | unsigned char temp_result[64]; |
32 | union { |
33 | sha256_ctx_t x; |
34 | sha512_ctx_t y; |
35 | } ctx; |
36 | union { |
37 | sha256_ctx_t x; |
38 | sha512_ctx_t y; |
39 | } alt_ctx; |
40 | } L __attribute__((__aligned__(__alignof__(uint64_t)))); |
41 | #define alt_result (L.alt_result ) |
42 | #define temp_result (L.temp_result) |
43 | #define ctx (L.ctx ) |
44 | #define alt_ctx (L.alt_ctx ) |
45 | unsigned salt_len; |
46 | unsigned key_len; |
47 | unsigned cnt; |
48 | unsigned rounds; |
49 | char *cp; |
50 | char is_sha512; |
51 | |
52 | /* Analyze salt, construct already known part of result */ |
53 | cnt = strlen(salt_data) + 1 + 43 + 1; |
54 | is_sha512 = salt_data[1]; |
55 | if (is_sha512 == '6') |
56 | cnt += 43; |
57 | result = resptr = xzalloc(cnt); /* will provide NUL terminator */ |
58 | *resptr++ = '$'; |
59 | *resptr++ = is_sha512; |
60 | *resptr++ = '$'; |
61 | rounds = ROUNDS_DEFAULT; |
62 | salt_data += 3; |
63 | if (strncmp(salt_data, str_rounds, 7) == 0) { |
64 | /* 7 == strlen("rounds=") */ |
65 | char *endp; |
66 | cnt = bb_strtou(salt_data + 7, &endp, 10); |
67 | if (*endp == '$') { |
68 | salt_data = endp + 1; |
69 | rounds = cnt; |
70 | if (rounds < ROUNDS_MIN) |
71 | rounds = ROUNDS_MIN; |
72 | if (rounds > ROUNDS_MAX) |
73 | rounds = ROUNDS_MAX; |
74 | /* add "rounds=NNNNN$" to result */ |
75 | resptr += sprintf(resptr, str_rounds, rounds); |
76 | } |
77 | } |
78 | salt_len = strchrnul(salt_data, '$') - salt_data; |
79 | if (salt_len > SALT_LEN_MAX) |
80 | salt_len = SALT_LEN_MAX; |
81 | /* xstrdup assures suitable alignment; also we will use it |
82 | as a scratch space later. */ |
83 | salt_data = xstrndup(salt_data, salt_len); |
84 | /* add "salt$" to result */ |
85 | strcpy(resptr, salt_data); |
86 | resptr += salt_len; |
87 | *resptr++ = '$'; |
88 | /* key data doesn't need much processing */ |
89 | key_len = strlen(key_data); |
90 | key_data = xstrdup(key_data); |
91 | |
92 | /* Which flavor of SHAnnn ops to use? */ |
93 | sha_begin = (void*)sha256_begin; |
94 | sha_hash = (void*)sha256_hash; |
95 | sha_end = (void*)sha256_end; |
96 | _32or64 = 32; |
97 | if (is_sha512 == '6') { |
98 | sha_begin = (void*)sha512_begin; |
99 | sha_hash = (void*)sha512_hash; |
100 | sha_end = (void*)sha512_end; |
101 | _32or64 = 64; |
102 | } |
103 | |
104 | /* Add KEY, SALT. */ |
105 | sha_begin(&ctx); |
106 | sha_hash(key_data, key_len, &ctx); |
107 | sha_hash(salt_data, salt_len, &ctx); |
108 | |
109 | /* Compute alternate SHA sum with input KEY, SALT, and KEY. |
110 | The final result will be added to the first context. */ |
111 | sha_begin(&alt_ctx); |
112 | sha_hash(key_data, key_len, &alt_ctx); |
113 | sha_hash(salt_data, salt_len, &alt_ctx); |
114 | sha_hash(key_data, key_len, &alt_ctx); |
115 | sha_end(alt_result, &alt_ctx); |
116 | |
117 | /* Add result of this to the other context. */ |
118 | /* Add for any character in the key one byte of the alternate sum. */ |
119 | for (cnt = key_len; cnt > _32or64; cnt -= _32or64) |
120 | sha_hash(alt_result, _32or64, &ctx); |
121 | sha_hash(alt_result, cnt, &ctx); |
122 | |
123 | /* Take the binary representation of the length of the key and for every |
124 | 1 add the alternate sum, for every 0 the key. */ |
125 | for (cnt = key_len; cnt != 0; cnt >>= 1) |
126 | if ((cnt & 1) != 0) |
127 | sha_hash(alt_result, _32or64, &ctx); |
128 | else |
129 | sha_hash(key_data, key_len, &ctx); |
130 | |
131 | /* Create intermediate result. */ |
132 | sha_end(alt_result, &ctx); |
133 | |
134 | /* Start computation of P byte sequence. */ |
135 | /* For every character in the password add the entire password. */ |
136 | sha_begin(&alt_ctx); |
137 | for (cnt = 0; cnt < key_len; ++cnt) |
138 | sha_hash(key_data, key_len, &alt_ctx); |
139 | sha_end(temp_result, &alt_ctx); |
140 | |
141 | /* NB: past this point, raw key_data is not used anymore */ |
142 | |
143 | /* Create byte sequence P. */ |
144 | #define p_bytes key_data /* reuse the buffer as it is of the key_len size */ |
145 | cp = p_bytes; /* was: ... = alloca(key_len); */ |
146 | for (cnt = key_len; cnt >= _32or64; cnt -= _32or64) { |
147 | cp = memcpy(cp, temp_result, _32or64); |
148 | cp += _32or64; |
149 | } |
150 | memcpy(cp, temp_result, cnt); |
151 | |
152 | /* Start computation of S byte sequence. */ |
153 | /* For every character in the password add the entire password. */ |
154 | sha_begin(&alt_ctx); |
155 | for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) |
156 | sha_hash(salt_data, salt_len, &alt_ctx); |
157 | sha_end(temp_result, &alt_ctx); |
158 | |
159 | /* NB: past this point, raw salt_data is not used anymore */ |
160 | |
161 | /* Create byte sequence S. */ |
162 | #define s_bytes salt_data /* reuse the buffer as it is of the salt_len size */ |
163 | cp = s_bytes; /* was: ... = alloca(salt_len); */ |
164 | for (cnt = salt_len; cnt >= _32or64; cnt -= _32or64) { |
165 | cp = memcpy(cp, temp_result, _32or64); |
166 | cp += _32or64; |
167 | } |
168 | memcpy(cp, temp_result, cnt); |
169 | |
170 | /* Repeatedly run the collected hash value through SHA to burn |
171 | CPU cycles. */ |
172 | for (cnt = 0; cnt < rounds; ++cnt) { |
173 | sha_begin(&ctx); |
174 | |
175 | /* Add key or last result. */ |
176 | if ((cnt & 1) != 0) |
177 | sha_hash(p_bytes, key_len, &ctx); |
178 | else |
179 | sha_hash(alt_result, _32or64, &ctx); |
180 | /* Add salt for numbers not divisible by 3. */ |
181 | if (cnt % 3 != 0) |
182 | sha_hash(s_bytes, salt_len, &ctx); |
183 | /* Add key for numbers not divisible by 7. */ |
184 | if (cnt % 7 != 0) |
185 | sha_hash(p_bytes, key_len, &ctx); |
186 | /* Add key or last result. */ |
187 | if ((cnt & 1) != 0) |
188 | sha_hash(alt_result, _32or64, &ctx); |
189 | else |
190 | sha_hash(p_bytes, key_len, &ctx); |
191 | |
192 | sha_end(alt_result, &ctx); |
193 | } |
194 | |
195 | /* Append encrypted password to result buffer */ |
196 | //TODO: replace with something like |
197 | // bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); |
198 | #define b64_from_24bit(B2, B1, B0, N) \ |
199 | do { \ |
200 | unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ |
201 | resptr = to64(resptr, w, N); \ |
202 | } while (0) |
203 | if (is_sha512 == '5') { |
204 | unsigned i = 0; |
205 | while (1) { |
206 | unsigned j = i + 10; |
207 | unsigned k = i + 20; |
208 | if (j >= 30) j -= 30; |
209 | if (k >= 30) k -= 30; |
210 | b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); |
211 | if (k == 29) |
212 | break; |
213 | i = k + 1; |
214 | } |
215 | b64_from_24bit(0, alt_result[31], alt_result[30], 3); |
216 | /* was: |
217 | b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4); |
218 | b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4); |
219 | b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4); |
220 | b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4); |
221 | b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4); |
222 | b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4); |
223 | b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4); |
224 | b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4); |
225 | b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4); |
226 | b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4); |
227 | b64_from_24bit(0, alt_result[31], alt_result[30], 3); |
228 | */ |
229 | } else { |
230 | unsigned i = 0; |
231 | while (1) { |
232 | unsigned j = i + 21; |
233 | unsigned k = i + 42; |
234 | if (j >= 63) j -= 63; |
235 | if (k >= 63) k -= 63; |
236 | b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); |
237 | if (j == 20) |
238 | break; |
239 | i = j + 1; |
240 | } |
241 | b64_from_24bit(0, 0, alt_result[63], 2); |
242 | /* was: |
243 | b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4); |
244 | b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4); |
245 | b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4); |
246 | b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4); |
247 | b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4); |
248 | b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4); |
249 | b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4); |
250 | b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4); |
251 | b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4); |
252 | b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4); |
253 | b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4); |
254 | b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4); |
255 | b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4); |
256 | b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4); |
257 | b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4); |
258 | b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4); |
259 | b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4); |
260 | b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4); |
261 | b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4); |
262 | b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4); |
263 | b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4); |
264 | b64_from_24bit(0, 0, alt_result[63], 2); |
265 | */ |
266 | } |
267 | /* *resptr = '\0'; - xzalloc did it */ |
268 | #undef b64_from_24bit |
269 | |
270 | /* Clear the buffer for the intermediate result so that people |
271 | attaching to processes or reading core dumps cannot get any |
272 | information. */ |
273 | memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */ |
274 | memset(key_data, 0, key_len); /* also p_bytes */ |
275 | memset(salt_data, 0, salt_len); /* also s_bytes */ |
276 | free(key_data); |
277 | free(salt_data); |
278 | #undef p_bytes |
279 | #undef s_bytes |
280 | |
281 | return result; |
282 | #undef alt_result |
283 | #undef temp_result |
284 | #undef ctx |
285 | #undef alt_ctx |
286 | } |