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[] ALIGN1 = "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)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
|
---|
23 | void (*sha_end)(void *ctx, void *resbuf) 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(&ctx, key_data, key_len);
|
---|
107 | sha_hash(&ctx, salt_data, salt_len);
|
---|
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(&alt_ctx, key_data, key_len);
|
---|
113 | sha_hash(&alt_ctx, salt_data, salt_len);
|
---|
114 | sha_hash(&alt_ctx, key_data, key_len);
|
---|
115 | sha_end(&alt_ctx, alt_result);
|
---|
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(&ctx, alt_result, _32or64);
|
---|
121 | sha_hash(&ctx, alt_result, cnt);
|
---|
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(&ctx, alt_result, _32or64);
|
---|
128 | else
|
---|
129 | sha_hash(&ctx, key_data, key_len);
|
---|
130 |
|
---|
131 | /* Create intermediate result. */
|
---|
132 | sha_end(&ctx, alt_result);
|
---|
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(&alt_ctx, key_data, key_len);
|
---|
139 | sha_end(&alt_ctx, temp_result);
|
---|
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(&alt_ctx, salt_data, salt_len);
|
---|
157 | sha_end(&alt_ctx, temp_result);
|
---|
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(&ctx, p_bytes, key_len);
|
---|
178 | else
|
---|
179 | sha_hash(&ctx, alt_result, _32or64);
|
---|
180 | /* Add salt for numbers not divisible by 3. */
|
---|
181 | if (cnt % 3 != 0)
|
---|
182 | sha_hash(&ctx, s_bytes, salt_len);
|
---|
183 | /* Add key for numbers not divisible by 7. */
|
---|
184 | if (cnt % 7 != 0)
|
---|
185 | sha_hash(&ctx, p_bytes, key_len);
|
---|
186 | /* Add key or last result. */
|
---|
187 | if ((cnt & 1) != 0)
|
---|
188 | sha_hash(&ctx, alt_result, _32or64);
|
---|
189 | else
|
---|
190 | sha_hash(&ctx, p_bytes, key_len);
|
---|
191 |
|
---|
192 | sha_end(&ctx, alt_result);
|
---|
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 | }
|
---|