Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: fusl/src/crypt/crypt_sha512.c

Issue 1573973002: Add a "fork" of musl as //fusl. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « fusl/src/crypt/crypt_sha256.c ('k') | fusl/src/crypt/encrypt.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * public domain sha512 crypt implementation
3 *
4 * original sha crypt design: http://people.redhat.com/drepper/SHA-crypt.txt
5 * in this implementation at least 32bit int is assumed,
6 * key length is limited, the $6$ prefix is mandatory, '\n' and ':' is rejected
7 * in the salt and rounds= setting must contain a valid iteration count,
8 * on error "*" is returned.
9 */
10 #include <ctype.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdint.h>
15
16 /* public domain sha512 implementation based on fips180-3 */
17 /* >=2^64 bits messages are not supported (about 2000 peta bytes) */
18
19 struct sha512 {
20 uint64_t len; /* processed message length */
21 uint64_t h[8]; /* hash state */
22 uint8_t buf[128]; /* message block buffer */
23 };
24
25 static uint64_t ror(uint64_t n, int k) { return (n >> k) | (n << (64-k)); }
26 #define Ch(x,y,z) (z ^ (x & (y ^ z)))
27 #define Maj(x,y,z) ((x & y) | (z & (x | y)))
28 #define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39))
29 #define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41))
30 #define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7))
31 #define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6))
32
33 static const uint64_t K[80] = {
34 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58 189dbbcULL,
35 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5d a6d8118ULL,
36 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d 5ffb4e2ULL,
37 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174c f692694ULL,
38 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc7 7ac9c65ULL,
39 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da8 31153b5ULL,
40 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7b eef0ee4ULL,
41 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670 a0e6e70ULL,
42 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139 d95b3dfULL,
43 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851 482353bULL,
44 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30 654be30ULL,
45 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa0703 2bbd1b8ULL,
46 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e 19b48a8ULL,
47 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d 6b2b8a3ULL,
48 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081 a6439ecULL,
49 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e 372532bULL,
50 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fe e6ed178ULL,
51 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b351 31c471bULL,
52 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49 c100d4cULL,
53 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4 a475817ULL
54 };
55
56 static void processblock(struct sha512 *s, const uint8_t *buf)
57 {
58 uint64_t W[80], t1, t2, a, b, c, d, e, f, g, h;
59 int i;
60
61 for (i = 0; i < 16; i++) {
62 W[i] = (uint64_t)buf[8*i]<<56;
63 W[i] |= (uint64_t)buf[8*i+1]<<48;
64 W[i] |= (uint64_t)buf[8*i+2]<<40;
65 W[i] |= (uint64_t)buf[8*i+3]<<32;
66 W[i] |= (uint64_t)buf[8*i+4]<<24;
67 W[i] |= (uint64_t)buf[8*i+5]<<16;
68 W[i] |= (uint64_t)buf[8*i+6]<<8;
69 W[i] |= buf[8*i+7];
70 }
71 for (; i < 80; i++)
72 W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
73 a = s->h[0];
74 b = s->h[1];
75 c = s->h[2];
76 d = s->h[3];
77 e = s->h[4];
78 f = s->h[5];
79 g = s->h[6];
80 h = s->h[7];
81 for (i = 0; i < 80; i++) {
82 t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
83 t2 = S0(a) + Maj(a,b,c);
84 h = g;
85 g = f;
86 f = e;
87 e = d + t1;
88 d = c;
89 c = b;
90 b = a;
91 a = t1 + t2;
92 }
93 s->h[0] += a;
94 s->h[1] += b;
95 s->h[2] += c;
96 s->h[3] += d;
97 s->h[4] += e;
98 s->h[5] += f;
99 s->h[6] += g;
100 s->h[7] += h;
101 }
102
103 static void pad(struct sha512 *s)
104 {
105 unsigned r = s->len % 128;
106
107 s->buf[r++] = 0x80;
108 if (r > 112) {
109 memset(s->buf + r, 0, 128 - r);
110 r = 0;
111 processblock(s, s->buf);
112 }
113 memset(s->buf + r, 0, 120 - r);
114 s->len *= 8;
115 s->buf[120] = s->len >> 56;
116 s->buf[121] = s->len >> 48;
117 s->buf[122] = s->len >> 40;
118 s->buf[123] = s->len >> 32;
119 s->buf[124] = s->len >> 24;
120 s->buf[125] = s->len >> 16;
121 s->buf[126] = s->len >> 8;
122 s->buf[127] = s->len;
123 processblock(s, s->buf);
124 }
125
126 static void sha512_init(struct sha512 *s)
127 {
128 s->len = 0;
129 s->h[0] = 0x6a09e667f3bcc908ULL;
130 s->h[1] = 0xbb67ae8584caa73bULL;
131 s->h[2] = 0x3c6ef372fe94f82bULL;
132 s->h[3] = 0xa54ff53a5f1d36f1ULL;
133 s->h[4] = 0x510e527fade682d1ULL;
134 s->h[5] = 0x9b05688c2b3e6c1fULL;
135 s->h[6] = 0x1f83d9abfb41bd6bULL;
136 s->h[7] = 0x5be0cd19137e2179ULL;
137 }
138
139 static void sha512_sum(struct sha512 *s, uint8_t *md)
140 {
141 int i;
142
143 pad(s);
144 for (i = 0; i < 8; i++) {
145 md[8*i] = s->h[i] >> 56;
146 md[8*i+1] = s->h[i] >> 48;
147 md[8*i+2] = s->h[i] >> 40;
148 md[8*i+3] = s->h[i] >> 32;
149 md[8*i+4] = s->h[i] >> 24;
150 md[8*i+5] = s->h[i] >> 16;
151 md[8*i+6] = s->h[i] >> 8;
152 md[8*i+7] = s->h[i];
153 }
154 }
155
156 static void sha512_update(struct sha512 *s, const void *m, unsigned long len)
157 {
158 const uint8_t *p = m;
159 unsigned r = s->len % 128;
160
161 s->len += len;
162 if (r) {
163 if (len < 128 - r) {
164 memcpy(s->buf + r, p, len);
165 return;
166 }
167 memcpy(s->buf + r, p, 128 - r);
168 len -= 128 - r;
169 p += 128 - r;
170 processblock(s, s->buf);
171 }
172 for (; len >= 128; len -= 128, p += 128)
173 processblock(s, p);
174 memcpy(s->buf, p, len);
175 }
176
177 static const unsigned char b64[] =
178 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
179
180 static char *to64(char *s, unsigned int u, int n)
181 {
182 while (--n >= 0) {
183 *s++ = b64[u % 64];
184 u /= 64;
185 }
186 return s;
187 }
188
189 /* key limit is not part of the original design, added for DoS protection.
190 * rounds limit has been lowered (versus the reference/spec), also for DoS
191 * protection. runtime is O(klen^2 + klen*rounds) */
192 #define KEY_MAX 256
193 #define SALT_MAX 16
194 #define ROUNDS_DEFAULT 5000
195 #define ROUNDS_MIN 1000
196 #define ROUNDS_MAX 9999999
197
198 /* hash n bytes of the repeated md message digest */
199 static void hashmd(struct sha512 *s, unsigned int n, const void *md)
200 {
201 unsigned int i;
202
203 for (i = n; i > 64; i -= 64)
204 sha512_update(s, md, 64);
205 sha512_update(s, md, i);
206 }
207
208 static char *sha512crypt(const char *key, const char *setting, char *output)
209 {
210 struct sha512 ctx;
211 unsigned char md[64], kmd[64], smd[64];
212 unsigned int i, r, klen, slen;
213 char rounds[20] = "";
214 const char *salt;
215 char *p;
216
217 /* reject large keys */
218 for (i = 0; i <= KEY_MAX && key[i]; i++);
219 if (i > KEY_MAX)
220 return 0;
221 klen = i;
222
223 /* setting: $6$rounds=n$salt$ (rounds=n$ and closing $ are optional) */
224 if (strncmp(setting, "$6$", 3) != 0)
225 return 0;
226 salt = setting + 3;
227
228 r = ROUNDS_DEFAULT;
229 if (strncmp(salt, "rounds=", sizeof "rounds=" - 1) == 0) {
230 unsigned long u;
231 char *end;
232
233 /*
234 * this is a deviation from the reference:
235 * bad rounds setting is rejected if it is
236 * - empty
237 * - unterminated (missing '$')
238 * - begins with anything but a decimal digit
239 * the reference implementation treats these bad
240 * rounds as part of the salt or parse them with
241 * strtoul semantics which may cause problems
242 * including non-portable hashes that depend on
243 * the host's value of ULONG_MAX.
244 */
245 salt += sizeof "rounds=" - 1;
246 if (!isdigit(*salt))
247 return 0;
248 u = strtoul(salt, &end, 10);
249 if (*end != '$')
250 return 0;
251 salt = end+1;
252 if (u < ROUNDS_MIN)
253 r = ROUNDS_MIN;
254 else if (u > ROUNDS_MAX)
255 r = ROUNDS_MAX;
256 else
257 r = u;
258 /* needed when rounds is zero prefixed or out of bounds */
259 sprintf(rounds, "rounds=%u$", r);
260 }
261
262 for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++)
263 /* reject characters that interfere with /etc/shadow parsing */
264 if (salt[i] == '\n' || salt[i] == ':')
265 return 0;
266 slen = i;
267
268 /* B = sha(key salt key) */
269 sha512_init(&ctx);
270 sha512_update(&ctx, key, klen);
271 sha512_update(&ctx, salt, slen);
272 sha512_update(&ctx, key, klen);
273 sha512_sum(&ctx, md);
274
275 /* A = sha(key salt repeat-B alternate-B-key) */
276 sha512_init(&ctx);
277 sha512_update(&ctx, key, klen);
278 sha512_update(&ctx, salt, slen);
279 hashmd(&ctx, klen, md);
280 for (i = klen; i > 0; i >>= 1)
281 if (i & 1)
282 sha512_update(&ctx, md, sizeof md);
283 else
284 sha512_update(&ctx, key, klen);
285 sha512_sum(&ctx, md);
286
287 /* DP = sha(repeat-key), this step takes O(klen^2) time */
288 sha512_init(&ctx);
289 for (i = 0; i < klen; i++)
290 sha512_update(&ctx, key, klen);
291 sha512_sum(&ctx, kmd);
292
293 /* DS = sha(repeat-salt) */
294 sha512_init(&ctx);
295 for (i = 0; i < 16 + md[0]; i++)
296 sha512_update(&ctx, salt, slen);
297 sha512_sum(&ctx, smd);
298
299 /* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */
300 for (i = 0; i < r; i++) {
301 sha512_init(&ctx);
302 if (i % 2)
303 hashmd(&ctx, klen, kmd);
304 else
305 sha512_update(&ctx, md, sizeof md);
306 if (i % 3)
307 sha512_update(&ctx, smd, slen);
308 if (i % 7)
309 hashmd(&ctx, klen, kmd);
310 if (i % 2)
311 sha512_update(&ctx, md, sizeof md);
312 else
313 hashmd(&ctx, klen, kmd);
314 sha512_sum(&ctx, md);
315 }
316
317 /* output is $6$rounds=n$salt$hash */
318 p = output;
319 p += sprintf(p, "$6$%s%.*s$", rounds, slen, salt);
320 #if 1
321 static const unsigned char perm[][3] = {
322 0,21,42,22,43,1,44,2,23,3,24,45,25,46,4,
323 47,5,26,6,27,48,28,49,7,50,8,29,9,30,51,
324 31,52,10,53,11,32,12,33,54,34,55,13,56,14,35,
325 15,36,57,37,58,16,59,17,38,18,39,60,40,61,19,
326 62,20,41 };
327 for (i=0; i<21; i++) p = to64(p,
328 (md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4);
329 #else
330 p = to64(p, (md[0]<<16)|(md[21]<<8)|md[42], 4);
331 p = to64(p, (md[22]<<16)|(md[43]<<8)|md[1], 4);
332 p = to64(p, (md[44]<<16)|(md[2]<<8)|md[23], 4);
333 p = to64(p, (md[3]<<16)|(md[24]<<8)|md[45], 4);
334 p = to64(p, (md[25]<<16)|(md[46]<<8)|md[4], 4);
335 p = to64(p, (md[47]<<16)|(md[5]<<8)|md[26], 4);
336 p = to64(p, (md[6]<<16)|(md[27]<<8)|md[48], 4);
337 p = to64(p, (md[28]<<16)|(md[49]<<8)|md[7], 4);
338 p = to64(p, (md[50]<<16)|(md[8]<<8)|md[29], 4);
339 p = to64(p, (md[9]<<16)|(md[30]<<8)|md[51], 4);
340 p = to64(p, (md[31]<<16)|(md[52]<<8)|md[10], 4);
341 p = to64(p, (md[53]<<16)|(md[11]<<8)|md[32], 4);
342 p = to64(p, (md[12]<<16)|(md[33]<<8)|md[54], 4);
343 p = to64(p, (md[34]<<16)|(md[55]<<8)|md[13], 4);
344 p = to64(p, (md[56]<<16)|(md[14]<<8)|md[35], 4);
345 p = to64(p, (md[15]<<16)|(md[36]<<8)|md[57], 4);
346 p = to64(p, (md[37]<<16)|(md[58]<<8)|md[16], 4);
347 p = to64(p, (md[59]<<16)|(md[17]<<8)|md[38], 4);
348 p = to64(p, (md[18]<<16)|(md[39]<<8)|md[60], 4);
349 p = to64(p, (md[40]<<16)|(md[61]<<8)|md[19], 4);
350 p = to64(p, (md[62]<<16)|(md[20]<<8)|md[41], 4);
351 #endif
352 p = to64(p, md[63], 2);
353 *p = 0;
354 return output;
355 }
356
357 char *__crypt_sha512(const char *key, const char *setting, char *output)
358 {
359 static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
360 static const char testsetting[] = "$6$rounds=1234$abc0123456789$";
361 static const char testhash[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/R cyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
362 char testbuf[128];
363 char *p, *q;
364
365 p = sha512crypt(key, setting, output);
366 /* self test and stack cleanup */
367 q = sha512crypt(testkey, testsetting, testbuf);
368 if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
369 return "*";
370 return p;
371 }
OLDNEW
« no previous file with comments | « fusl/src/crypt/crypt_sha256.c ('k') | fusl/src/crypt/encrypt.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698