Branch data Line data Source code
1 : : /* This file is based on the work of Ulrich Drepper
2 : : * (http://people.redhat.com/drepper/SHA-crypt.txt). I have replaced the
3 : : * included SHA512 implementation by calls to NSS
4 : : * (http://www.mozilla.org/projects/security/pki/nss/).
5 : : *
6 : : * Sumit Bose <sbose@redhat.com>
7 : : */
8 : : /* SHA512-based Unix crypt implementation.
9 : : Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
10 : :
11 : : #include "config.h"
12 : :
13 : : #include <endian.h>
14 : : #include <errno.h>
15 : : #include <limits.h>
16 : : #include <stdbool.h>
17 : : #include <stdint.h>
18 : : #include <stdio.h>
19 : : #include <stdlib.h>
20 : : #include <string.h>
21 : : #include <sys/param.h>
22 : : #include <sys/types.h>
23 : :
24 : : #include "util/util.h"
25 : : #include "util/crypto/nss/nss_util.h"
26 : :
27 : : #include <prinit.h>
28 : : #include <nss.h>
29 : : #include <sechash.h>
30 : : #include <pk11func.h>
31 : :
32 : : /* Define our magic string to mark salt for SHA512 "encryption" replacement. */
33 : : const char sha512_salt_prefix[] = "$6$";
34 : : #define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1)
35 : :
36 : : /* Prefix for optional rounds specification. */
37 : : const char sha512_rounds_prefix[] = "rounds=";
38 : : #define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1)
39 : :
40 : : #define SALT_LEN_MAX 16
41 : : #define ROUNDS_DEFAULT 5000
42 : : #define ROUNDS_MIN 1000
43 : : #define ROUNDS_MAX 999999999
44 : :
45 : : /* Table with characters for base64 transformation. */
46 : : const char b64t[64] =
47 : : "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
48 : :
49 : : /* base64 conversion function */
50 : 114 : static inline void b64_from_24bit(char **dest, size_t *len, size_t n,
51 : : uint8_t b2, uint8_t b1, uint8_t b0)
52 : : {
53 : : uint32_t w;
54 : : size_t i;
55 : :
56 [ - + ]: 114 : if (*len < n) n = *len;
57 : :
58 : 114 : w = (b2 << 16) | (b1 << 8) | b0;
59 [ + + ]: 560 : for (i = 0; i < n; i++) {
60 : 446 : (*dest)[i] = b64t[w & 0x3f];
61 : 446 : w >>= 6;
62 : : }
63 : :
64 : 114 : *len -= i;
65 : 114 : *dest += i;
66 : 114 : }
67 : :
68 : : #define PTR_2_INT(x) ((x) - ((__typeof__ (x)) NULL))
69 : : #define ALIGN64 __alignof__(uint64_t)
70 : :
71 : 5 : static int sha512_crypt_r(const char *key,
72 : : const char *salt,
73 : : char *buffer, size_t buflen)
74 : : {
75 : : unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64)));
76 : : unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64)));
77 : 5 : size_t rounds = ROUNDS_DEFAULT;
78 : 5 : bool rounds_custom = false;
79 : 5 : HASHContext *alt_ctx = NULL;
80 : 5 : HASHContext *ctx = NULL;
81 : : size_t salt_len;
82 : : size_t key_len;
83 : : size_t cnt;
84 : 5 : char *copied_salt = NULL;
85 : 5 : char *copied_key = NULL;
86 : 5 : char *p_bytes = NULL;
87 : 5 : char *s_bytes = NULL;
88 : : int p1, p2, p3, pt, n;
89 : : unsigned int part;
90 : : char *cp, *tmp;
91 : : int ret;
92 : :
93 : : /* Find beginning of salt string. The prefix should normally always be
94 : : * present. Just in case it is not. */
95 [ + + ]: 5 : if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
96 : : /* Skip salt prefix. */
97 : 4 : salt += SALT_PREF_SIZE;
98 : : }
99 : :
100 [ - + ]: 5 : if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
101 : : unsigned long int srounds;
102 : : const char *num;
103 : : char *endp;
104 : :
105 : 0 : num = salt + ROUNDS_SIZE;
106 : 0 : srounds = strtoul(num, &endp, 10);
107 [ # # ]: 0 : if (*endp == '$') {
108 : 0 : salt = endp + 1;
109 [ # # ]: 0 : if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
110 [ # # ]: 0 : if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
111 : 0 : rounds = srounds;
112 : 0 : rounds_custom = true;
113 : : }
114 : : }
115 : :
116 [ - + ][ # # ]: 5 : salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
117 : 5 : key_len = strlen(key);
118 : :
119 [ - + ]: 5 : if ((PTR_2_INT(key) % ALIGN64) != 0) {
120 : 0 : tmp = (char *)alloca(key_len + ALIGN64);
121 : 0 : key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
122 : : }
123 : :
124 [ + + ]: 5 : if (PTR_2_INT(salt) % ALIGN64 != 0) {
125 : 4 : tmp = (char *)alloca(salt_len + ALIGN64);
126 : 4 : salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
127 : : }
128 : :
129 : 5 : ret = nspr_nss_init();
130 [ + - ]: 5 : if (ret != EOK) {
131 : : ret = EIO;
132 : : goto done;
133 : : }
134 : :
135 : 5 : ctx = HASH_Create(HASH_AlgSHA512);
136 [ + - ]: 5 : if (!ctx) {
137 : : ret = EIO;
138 : : goto done;
139 : : }
140 : :
141 : 5 : alt_ctx = HASH_Create(HASH_AlgSHA512);
142 [ + - ]: 5 : if (!alt_ctx) {
143 : : ret = EIO;
144 : : goto done;
145 : : }
146 : :
147 : : /* Prepare for the real work. */
148 : 5 : HASH_Begin(ctx);
149 : :
150 : : /* Add the key string. */
151 : 5 : HASH_Update(ctx, (const unsigned char *)key, key_len);
152 : :
153 : : /* The last part is the salt string. This must be at most 16
154 : : * characters and it ends at the first `$' character (for
155 : : * compatibility with existing implementations). */
156 : 5 : HASH_Update(ctx, (const unsigned char *)salt, salt_len);
157 : :
158 : :
159 : : /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
160 : : * The final result will be added to the first context. */
161 : 5 : HASH_Begin(alt_ctx);
162 : :
163 : : /* Add key. */
164 : 5 : HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
165 : :
166 : : /* Add salt. */
167 : 5 : HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
168 : :
169 : : /* Add key again. */
170 : 5 : HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
171 : :
172 : : /* Now get result of this (64 bytes) and add it to the other context. */
173 : 5 : HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx));
174 : :
175 : : /* Add for any character in the key one byte of the alternate sum. */
176 [ - + ]: 5 : for (cnt = key_len; cnt > 64; cnt -= 64) {
177 : 0 : HASH_Update(ctx, alt_result, 64);
178 : : }
179 : 5 : HASH_Update(ctx, alt_result, cnt);
180 : :
181 : : /* Take the binary representation of the length of the key and for every
182 : : * 1 add the alternate sum, for every 0 the key. */
183 [ + + ]: 21 : for (cnt = key_len; cnt > 0; cnt >>= 1) {
184 [ + + ]: 16 : if ((cnt & 1) != 0) {
185 : 13 : HASH_Update(ctx, alt_result, 64);
186 : : } else {
187 : 3 : HASH_Update(ctx, (const unsigned char *)key, key_len);
188 : : }
189 : : }
190 : :
191 : : /* Create intermediate result. */
192 : 5 : HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
193 : :
194 : : /* Start computation of P byte sequence. */
195 : 5 : HASH_Begin(alt_ctx);
196 : :
197 : : /* For every character in the password add the entire password. */
198 [ + + ]: 50 : for (cnt = 0; cnt < key_len; cnt++) {
199 : 45 : HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
200 : : }
201 : :
202 : : /* Finish the digest. */
203 : 5 : HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
204 : :
205 : : /* Create byte sequence P. */
206 : 5 : cp = p_bytes = alloca(key_len);
207 [ - + ]: 5 : for (cnt = key_len; cnt >= 64; cnt -= 64) {
208 : 0 : cp = mempcpy(cp, temp_result, 64);
209 : : }
210 : 5 : memcpy(cp, temp_result, cnt);
211 : :
212 : : /* Start computation of S byte sequence. */
213 : 5 : HASH_Begin(alt_ctx);
214 : :
215 : : /* For every character in the password add the entire salt. */
216 [ + + ]: 259 : for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
217 : 254 : HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
218 : : }
219 : :
220 : : /* Finish the digest. */
221 : 5 : HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
222 : :
223 : : /* Create byte sequence S. */
224 : 5 : cp = s_bytes = alloca(salt_len);
225 [ - + ]: 5 : for (cnt = salt_len; cnt >= 64; cnt -= 64) {
226 : 0 : cp = mempcpy(cp, temp_result, 64);
227 : : }
228 : 5 : memcpy(cp, temp_result, cnt);
229 : :
230 : : /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
231 [ + + ]: 25005 : for (cnt = 0; cnt < rounds; cnt++) {
232 : :
233 : 25000 : HASH_Begin(ctx);
234 : :
235 : : /* Add key or last result. */
236 [ + + ]: 25000 : if ((cnt & 1) != 0) {
237 : 12500 : HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
238 : : } else {
239 : 12500 : HASH_Update(ctx, alt_result, 64);
240 : : }
241 : :
242 : : /* Add salt for numbers not divisible by 3. */
243 [ + + ]: 25000 : if (cnt % 3 != 0) {
244 : 16665 : HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len);
245 : : }
246 : :
247 : : /* Add key for numbers not divisible by 7. */
248 [ + + ]: 25000 : if (cnt % 7 != 0) {
249 : 21425 : HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
250 : : }
251 : :
252 : : /* Add key or last result. */
253 [ + + ]: 25000 : if ((cnt & 1) != 0) {
254 : 12500 : HASH_Update(ctx, alt_result, 64);
255 : : } else {
256 : 12500 : HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
257 : : }
258 : :
259 : : /* Create intermediate result. */
260 : 25000 : HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
261 : : }
262 : :
263 : : /* Now we can construct the result string.
264 : : * It consists of three parts. */
265 [ + - ]: 5 : if (buflen <= SALT_PREF_SIZE) {
266 : : ret = ERANGE;
267 : : goto done;
268 : : }
269 : :
270 : 5 : cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
271 : 5 : buflen -= SALT_PREF_SIZE;
272 : :
273 [ - + ]: 5 : if (rounds_custom) {
274 : 0 : n = snprintf(cp, buflen, "%s%zu$",
275 : : sha512_rounds_prefix, rounds);
276 [ # # ][ # # ]: 0 : if (n < 0 || n >= buflen) {
277 : : ret = ERANGE;
278 : : goto done;
279 : : }
280 : 0 : cp += n;
281 : 0 : buflen -= n;
282 : : }
283 : :
284 [ + - ]: 5 : if (buflen <= salt_len + 1) {
285 : : ret = ERANGE;
286 : : goto done;
287 : : }
288 : 5 : cp = __stpncpy(cp, salt, salt_len);
289 : 5 : *cp++ = '$';
290 : 5 : buflen -= salt_len + 1;
291 : :
292 : : /* fuzzyfill the base 64 string */
293 : 5 : p1 = 0;
294 : 5 : p2 = 21;
295 : 5 : p3 = 42;
296 [ + + ]: 110 : for (n = 0; n < 21; n++) {
297 : 105 : b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
298 [ + - ]: 105 : if (buflen == 0) {
299 : : ret = ERANGE;
300 : : goto done;
301 : : }
302 : 105 : pt = p1;
303 : 105 : p1 = p2 + 1;
304 : 105 : p2 = p3 + 1;
305 : 105 : p3 = pt + 1;
306 : : }
307 : : /* 64th and last byte */
308 : 5 : b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
309 [ + - ]: 5 : if (buflen == 0) {
310 : : ret = ERANGE;
311 : : goto done;
312 : : }
313 : :
314 : 5 : *cp = '\0';
315 : 5 : ret = EOK;
316 : :
317 : : done:
318 : : /* Clear the buffer for the intermediate result so that people attaching
319 : : * to processes or reading core dumps cannot get any information. We do it
320 : : * in this way to clear correct_words[] inside the SHA512 implementation
321 : : * as well. */
322 [ + - ]: 5 : if (ctx) HASH_Destroy(ctx);
323 [ + - ]: 5 : if (alt_ctx) HASH_Destroy(alt_ctx);
324 [ + - ]: 5 : if (p_bytes) memset(p_bytes, '\0', key_len);
325 [ + - ]: 5 : if (s_bytes) memset(s_bytes, '\0', salt_len);
326 [ - + ]: 5 : if (copied_key) memset(copied_key, '\0', key_len);
327 [ + + ]: 5 : if (copied_salt) memset(copied_salt, '\0', salt_len);
328 : 5 : memset(temp_result, '\0', sizeof(temp_result));
329 : :
330 : 5 : return ret;
331 : : }
332 : :
333 : 5 : int s3crypt_sha512(TALLOC_CTX *memctx,
334 : : const char *key, const char *salt, char **_hash)
335 : : {
336 : : char *hash;
337 : 5 : int hlen = (sizeof (sha512_salt_prefix) - 1
338 : : + sizeof (sha512_rounds_prefix) + 9 + 1
339 : 5 : + strlen (salt) + 1 + 86 + 1);
340 : : int ret;
341 : :
342 : 5 : hash = talloc_size(memctx, hlen);
343 [ + - ]: 5 : if (!hash) return ENOMEM;
344 : :
345 : 5 : ret = sha512_crypt_r(key, salt, hash, hlen);
346 [ + - ]: 5 : if (ret) return ret;
347 : :
348 : 5 : *_hash = hash;
349 : 5 : return ret;
350 : : }
351 : :
352 : : #define SALT_RAND_LEN 12
353 : :
354 : 1 : int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt)
355 : : {
356 : : uint8_t rb[SALT_RAND_LEN];
357 : : char *salt, *cp;
358 : : size_t slen;
359 : : int ret;
360 : :
361 : 1 : ret = nspr_nss_init();
362 [ + - ]: 1 : if (ret != EOK) {
363 : : return EIO;
364 : : }
365 : :
366 : 1 : salt = talloc_size(memctx, SALT_LEN_MAX + 1);
367 [ + - ]: 1 : if (!salt) {
368 : : return ENOMEM;
369 : : }
370 : :
371 : 1 : ret = PK11_GenerateRandom(rb, SALT_RAND_LEN);
372 [ + - ]: 1 : if (ret != SECSuccess) {
373 : : return EIO;
374 : : }
375 : :
376 : 1 : slen = SALT_LEN_MAX;
377 : 1 : cp = salt;
378 : 1 : b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
379 : 1 : b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
380 : 1 : b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]);
381 : 1 : b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]);
382 : 1 : *cp = '\0';
383 : :
384 : 1 : *_salt = salt;
385 : :
386 : : return EOK;
387 : : }
|