2 * public domain sha512 crypt implementation
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.
11 #include <nel/misc/types_nl.h>
18 /* public domain sha512 implementation based on fips180-3 */
19 /* >=2^64 bits messages are not supported (about 2000 peta bytes) */
22 uint64 len
; /* processed message length */
23 uint64 h
[8]; /* hash state */
24 uint8 buf
[128]; /* message block buffer */
27 static uint64
ror(uint64 n
, int k
) { return (n
>> k
) | (n
<< (64-k
)); }
28 #define Ch(x,y,z) (z ^ (x & (y ^ z)))
29 #define Maj(x,y,z) ((x & y) | (z & (x | y)))
30 #define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39))
31 #define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41))
32 #define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7))
33 #define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6))
35 static const uint64 K
[80] = {
36 0x428a2f98d728ae22ULL
, 0x7137449123ef65cdULL
, 0xb5c0fbcfec4d3b2fULL
, 0xe9b5dba58189dbbcULL
,
37 0x3956c25bf348b538ULL
, 0x59f111f1b605d019ULL
, 0x923f82a4af194f9bULL
, 0xab1c5ed5da6d8118ULL
,
38 0xd807aa98a3030242ULL
, 0x12835b0145706fbeULL
, 0x243185be4ee4b28cULL
, 0x550c7dc3d5ffb4e2ULL
,
39 0x72be5d74f27b896fULL
, 0x80deb1fe3b1696b1ULL
, 0x9bdc06a725c71235ULL
, 0xc19bf174cf692694ULL
,
40 0xe49b69c19ef14ad2ULL
, 0xefbe4786384f25e3ULL
, 0x0fc19dc68b8cd5b5ULL
, 0x240ca1cc77ac9c65ULL
,
41 0x2de92c6f592b0275ULL
, 0x4a7484aa6ea6e483ULL
, 0x5cb0a9dcbd41fbd4ULL
, 0x76f988da831153b5ULL
,
42 0x983e5152ee66dfabULL
, 0xa831c66d2db43210ULL
, 0xb00327c898fb213fULL
, 0xbf597fc7beef0ee4ULL
,
43 0xc6e00bf33da88fc2ULL
, 0xd5a79147930aa725ULL
, 0x06ca6351e003826fULL
, 0x142929670a0e6e70ULL
,
44 0x27b70a8546d22ffcULL
, 0x2e1b21385c26c926ULL
, 0x4d2c6dfc5ac42aedULL
, 0x53380d139d95b3dfULL
,
45 0x650a73548baf63deULL
, 0x766a0abb3c77b2a8ULL
, 0x81c2c92e47edaee6ULL
, 0x92722c851482353bULL
,
46 0xa2bfe8a14cf10364ULL
, 0xa81a664bbc423001ULL
, 0xc24b8b70d0f89791ULL
, 0xc76c51a30654be30ULL
,
47 0xd192e819d6ef5218ULL
, 0xd69906245565a910ULL
, 0xf40e35855771202aULL
, 0x106aa07032bbd1b8ULL
,
48 0x19a4c116b8d2d0c8ULL
, 0x1e376c085141ab53ULL
, 0x2748774cdf8eeb99ULL
, 0x34b0bcb5e19b48a8ULL
,
49 0x391c0cb3c5c95a63ULL
, 0x4ed8aa4ae3418acbULL
, 0x5b9cca4f7763e373ULL
, 0x682e6ff3d6b2b8a3ULL
,
50 0x748f82ee5defb2fcULL
, 0x78a5636f43172f60ULL
, 0x84c87814a1f0ab72ULL
, 0x8cc702081a6439ecULL
,
51 0x90befffa23631e28ULL
, 0xa4506cebde82bde9ULL
, 0xbef9a3f7b2c67915ULL
, 0xc67178f2e372532bULL
,
52 0xca273eceea26619cULL
, 0xd186b8c721c0c207ULL
, 0xeada7dd6cde0eb1eULL
, 0xf57d4f7fee6ed178ULL
,
53 0x06f067aa72176fbaULL
, 0x0a637dc5a2c898a6ULL
, 0x113f9804bef90daeULL
, 0x1b710b35131c471bULL
,
54 0x28db77f523047d84ULL
, 0x32caab7b40c72493ULL
, 0x3c9ebe0a15c9bebcULL
, 0x431d67c49c100d4cULL
,
55 0x4cc5d4becb3e42b6ULL
, 0x597f299cfc657e2aULL
, 0x5fcb6fab3ad6faecULL
, 0x6c44198c4a475817ULL
58 static void processblock(struct sha512
*s
, const uint8
*buf
)
60 uint64 W
[80], t1
, t2
, a
, b
, c
, d
, e
, f
, g
, h
;
63 for (i
= 0; i
< 16; i
++) {
64 W
[i
] = (uint64
)buf
[8*i
]<<56;
65 W
[i
] |= (uint64
)buf
[8*i
+1]<<48;
66 W
[i
] |= (uint64
)buf
[8*i
+2]<<40;
67 W
[i
] |= (uint64
)buf
[8*i
+3]<<32;
68 W
[i
] |= (uint64
)buf
[8*i
+4]<<24;
69 W
[i
] |= (uint64
)buf
[8*i
+5]<<16;
70 W
[i
] |= (uint64
)buf
[8*i
+6]<<8;
74 W
[i
] = R1(W
[i
-2]) + W
[i
-7] + R0(W
[i
-15]) + W
[i
-16];
83 for (i
= 0; i
< 80; i
++) {
84 t1
= h
+ S1(e
) + Ch(e
,f
,g
) + K
[i
] + W
[i
];
85 t2
= S0(a
) + Maj(a
,b
,c
);
105 static void pad(struct sha512
*s
)
107 unsigned r
= s
->len
% 128;
111 memset(s
->buf
+ r
, 0, 128 - r
);
113 processblock(s
, s
->buf
);
115 memset(s
->buf
+ r
, 0, 120 - r
);
117 s
->buf
[120] = s
->len
>> 56;
118 s
->buf
[121] = s
->len
>> 48;
119 s
->buf
[122] = s
->len
>> 40;
120 s
->buf
[123] = s
->len
>> 32;
121 s
->buf
[124] = s
->len
>> 24;
122 s
->buf
[125] = s
->len
>> 16;
123 s
->buf
[126] = s
->len
>> 8;
124 s
->buf
[127] = s
->len
;
125 processblock(s
, s
->buf
);
128 static void sha512_init(struct sha512
*s
)
131 s
->h
[0] = 0x6a09e667f3bcc908ULL
;
132 s
->h
[1] = 0xbb67ae8584caa73bULL
;
133 s
->h
[2] = 0x3c6ef372fe94f82bULL
;
134 s
->h
[3] = 0xa54ff53a5f1d36f1ULL
;
135 s
->h
[4] = 0x510e527fade682d1ULL
;
136 s
->h
[5] = 0x9b05688c2b3e6c1fULL
;
137 s
->h
[6] = 0x1f83d9abfb41bd6bULL
;
138 s
->h
[7] = 0x5be0cd19137e2179ULL
;
141 static void sha512_sum(struct sha512
*s
, uint8
*md
)
146 for (i
= 0; i
< 8; i
++) {
147 md
[8*i
] = s
->h
[i
] >> 56;
148 md
[8*i
+1] = s
->h
[i
] >> 48;
149 md
[8*i
+2] = s
->h
[i
] >> 40;
150 md
[8*i
+3] = s
->h
[i
] >> 32;
151 md
[8*i
+4] = s
->h
[i
] >> 24;
152 md
[8*i
+5] = s
->h
[i
] >> 16;
153 md
[8*i
+6] = s
->h
[i
] >> 8;
158 static void sha512_update(struct sha512
*s
, const void *m
, unsigned long len
)
160 const uint8
*p
= (uint8
*)m
;
161 unsigned r
= s
->len
% 128;
166 memcpy(s
->buf
+ r
, p
, len
);
169 memcpy(s
->buf
+ r
, p
, 128 - r
);
172 processblock(s
, s
->buf
);
174 for (; len
>= 128; len
-= 128, p
+= 128)
176 memcpy(s
->buf
, p
, len
);
179 static const unsigned char b64
[] =
180 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
182 static char *to64(char *s
, unsigned int u
, int n
)
191 /* key limit is not part of the original design, added for DoS protection.
192 * rounds limit has been lowered (versus the reference/spec), also for DoS
193 * protection. runtime is O(klen^2 + klen*rounds) */
196 #define ROUNDS_DEFAULT 5000
197 #define ROUNDS_MIN 1000
198 #define ROUNDS_MAX 9999999
200 /* hash n bytes of the repeated md message digest */
201 static void hashmd(struct sha512
*s
, unsigned int n
, const void *md
)
205 for (i
= n
; i
> 64; i
-= 64)
206 sha512_update(s
, md
, 64);
207 sha512_update(s
, md
, i
);
210 static char *sha512crypt(const char *key
, const char *setting
, char *output
)
213 unsigned char md
[64], kmd
[64], smd
[64];
214 unsigned int i
, r
, klen
, slen
;
215 char rounds
[20] = "";
219 /* reject large keys */
220 for (i
= 0; i
<= KEY_MAX
&& key
[i
]; i
++);
225 /* setting: $6$rounds=n$salt$ (rounds=n$ and closing $ are optional) */
226 if (strncmp(setting
, "$6$", 3) != 0)
231 if (strncmp(salt
, "rounds=", sizeof "rounds=" - 1) == 0) {
236 * this is a deviation from the reference:
237 * bad rounds setting is rejected if it is
239 * - unterminated (missing '$')
240 * - begins with anything but a decimal digit
241 * the reference implementation treats these bad
242 * rounds as part of the salt or parse them with
243 * strtoul semantics which may cause problems
244 * including non-portable hashes that depend on
245 * the host's value of ULONG_MAX.
247 salt
+= sizeof "rounds=" - 1;
250 u
= strtoul(salt
, &end
, 10);
256 else if (u
> ROUNDS_MAX
)
260 /* needed when rounds is zero prefixed or out of bounds */
261 sprintf(rounds
, "rounds=%u$", r
);
264 for (i
= 0; i
< SALT_MAX
&& salt
[i
] && salt
[i
] != '$'; i
++)
265 /* reject characters that interfere with /etc/shadow parsing */
266 if (salt
[i
] == '\n' || salt
[i
] == ':')
270 /* B = sha(key salt key) */
272 sha512_update(&ctx
, key
, klen
);
273 sha512_update(&ctx
, salt
, slen
);
274 sha512_update(&ctx
, key
, klen
);
275 sha512_sum(&ctx
, md
);
277 /* A = sha(key salt repeat-B alternate-B-key) */
279 sha512_update(&ctx
, key
, klen
);
280 sha512_update(&ctx
, salt
, slen
);
281 hashmd(&ctx
, klen
, md
);
282 for (i
= klen
; i
> 0; i
>>= 1)
284 sha512_update(&ctx
, md
, sizeof md
);
286 sha512_update(&ctx
, key
, klen
);
287 sha512_sum(&ctx
, md
);
289 /* DP = sha(repeat-key), this step takes O(klen^2) time */
291 for (i
= 0; i
< klen
; i
++)
292 sha512_update(&ctx
, key
, klen
);
293 sha512_sum(&ctx
, kmd
);
295 /* DS = sha(repeat-salt) */
297 for (i
= 0; i
< 16u + md
[0]; i
++)
298 sha512_update(&ctx
, salt
, slen
);
299 sha512_sum(&ctx
, smd
);
301 /* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */
302 for (i
= 0; i
< r
; i
++) {
305 hashmd(&ctx
, klen
, kmd
);
307 sha512_update(&ctx
, md
, sizeof md
);
309 sha512_update(&ctx
, smd
, slen
);
311 hashmd(&ctx
, klen
, kmd
);
313 sha512_update(&ctx
, md
, sizeof md
);
315 hashmd(&ctx
, klen
, kmd
);
316 sha512_sum(&ctx
, md
);
319 /* output is $6$rounds=n$salt$hash */
321 p
+= sprintf(p
, "$6$%s%.*s$", rounds
, slen
, salt
);
323 static const unsigned char perm
[][3] = {
346 for (i
=0; i
<21; i
++) p
= to64(p
,
347 (md
[perm
[i
][0]]<<16)|(md
[perm
[i
][1]]<<8)|md
[perm
[i
][2]], 4);
349 p
= to64(p
, (md
[0]<<16)|(md
[21]<<8)|md
[42], 4);
350 p
= to64(p
, (md
[22]<<16)|(md
[43]<<8)|md
[1], 4);
351 p
= to64(p
, (md
[44]<<16)|(md
[2]<<8)|md
[23], 4);
352 p
= to64(p
, (md
[3]<<16)|(md
[24]<<8)|md
[45], 4);
353 p
= to64(p
, (md
[25]<<16)|(md
[46]<<8)|md
[4], 4);
354 p
= to64(p
, (md
[47]<<16)|(md
[5]<<8)|md
[26], 4);
355 p
= to64(p
, (md
[6]<<16)|(md
[27]<<8)|md
[48], 4);
356 p
= to64(p
, (md
[28]<<16)|(md
[49]<<8)|md
[7], 4);
357 p
= to64(p
, (md
[50]<<16)|(md
[8]<<8)|md
[29], 4);
358 p
= to64(p
, (md
[9]<<16)|(md
[30]<<8)|md
[51], 4);
359 p
= to64(p
, (md
[31]<<16)|(md
[52]<<8)|md
[10], 4);
360 p
= to64(p
, (md
[53]<<16)|(md
[11]<<8)|md
[32], 4);
361 p
= to64(p
, (md
[12]<<16)|(md
[33]<<8)|md
[54], 4);
362 p
= to64(p
, (md
[34]<<16)|(md
[55]<<8)|md
[13], 4);
363 p
= to64(p
, (md
[56]<<16)|(md
[14]<<8)|md
[35], 4);
364 p
= to64(p
, (md
[15]<<16)|(md
[36]<<8)|md
[57], 4);
365 p
= to64(p
, (md
[37]<<16)|(md
[58]<<8)|md
[16], 4);
366 p
= to64(p
, (md
[59]<<16)|(md
[17]<<8)|md
[38], 4);
367 p
= to64(p
, (md
[18]<<16)|(md
[39]<<8)|md
[60], 4);
368 p
= to64(p
, (md
[40]<<16)|(md
[61]<<8)|md
[19], 4);
369 p
= to64(p
, (md
[62]<<16)|(md
[20]<<8)|md
[41], 4);
371 p
= to64(p
, md
[63], 2);
376 std::string
__crypt_sha512(const char *key
, const char *setting
, char *output
)
378 static const char testkey
[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
379 static const char testsetting
[] = "$6$rounds=1234$abc0123456789$";
380 static const char testhash
[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
384 p
= sha512crypt(key
, setting
, output
);
386 /* self test and stack cleanup */
387 q
= sha512crypt(testkey
, testsetting
, testbuf
);
388 if (!p
|| q
!= testbuf
|| memcmp(testbuf
, testhash
, sizeof(testhash
)))