xref: /dflybsd-src/lib/libcrypt/crypt-sha512.c (revision e0369600668aca82fea4c3901659ea23bc610fc0)
16737f3b9SNolan Lum /*
2d8ee3b5dSSamuel J. Greear  * SHA512-based Unix crypt implementation.
3d8ee3b5dSSamuel J. Greear  * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
46737f3b9SNolan Lum  */
5d8ee3b5dSSamuel J. Greear #include <errno.h>
6d8ee3b5dSSamuel J. Greear #include <limits.h>
7d8ee3b5dSSamuel J. Greear #include <stdbool.h>
8d8ee3b5dSSamuel J. Greear #include <stdint.h>
9d8ee3b5dSSamuel J. Greear #include <stdio.h>
10d8ee3b5dSSamuel J. Greear #include <stdlib.h>
116737f3b9SNolan Lum #include <string.h>
12d8ee3b5dSSamuel J. Greear #include <sys/endian.h>
13d8ee3b5dSSamuel J. Greear #include <sys/param.h>
14d8ee3b5dSSamuel J. Greear #include <sys/types.h>
156737f3b9SNolan Lum 
16*e0369600Szrj #include "crypt.h"
170fe46dc6SMatthew Dillon #include "local.h"
186737f3b9SNolan Lum 
194c7c7880SSascha Wildner #if _BYTE_ORDER == _LITTLE_ENDIAN
20d8ee3b5dSSamuel J. Greear # define SWAP(n) \
21d8ee3b5dSSamuel J. Greear   (((n) << 56)					\
22d8ee3b5dSSamuel J. Greear    | (((n) & 0xff00) << 40)			\
23d8ee3b5dSSamuel J. Greear    | (((n) & 0xff0000) << 24)			\
24d8ee3b5dSSamuel J. Greear    | (((n) & 0xff000000) << 8)			\
25d8ee3b5dSSamuel J. Greear    | (((n) >> 8) & 0xff000000)			\
26d8ee3b5dSSamuel J. Greear    | (((n) >> 24) & 0xff0000)			\
27d8ee3b5dSSamuel J. Greear    | (((n) >> 40) & 0xff00)			\
28d8ee3b5dSSamuel J. Greear    | ((n) >> 56))
29d8ee3b5dSSamuel J. Greear #else
30d8ee3b5dSSamuel J. Greear # define SWAP(n) (n)
31d8ee3b5dSSamuel J. Greear #endif
326737f3b9SNolan Lum 
336737f3b9SNolan Lum 
34d8ee3b5dSSamuel J. Greear /* This array contains the bytes used to pad the buffer to the next
35d8ee3b5dSSamuel J. Greear    64-byte boundary.  (FIPS 180-2:5.1.2)  */
36d8ee3b5dSSamuel J. Greear static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ...  */ };
376737f3b9SNolan Lum 
386737f3b9SNolan Lum 
39d8ee3b5dSSamuel J. Greear /* Constants for SHA512 from FIPS 180-2:4.2.3.  */
40d8ee3b5dSSamuel J. Greear static const uint64_t K[80] =
41d8ee3b5dSSamuel J. Greear   {
42d8ee3b5dSSamuel J. Greear     UINT64_C (0x428a2f98d728ae22), UINT64_C (0x7137449123ef65cd),
43d8ee3b5dSSamuel J. Greear     UINT64_C (0xb5c0fbcfec4d3b2f), UINT64_C (0xe9b5dba58189dbbc),
44d8ee3b5dSSamuel J. Greear     UINT64_C (0x3956c25bf348b538), UINT64_C (0x59f111f1b605d019),
45d8ee3b5dSSamuel J. Greear     UINT64_C (0x923f82a4af194f9b), UINT64_C (0xab1c5ed5da6d8118),
46d8ee3b5dSSamuel J. Greear     UINT64_C (0xd807aa98a3030242), UINT64_C (0x12835b0145706fbe),
47d8ee3b5dSSamuel J. Greear     UINT64_C (0x243185be4ee4b28c), UINT64_C (0x550c7dc3d5ffb4e2),
48d8ee3b5dSSamuel J. Greear     UINT64_C (0x72be5d74f27b896f), UINT64_C (0x80deb1fe3b1696b1),
49d8ee3b5dSSamuel J. Greear     UINT64_C (0x9bdc06a725c71235), UINT64_C (0xc19bf174cf692694),
50d8ee3b5dSSamuel J. Greear     UINT64_C (0xe49b69c19ef14ad2), UINT64_C (0xefbe4786384f25e3),
51d8ee3b5dSSamuel J. Greear     UINT64_C (0x0fc19dc68b8cd5b5), UINT64_C (0x240ca1cc77ac9c65),
52d8ee3b5dSSamuel J. Greear     UINT64_C (0x2de92c6f592b0275), UINT64_C (0x4a7484aa6ea6e483),
53d8ee3b5dSSamuel J. Greear     UINT64_C (0x5cb0a9dcbd41fbd4), UINT64_C (0x76f988da831153b5),
54d8ee3b5dSSamuel J. Greear     UINT64_C (0x983e5152ee66dfab), UINT64_C (0xa831c66d2db43210),
55d8ee3b5dSSamuel J. Greear     UINT64_C (0xb00327c898fb213f), UINT64_C (0xbf597fc7beef0ee4),
56d8ee3b5dSSamuel J. Greear     UINT64_C (0xc6e00bf33da88fc2), UINT64_C (0xd5a79147930aa725),
57d8ee3b5dSSamuel J. Greear     UINT64_C (0x06ca6351e003826f), UINT64_C (0x142929670a0e6e70),
58d8ee3b5dSSamuel J. Greear     UINT64_C (0x27b70a8546d22ffc), UINT64_C (0x2e1b21385c26c926),
59d8ee3b5dSSamuel J. Greear     UINT64_C (0x4d2c6dfc5ac42aed), UINT64_C (0x53380d139d95b3df),
60d8ee3b5dSSamuel J. Greear     UINT64_C (0x650a73548baf63de), UINT64_C (0x766a0abb3c77b2a8),
61d8ee3b5dSSamuel J. Greear     UINT64_C (0x81c2c92e47edaee6), UINT64_C (0x92722c851482353b),
62d8ee3b5dSSamuel J. Greear     UINT64_C (0xa2bfe8a14cf10364), UINT64_C (0xa81a664bbc423001),
63d8ee3b5dSSamuel J. Greear     UINT64_C (0xc24b8b70d0f89791), UINT64_C (0xc76c51a30654be30),
64d8ee3b5dSSamuel J. Greear     UINT64_C (0xd192e819d6ef5218), UINT64_C (0xd69906245565a910),
65d8ee3b5dSSamuel J. Greear     UINT64_C (0xf40e35855771202a), UINT64_C (0x106aa07032bbd1b8),
66d8ee3b5dSSamuel J. Greear     UINT64_C (0x19a4c116b8d2d0c8), UINT64_C (0x1e376c085141ab53),
67d8ee3b5dSSamuel J. Greear     UINT64_C (0x2748774cdf8eeb99), UINT64_C (0x34b0bcb5e19b48a8),
68d8ee3b5dSSamuel J. Greear     UINT64_C (0x391c0cb3c5c95a63), UINT64_C (0x4ed8aa4ae3418acb),
69d8ee3b5dSSamuel J. Greear     UINT64_C (0x5b9cca4f7763e373), UINT64_C (0x682e6ff3d6b2b8a3),
70d8ee3b5dSSamuel J. Greear     UINT64_C (0x748f82ee5defb2fc), UINT64_C (0x78a5636f43172f60),
71d8ee3b5dSSamuel J. Greear     UINT64_C (0x84c87814a1f0ab72), UINT64_C (0x8cc702081a6439ec),
72d8ee3b5dSSamuel J. Greear     UINT64_C (0x90befffa23631e28), UINT64_C (0xa4506cebde82bde9),
73d8ee3b5dSSamuel J. Greear     UINT64_C (0xbef9a3f7b2c67915), UINT64_C (0xc67178f2e372532b),
74d8ee3b5dSSamuel J. Greear     UINT64_C (0xca273eceea26619c), UINT64_C (0xd186b8c721c0c207),
75d8ee3b5dSSamuel J. Greear     UINT64_C (0xeada7dd6cde0eb1e), UINT64_C (0xf57d4f7fee6ed178),
76d8ee3b5dSSamuel J. Greear     UINT64_C (0x06f067aa72176fba), UINT64_C (0x0a637dc5a2c898a6),
77d8ee3b5dSSamuel J. Greear     UINT64_C (0x113f9804bef90dae), UINT64_C (0x1b710b35131c471b),
78d8ee3b5dSSamuel J. Greear     UINT64_C (0x28db77f523047d84), UINT64_C (0x32caab7b40c72493),
79d8ee3b5dSSamuel J. Greear     UINT64_C (0x3c9ebe0a15c9bebc), UINT64_C (0x431d67c49c100d4c),
80d8ee3b5dSSamuel J. Greear     UINT64_C (0x4cc5d4becb3e42b6), UINT64_C (0x597f299cfc657e2a),
81d8ee3b5dSSamuel J. Greear     UINT64_C (0x5fcb6fab3ad6faec), UINT64_C (0x6c44198c4a475817)
82d8ee3b5dSSamuel J. Greear   };
836737f3b9SNolan Lum 
846737f3b9SNolan Lum 
85d8ee3b5dSSamuel J. Greear /* Process LEN bytes of BUFFER, accumulating context into CTX.
86d8ee3b5dSSamuel J. Greear    It is assumed that LEN % 128 == 0.  */
870fe46dc6SMatthew Dillon void
__crypt__sha512_process_block(const void * buffer,size_t len,struct sha512_ctx * ctx)880fe46dc6SMatthew Dillon __crypt__sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
89d8ee3b5dSSamuel J. Greear {
90d8ee3b5dSSamuel J. Greear   const uint64_t *words = buffer;
91d8ee3b5dSSamuel J. Greear   size_t nwords = len / sizeof (uint64_t);
92d8ee3b5dSSamuel J. Greear   uint64_t a = ctx->H[0];
93d8ee3b5dSSamuel J. Greear   uint64_t b = ctx->H[1];
94d8ee3b5dSSamuel J. Greear   uint64_t c = ctx->H[2];
95d8ee3b5dSSamuel J. Greear   uint64_t d = ctx->H[3];
96d8ee3b5dSSamuel J. Greear   uint64_t e = ctx->H[4];
97d8ee3b5dSSamuel J. Greear   uint64_t f = ctx->H[5];
98d8ee3b5dSSamuel J. Greear   uint64_t g = ctx->H[6];
99d8ee3b5dSSamuel J. Greear   uint64_t h = ctx->H[7];
1006737f3b9SNolan Lum 
101d8ee3b5dSSamuel J. Greear   /* First increment the byte count.  FIPS 180-2 specifies the possible
102d8ee3b5dSSamuel J. Greear      length of the file up to 2^128 bits.  Here we only compute the
103d8ee3b5dSSamuel J. Greear      number of bytes.  Do a double word increment.  */
104d8ee3b5dSSamuel J. Greear   ctx->total[0] += len;
105d8ee3b5dSSamuel J. Greear   if (ctx->total[0] < len)
106d8ee3b5dSSamuel J. Greear     ++ctx->total[1];
1076737f3b9SNolan Lum 
108d8ee3b5dSSamuel J. Greear   /* Process all bytes in the buffer with 128 bytes in each round of
109d8ee3b5dSSamuel J. Greear      the loop.  */
110d8ee3b5dSSamuel J. Greear   while (nwords > 0)
111d8ee3b5dSSamuel J. Greear     {
112d8ee3b5dSSamuel J. Greear       uint64_t W[80];
113d8ee3b5dSSamuel J. Greear       uint64_t a_save = a;
114d8ee3b5dSSamuel J. Greear       uint64_t b_save = b;
115d8ee3b5dSSamuel J. Greear       uint64_t c_save = c;
116d8ee3b5dSSamuel J. Greear       uint64_t d_save = d;
117d8ee3b5dSSamuel J. Greear       uint64_t e_save = e;
118d8ee3b5dSSamuel J. Greear       uint64_t f_save = f;
119d8ee3b5dSSamuel J. Greear       uint64_t g_save = g;
120d8ee3b5dSSamuel J. Greear       uint64_t h_save = h;
121d8ee3b5dSSamuel J. Greear 
122d8ee3b5dSSamuel J. Greear       /* Operators defined in FIPS 180-2:4.1.2.  */
123d8ee3b5dSSamuel J. Greear #define Ch(x, y, z) ((x & y) ^ (~x & z))
124d8ee3b5dSSamuel J. Greear #define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
125d8ee3b5dSSamuel J. Greear #define S0(x) (CYCLIC (x, 28) ^ CYCLIC (x, 34) ^ CYCLIC (x, 39))
126d8ee3b5dSSamuel J. Greear #define S1(x) (CYCLIC (x, 14) ^ CYCLIC (x, 18) ^ CYCLIC (x, 41))
127d8ee3b5dSSamuel J. Greear #define R0(x) (CYCLIC (x, 1) ^ CYCLIC (x, 8) ^ (x >> 7))
128d8ee3b5dSSamuel J. Greear #define R1(x) (CYCLIC (x, 19) ^ CYCLIC (x, 61) ^ (x >> 6))
129d8ee3b5dSSamuel J. Greear 
130d8ee3b5dSSamuel J. Greear       /* It is unfortunate that C does not provide an operator for
131d8ee3b5dSSamuel J. Greear 	 cyclic rotation.  Hope the C compiler is smart enough.  */
132d8ee3b5dSSamuel J. Greear #define CYCLIC(w, s) ((w >> s) | (w << (64 - s)))
133d8ee3b5dSSamuel J. Greear 
134d8ee3b5dSSamuel J. Greear       /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2.  */
135d8ee3b5dSSamuel J. Greear       for (unsigned int t = 0; t < 16; ++t)
136d8ee3b5dSSamuel J. Greear 	{
137d8ee3b5dSSamuel J. Greear 	  W[t] = SWAP (*words);
138d8ee3b5dSSamuel J. Greear 	  ++words;
1396737f3b9SNolan Lum 	}
140d8ee3b5dSSamuel J. Greear       for (unsigned int t = 16; t < 80; ++t)
141d8ee3b5dSSamuel J. Greear 	W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
1426737f3b9SNolan Lum 
143d8ee3b5dSSamuel J. Greear       /* The actual computation according to FIPS 180-2:6.3.2 step 3.  */
144d8ee3b5dSSamuel J. Greear       for (unsigned int t = 0; t < 80; ++t)
145d8ee3b5dSSamuel J. Greear 	{
146d8ee3b5dSSamuel J. Greear 	  uint64_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
147d8ee3b5dSSamuel J. Greear 	  uint64_t T2 = S0 (a) + Maj (a, b, c);
148d8ee3b5dSSamuel J. Greear 	  h = g;
149d8ee3b5dSSamuel J. Greear 	  g = f;
150d8ee3b5dSSamuel J. Greear 	  f = e;
151d8ee3b5dSSamuel J. Greear 	  e = d + T1;
152d8ee3b5dSSamuel J. Greear 	  d = c;
153d8ee3b5dSSamuel J. Greear 	  c = b;
154d8ee3b5dSSamuel J. Greear 	  b = a;
155d8ee3b5dSSamuel J. Greear 	  a = T1 + T2;
1566737f3b9SNolan Lum 	}
157d8ee3b5dSSamuel J. Greear 
158d8ee3b5dSSamuel J. Greear       /* Add the starting values of the context according to FIPS 180-2:6.3.2
159d8ee3b5dSSamuel J. Greear 	 step 4.  */
160d8ee3b5dSSamuel J. Greear       a += a_save;
161d8ee3b5dSSamuel J. Greear       b += b_save;
162d8ee3b5dSSamuel J. Greear       c += c_save;
163d8ee3b5dSSamuel J. Greear       d += d_save;
164d8ee3b5dSSamuel J. Greear       e += e_save;
165d8ee3b5dSSamuel J. Greear       f += f_save;
166d8ee3b5dSSamuel J. Greear       g += g_save;
167d8ee3b5dSSamuel J. Greear       h += h_save;
168d8ee3b5dSSamuel J. Greear 
169d8ee3b5dSSamuel J. Greear       /* Prepare for the next round.  */
170d8ee3b5dSSamuel J. Greear       nwords -= 16;
171d8ee3b5dSSamuel J. Greear     }
172d8ee3b5dSSamuel J. Greear 
173d8ee3b5dSSamuel J. Greear   /* Put checksum in context given as argument.  */
174d8ee3b5dSSamuel J. Greear   ctx->H[0] = a;
175d8ee3b5dSSamuel J. Greear   ctx->H[1] = b;
176d8ee3b5dSSamuel J. Greear   ctx->H[2] = c;
177d8ee3b5dSSamuel J. Greear   ctx->H[3] = d;
178d8ee3b5dSSamuel J. Greear   ctx->H[4] = e;
179d8ee3b5dSSamuel J. Greear   ctx->H[5] = f;
180d8ee3b5dSSamuel J. Greear   ctx->H[6] = g;
181d8ee3b5dSSamuel J. Greear   ctx->H[7] = h;
182d8ee3b5dSSamuel J. Greear }
183d8ee3b5dSSamuel J. Greear 
184d8ee3b5dSSamuel J. Greear 
185d8ee3b5dSSamuel J. Greear /* Initialize structure containing state of computation.
186d8ee3b5dSSamuel J. Greear    (FIPS 180-2:5.3.3)  */
1870fe46dc6SMatthew Dillon void
__crypt__sha512_init_ctx(struct sha512_ctx * ctx)1880fe46dc6SMatthew Dillon __crypt__sha512_init_ctx (struct sha512_ctx *ctx)
189d8ee3b5dSSamuel J. Greear {
190d8ee3b5dSSamuel J. Greear   ctx->H[0] = UINT64_C (0x6a09e667f3bcc908);
191d8ee3b5dSSamuel J. Greear   ctx->H[1] = UINT64_C (0xbb67ae8584caa73b);
192d8ee3b5dSSamuel J. Greear   ctx->H[2] = UINT64_C (0x3c6ef372fe94f82b);
193d8ee3b5dSSamuel J. Greear   ctx->H[3] = UINT64_C (0xa54ff53a5f1d36f1);
194d8ee3b5dSSamuel J. Greear   ctx->H[4] = UINT64_C (0x510e527fade682d1);
195d8ee3b5dSSamuel J. Greear   ctx->H[5] = UINT64_C (0x9b05688c2b3e6c1f);
196d8ee3b5dSSamuel J. Greear   ctx->H[6] = UINT64_C (0x1f83d9abfb41bd6b);
197d8ee3b5dSSamuel J. Greear   ctx->H[7] = UINT64_C (0x5be0cd19137e2179);
198d8ee3b5dSSamuel J. Greear 
199d8ee3b5dSSamuel J. Greear   ctx->total[0] = ctx->total[1] = 0;
200d8ee3b5dSSamuel J. Greear   ctx->buflen = 0;
201d8ee3b5dSSamuel J. Greear }
202d8ee3b5dSSamuel J. Greear 
203d8ee3b5dSSamuel J. Greear 
204d8ee3b5dSSamuel J. Greear /* Process the remaining bytes in the internal buffer and the usual
205d8ee3b5dSSamuel J. Greear    prolog according to the standard and write the result to RESBUF.
206d8ee3b5dSSamuel J. Greear 
207d8ee3b5dSSamuel J. Greear    IMPORTANT: On some systems it is required that RESBUF is correctly
208d8ee3b5dSSamuel J. Greear    aligned for a 32 bits value.  */
2090fe46dc6SMatthew Dillon void *
__crypt__sha512_finish_ctx(struct sha512_ctx * ctx,void * resbuf)2100fe46dc6SMatthew Dillon __crypt__sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
211d8ee3b5dSSamuel J. Greear {
212d8ee3b5dSSamuel J. Greear   /* Take yet unprocessed bytes into account.  */
213d8ee3b5dSSamuel J. Greear   uint64_t bytes = ctx->buflen;
214d8ee3b5dSSamuel J. Greear   size_t pad;
215d8ee3b5dSSamuel J. Greear 
216d8ee3b5dSSamuel J. Greear   /* Now count remaining bytes.  */
217d8ee3b5dSSamuel J. Greear   ctx->total[0] += bytes;
218d8ee3b5dSSamuel J. Greear   if (ctx->total[0] < bytes)
219d8ee3b5dSSamuel J. Greear     ++ctx->total[1];
220d8ee3b5dSSamuel J. Greear 
221d8ee3b5dSSamuel J. Greear   pad = bytes >= 112 ? 128 + 112 - bytes : 112 - bytes;
222d8ee3b5dSSamuel J. Greear   memcpy (&ctx->buffer[bytes], fillbuf, pad);
223d8ee3b5dSSamuel J. Greear 
224d8ee3b5dSSamuel J. Greear   /* Put the 128-bit file length in *bits* at the end of the buffer.  */
225d8ee3b5dSSamuel J. Greear   *(uint64_t *) &ctx->buffer[bytes + pad + 8] = SWAP (ctx->total[0] << 3);
226d8ee3b5dSSamuel J. Greear   *(uint64_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
227d8ee3b5dSSamuel J. Greear 						  (ctx->total[0] >> 61));
228d8ee3b5dSSamuel J. Greear 
229d8ee3b5dSSamuel J. Greear   /* Process last bytes.  */
2300fe46dc6SMatthew Dillon   __crypt__sha512_process_block (ctx->buffer, bytes + pad + 16, ctx);
231d8ee3b5dSSamuel J. Greear 
232d8ee3b5dSSamuel J. Greear   /* Put result from CTX in first 64 bytes following RESBUF.  */
233d8ee3b5dSSamuel J. Greear   for (unsigned int i = 0; i < 8; ++i)
234d8ee3b5dSSamuel J. Greear     ((uint64_t *) resbuf)[i] = SWAP (ctx->H[i]);
235d8ee3b5dSSamuel J. Greear 
236d8ee3b5dSSamuel J. Greear   return resbuf;
237d8ee3b5dSSamuel J. Greear }
238d8ee3b5dSSamuel J. Greear 
239d8ee3b5dSSamuel J. Greear 
2400fe46dc6SMatthew Dillon void
__crypt__sha512_process_bytes(const void * buffer,size_t len,struct sha512_ctx * ctx)2410fe46dc6SMatthew Dillon __crypt__sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
242d8ee3b5dSSamuel J. Greear {
243d8ee3b5dSSamuel J. Greear   /* When we already have some bits in our internal buffer concatenate
244d8ee3b5dSSamuel J. Greear      both inputs first.  */
245d8ee3b5dSSamuel J. Greear   if (ctx->buflen != 0)
246d8ee3b5dSSamuel J. Greear     {
247d8ee3b5dSSamuel J. Greear       size_t left_over = ctx->buflen;
248d8ee3b5dSSamuel J. Greear       size_t add = 256 - left_over > len ? len : 256 - left_over;
249d8ee3b5dSSamuel J. Greear 
250d8ee3b5dSSamuel J. Greear       memcpy (&ctx->buffer[left_over], buffer, add);
251d8ee3b5dSSamuel J. Greear       ctx->buflen += add;
252d8ee3b5dSSamuel J. Greear 
253d8ee3b5dSSamuel J. Greear       if (ctx->buflen > 128)
254d8ee3b5dSSamuel J. Greear 	{
2550fe46dc6SMatthew Dillon 	  __crypt__sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
256d8ee3b5dSSamuel J. Greear 
257d8ee3b5dSSamuel J. Greear 	  ctx->buflen &= 127;
258d8ee3b5dSSamuel J. Greear 	  /* The regions in the following copy operation cannot overlap.  */
259d8ee3b5dSSamuel J. Greear 	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~127],
260d8ee3b5dSSamuel J. Greear 		  ctx->buflen);
261d8ee3b5dSSamuel J. Greear 	}
262d8ee3b5dSSamuel J. Greear 
263d8ee3b5dSSamuel J. Greear       buffer = (const char *) buffer + add;
264d8ee3b5dSSamuel J. Greear       len -= add;
265d8ee3b5dSSamuel J. Greear     }
266d8ee3b5dSSamuel J. Greear 
267d8ee3b5dSSamuel J. Greear   /* Process available complete blocks.  */
268d8ee3b5dSSamuel J. Greear   if (len >= 128)
269d8ee3b5dSSamuel J. Greear     {
270d8ee3b5dSSamuel J. Greear #if __GNUC__ >= 2
271d8ee3b5dSSamuel J. Greear # define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint64_t) != 0)
272d8ee3b5dSSamuel J. Greear #else
273d8ee3b5dSSamuel J. Greear # define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint64_t) != 0)
274d8ee3b5dSSamuel J. Greear #endif
275d8ee3b5dSSamuel J. Greear       if (UNALIGNED_P (buffer))
276d8ee3b5dSSamuel J. Greear 	while (len > 128)
277d8ee3b5dSSamuel J. Greear 	  {
2780fe46dc6SMatthew Dillon 	    __crypt__sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128,
279d8ee3b5dSSamuel J. Greear 				    ctx);
280d8ee3b5dSSamuel J. Greear 	    buffer = (const char *) buffer + 128;
281d8ee3b5dSSamuel J. Greear 	    len -= 128;
282d8ee3b5dSSamuel J. Greear 	  }
283d8ee3b5dSSamuel J. Greear       else
284d8ee3b5dSSamuel J. Greear 	{
2850fe46dc6SMatthew Dillon 	  __crypt__sha512_process_block (buffer, len & ~127, ctx);
286d8ee3b5dSSamuel J. Greear 	  buffer = (const char *) buffer + (len & ~127);
287d8ee3b5dSSamuel J. Greear 	  len &= 127;
288d8ee3b5dSSamuel J. Greear 	}
289d8ee3b5dSSamuel J. Greear     }
290d8ee3b5dSSamuel J. Greear 
291d8ee3b5dSSamuel J. Greear   /* Move remaining bytes into internal buffer.  */
292d8ee3b5dSSamuel J. Greear   if (len > 0)
293d8ee3b5dSSamuel J. Greear     {
294d8ee3b5dSSamuel J. Greear       size_t left_over = ctx->buflen;
295d8ee3b5dSSamuel J. Greear 
296d8ee3b5dSSamuel J. Greear       memcpy (&ctx->buffer[left_over], buffer, len);
297d8ee3b5dSSamuel J. Greear       left_over += len;
298d8ee3b5dSSamuel J. Greear       if (left_over >= 128)
299d8ee3b5dSSamuel J. Greear 	{
3000fe46dc6SMatthew Dillon 	  __crypt__sha512_process_block (ctx->buffer, 128, ctx);
301d8ee3b5dSSamuel J. Greear 	  left_over -= 128;
302d8ee3b5dSSamuel J. Greear 	  memcpy (ctx->buffer, &ctx->buffer[128], left_over);
303d8ee3b5dSSamuel J. Greear 	}
304d8ee3b5dSSamuel J. Greear       ctx->buflen = left_over;
305d8ee3b5dSSamuel J. Greear     }
306d8ee3b5dSSamuel J. Greear }
307d8ee3b5dSSamuel J. Greear 
308d8ee3b5dSSamuel J. Greear 
309d8ee3b5dSSamuel J. Greear /* Define our magic string to mark salt for SHA512 "encryption"
310d8ee3b5dSSamuel J. Greear    replacement.  */
311d8ee3b5dSSamuel J. Greear static const char sha512_salt_prefix[] = "$6$";
312d8ee3b5dSSamuel J. Greear 
313d8ee3b5dSSamuel J. Greear /* Prefix for optional rounds specification.  */
314d8ee3b5dSSamuel J. Greear static const char sha512_rounds_prefix[] = "rounds=";
315d8ee3b5dSSamuel J. Greear 
316d8ee3b5dSSamuel J. Greear /* Maximum salt string length.  */
317d8ee3b5dSSamuel J. Greear #define SALT_LEN_MAX 16
318d8ee3b5dSSamuel J. Greear /* Default number of rounds if not explicitly specified.  */
319d8ee3b5dSSamuel J. Greear #define ROUNDS_DEFAULT 5000
320d8ee3b5dSSamuel J. Greear /* Minimum number of rounds.  */
321d8ee3b5dSSamuel J. Greear #define ROUNDS_MIN 1000
322d8ee3b5dSSamuel J. Greear /* Maximum number of rounds.  */
323d8ee3b5dSSamuel J. Greear #define ROUNDS_MAX 999999999
324d8ee3b5dSSamuel J. Greear 
325d8ee3b5dSSamuel J. Greear /* Table with characters for base64 transformation.  */
326d8ee3b5dSSamuel J. Greear static const char b64t[64] =
327d8ee3b5dSSamuel J. Greear "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
328d8ee3b5dSSamuel J. Greear 
329d8ee3b5dSSamuel J. Greear 
330d8ee3b5dSSamuel J. Greear static char *
crypt_sha512_r(const char * key,const char * salt,char * buffer,int buflen)331d8ee3b5dSSamuel J. Greear crypt_sha512_r (const char *key, const char *salt, char *buffer, int buflen)
332d8ee3b5dSSamuel J. Greear {
333d8ee3b5dSSamuel J. Greear   unsigned char alt_result[64]
334d8ee3b5dSSamuel J. Greear     __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
335d8ee3b5dSSamuel J. Greear   unsigned char temp_result[64]
336d8ee3b5dSSamuel J. Greear     __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
337d8ee3b5dSSamuel J. Greear   struct sha512_ctx ctx;
338d8ee3b5dSSamuel J. Greear   struct sha512_ctx alt_ctx;
339d8ee3b5dSSamuel J. Greear   size_t salt_len;
340d8ee3b5dSSamuel J. Greear   size_t key_len;
341d8ee3b5dSSamuel J. Greear   size_t cnt;
342d8ee3b5dSSamuel J. Greear   char *cp;
343d8ee3b5dSSamuel J. Greear   char *copied_key = NULL;
344d8ee3b5dSSamuel J. Greear   char *copied_salt = NULL;
345d8ee3b5dSSamuel J. Greear   char *p_bytes;
346d8ee3b5dSSamuel J. Greear   char *s_bytes;
347d8ee3b5dSSamuel J. Greear   /* Default number of rounds.  */
348d8ee3b5dSSamuel J. Greear   size_t rounds = ROUNDS_DEFAULT;
349d8ee3b5dSSamuel J. Greear   bool rounds_custom = false;
350d8ee3b5dSSamuel J. Greear 
351d8ee3b5dSSamuel J. Greear   /* Find beginning of salt string.  The prefix should normally always
352d8ee3b5dSSamuel J. Greear      be present.  Just in case it is not.  */
353d8ee3b5dSSamuel J. Greear   if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
354d8ee3b5dSSamuel J. Greear     /* Skip salt prefix.  */
355d8ee3b5dSSamuel J. Greear     salt += sizeof (sha512_salt_prefix) - 1;
356d8ee3b5dSSamuel J. Greear 
357d8ee3b5dSSamuel J. Greear   if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1)
358d8ee3b5dSSamuel J. Greear       == 0)
359d8ee3b5dSSamuel J. Greear     {
360d8ee3b5dSSamuel J. Greear       const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
361d8ee3b5dSSamuel J. Greear       char *endp;
362d8ee3b5dSSamuel J. Greear       unsigned long int srounds = strtoul (num, &endp, 10);
363d8ee3b5dSSamuel J. Greear       if (*endp == '$')
364d8ee3b5dSSamuel J. Greear 	{
365d8ee3b5dSSamuel J. Greear 	  salt = endp + 1;
366d8ee3b5dSSamuel J. Greear 	  rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
367d8ee3b5dSSamuel J. Greear 	  rounds_custom = true;
368d8ee3b5dSSamuel J. Greear 	}
369d8ee3b5dSSamuel J. Greear     }
370d8ee3b5dSSamuel J. Greear 
371d8ee3b5dSSamuel J. Greear   salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
372d8ee3b5dSSamuel J. Greear   key_len = strlen (key);
373d8ee3b5dSSamuel J. Greear 
374d8ee3b5dSSamuel J. Greear   if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
375d8ee3b5dSSamuel J. Greear     {
376d8ee3b5dSSamuel J. Greear       char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
377d8ee3b5dSSamuel J. Greear       key = copied_key =
378d8ee3b5dSSamuel J. Greear 	memcpy (tmp + __alignof__ (uint64_t)
379d8ee3b5dSSamuel J. Greear 		- (tmp - (char *) 0) % __alignof__ (uint64_t),
380d8ee3b5dSSamuel J. Greear 		key, key_len);
381d8ee3b5dSSamuel J. Greear     }
382d8ee3b5dSSamuel J. Greear 
383d8ee3b5dSSamuel J. Greear   if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
384d8ee3b5dSSamuel J. Greear     {
385d8ee3b5dSSamuel J. Greear       char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
386d8ee3b5dSSamuel J. Greear       salt = copied_salt =
387d8ee3b5dSSamuel J. Greear 	memcpy (tmp + __alignof__ (uint64_t)
388d8ee3b5dSSamuel J. Greear 		- (tmp - (char *) 0) % __alignof__ (uint64_t),
389d8ee3b5dSSamuel J. Greear 		salt, salt_len);
390d8ee3b5dSSamuel J. Greear     }
391d8ee3b5dSSamuel J. Greear 
392d8ee3b5dSSamuel J. Greear   /* Prepare for the real work.  */
3930fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&ctx);
394d8ee3b5dSSamuel J. Greear 
395d8ee3b5dSSamuel J. Greear   /* Add the key string.  */
3960fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (key, key_len, &ctx);
397d8ee3b5dSSamuel J. Greear 
398d8ee3b5dSSamuel J. Greear   /* The last part is the salt string.  This must be at most 16
399d8ee3b5dSSamuel J. Greear      characters and it ends at the first `$' character (for
400d8ee3b5dSSamuel J. Greear      compatibility with existing implementations).  */
4010fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (salt, salt_len, &ctx);
402d8ee3b5dSSamuel J. Greear 
403d8ee3b5dSSamuel J. Greear 
404d8ee3b5dSSamuel J. Greear   /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.  The
405d8ee3b5dSSamuel J. Greear      final result will be added to the first context.  */
4060fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&alt_ctx);
407d8ee3b5dSSamuel J. Greear 
408d8ee3b5dSSamuel J. Greear   /* Add key.  */
4090fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (key, key_len, &alt_ctx);
410d8ee3b5dSSamuel J. Greear 
411d8ee3b5dSSamuel J. Greear   /* Add salt.  */
4120fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (salt, salt_len, &alt_ctx);
413d8ee3b5dSSamuel J. Greear 
414d8ee3b5dSSamuel J. Greear   /* Add key again.  */
4150fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (key, key_len, &alt_ctx);
416d8ee3b5dSSamuel J. Greear 
417d8ee3b5dSSamuel J. Greear   /* Now get result of this (64 bytes) and add it to the other
418d8ee3b5dSSamuel J. Greear      context.  */
4190fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&alt_ctx, alt_result);
420d8ee3b5dSSamuel J. Greear 
421d8ee3b5dSSamuel J. Greear   /* Add for any character in the key one byte of the alternate sum.  */
422d8ee3b5dSSamuel J. Greear   for (cnt = key_len; cnt > 64; cnt -= 64)
4230fe46dc6SMatthew Dillon     __crypt__sha512_process_bytes (alt_result, 64, &ctx);
4240fe46dc6SMatthew Dillon   __crypt__sha512_process_bytes (alt_result, cnt, &ctx);
425d8ee3b5dSSamuel J. Greear 
426d8ee3b5dSSamuel J. Greear   /* Take the binary representation of the length of the key and for every
427d8ee3b5dSSamuel J. Greear      1 add the alternate sum, for every 0 the key.  */
428d8ee3b5dSSamuel J. Greear   for (cnt = key_len; cnt > 0; cnt >>= 1)
429d8ee3b5dSSamuel J. Greear     if ((cnt & 1) != 0)
4300fe46dc6SMatthew Dillon       __crypt__sha512_process_bytes (alt_result, 64, &ctx);
431d8ee3b5dSSamuel J. Greear     else
4320fe46dc6SMatthew Dillon       __crypt__sha512_process_bytes (key, key_len, &ctx);
433d8ee3b5dSSamuel J. Greear 
434d8ee3b5dSSamuel J. Greear   /* Create intermediate result.  */
4350fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&ctx, alt_result);
436d8ee3b5dSSamuel J. Greear 
437d8ee3b5dSSamuel J. Greear   /* Start computation of P byte sequence.  */
4380fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&alt_ctx);
439d8ee3b5dSSamuel J. Greear 
440d8ee3b5dSSamuel J. Greear   /* For every character in the password add the entire password.  */
441d8ee3b5dSSamuel J. Greear   for (cnt = 0; cnt < key_len; ++cnt)
4420fe46dc6SMatthew Dillon     __crypt__sha512_process_bytes (key, key_len, &alt_ctx);
443d8ee3b5dSSamuel J. Greear 
444d8ee3b5dSSamuel J. Greear   /* Finish the digest.  */
4450fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&alt_ctx, temp_result);
446d8ee3b5dSSamuel J. Greear 
447d8ee3b5dSSamuel J. Greear   /* Create byte sequence P.  */
448d8ee3b5dSSamuel J. Greear   cp = p_bytes = alloca (key_len);
449d8ee3b5dSSamuel J. Greear   for (cnt = key_len; cnt >= 64; cnt -= 64)
450d8ee3b5dSSamuel J. Greear     cp = mempcpy (cp, temp_result, 64);
451d8ee3b5dSSamuel J. Greear   memcpy (cp, temp_result, cnt);
452d8ee3b5dSSamuel J. Greear 
453d8ee3b5dSSamuel J. Greear   /* Start computation of S byte sequence.  */
4540fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&alt_ctx);
455d8ee3b5dSSamuel J. Greear 
456d8ee3b5dSSamuel J. Greear   /* For every character in the password add the entire password.  */
457d8ee3b5dSSamuel J. Greear   for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
4580fe46dc6SMatthew Dillon     __crypt__sha512_process_bytes (salt, salt_len, &alt_ctx);
459d8ee3b5dSSamuel J. Greear 
460d8ee3b5dSSamuel J. Greear   /* Finish the digest.  */
4610fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&alt_ctx, temp_result);
462d8ee3b5dSSamuel J. Greear 
463d8ee3b5dSSamuel J. Greear   /* Create byte sequence S.  */
464d8ee3b5dSSamuel J. Greear   cp = s_bytes = alloca (salt_len);
465d8ee3b5dSSamuel J. Greear   for (cnt = salt_len; cnt >= 64; cnt -= 64)
466d8ee3b5dSSamuel J. Greear     cp = mempcpy (cp, temp_result, 64);
467d8ee3b5dSSamuel J. Greear   memcpy (cp, temp_result, cnt);
468d8ee3b5dSSamuel J. Greear 
469d8ee3b5dSSamuel J. Greear   /* Repeatedly run the collected hash value through SHA512 to burn
470d8ee3b5dSSamuel J. Greear      CPU cycles.  */
471d8ee3b5dSSamuel J. Greear   for (cnt = 0; cnt < rounds; ++cnt)
472d8ee3b5dSSamuel J. Greear     {
473d8ee3b5dSSamuel J. Greear       /* New context.  */
4740fe46dc6SMatthew Dillon       __crypt__sha512_init_ctx (&ctx);
475d8ee3b5dSSamuel J. Greear 
476d8ee3b5dSSamuel J. Greear       /* Add key or last result.  */
477d8ee3b5dSSamuel J. Greear       if ((cnt & 1) != 0)
4780fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (p_bytes, key_len, &ctx);
479d8ee3b5dSSamuel J. Greear       else
4800fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (alt_result, 64, &ctx);
481d8ee3b5dSSamuel J. Greear 
482d8ee3b5dSSamuel J. Greear       /* Add salt for numbers not divisible by 3.  */
483d8ee3b5dSSamuel J. Greear       if (cnt % 3 != 0)
4840fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (s_bytes, salt_len, &ctx);
485d8ee3b5dSSamuel J. Greear 
486d8ee3b5dSSamuel J. Greear       /* Add key for numbers not divisible by 7.  */
487d8ee3b5dSSamuel J. Greear       if (cnt % 7 != 0)
4880fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (p_bytes, key_len, &ctx);
489d8ee3b5dSSamuel J. Greear 
490d8ee3b5dSSamuel J. Greear       /* Add key or last result.  */
491d8ee3b5dSSamuel J. Greear       if ((cnt & 1) != 0)
4920fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (alt_result, 64, &ctx);
493d8ee3b5dSSamuel J. Greear       else
4940fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (p_bytes, key_len, &ctx);
495d8ee3b5dSSamuel J. Greear 
496d8ee3b5dSSamuel J. Greear       /* Create intermediate result.  */
4970fe46dc6SMatthew Dillon       __crypt__sha512_finish_ctx (&ctx, alt_result);
498d8ee3b5dSSamuel J. Greear     }
499d8ee3b5dSSamuel J. Greear 
500d8ee3b5dSSamuel J. Greear   /* Now we can construct the result string.  It consists of three
501d8ee3b5dSSamuel J. Greear      parts.  */
502d8ee3b5dSSamuel J. Greear   cp = stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
503d8ee3b5dSSamuel J. Greear   buflen -= sizeof (sha512_salt_prefix) - 1;
504d8ee3b5dSSamuel J. Greear 
505d8ee3b5dSSamuel J. Greear   if (rounds_custom)
506d8ee3b5dSSamuel J. Greear     {
507d8ee3b5dSSamuel J. Greear       int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
508d8ee3b5dSSamuel J. Greear 			sha512_rounds_prefix, rounds);
509d8ee3b5dSSamuel J. Greear       cp += n;
510d8ee3b5dSSamuel J. Greear       buflen -= n;
511d8ee3b5dSSamuel J. Greear     }
512d8ee3b5dSSamuel J. Greear 
513d8ee3b5dSSamuel J. Greear   cp = stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
514d8ee3b5dSSamuel J. Greear   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
515d8ee3b5dSSamuel J. Greear 
516d8ee3b5dSSamuel J. Greear   if (buflen > 0)
517d8ee3b5dSSamuel J. Greear     {
518d8ee3b5dSSamuel J. Greear       *cp++ = '$';
519d8ee3b5dSSamuel J. Greear       --buflen;
520d8ee3b5dSSamuel J. Greear     }
521d8ee3b5dSSamuel J. Greear 
522d8ee3b5dSSamuel J. Greear #define b64_from_24bit(B2, B1, B0, N)					      \
523d8ee3b5dSSamuel J. Greear   do {									      \
524d8ee3b5dSSamuel J. Greear     unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);			      \
525d8ee3b5dSSamuel J. Greear     int n = (N);							      \
526d8ee3b5dSSamuel J. Greear     while (n-- > 0 && buflen > 0)					      \
527d8ee3b5dSSamuel J. Greear       {									      \
528d8ee3b5dSSamuel J. Greear 	*cp++ = b64t[w & 0x3f];						      \
529d8ee3b5dSSamuel J. Greear 	--buflen;							      \
530d8ee3b5dSSamuel J. Greear 	w >>= 6;							      \
531d8ee3b5dSSamuel J. Greear       }									      \
532d8ee3b5dSSamuel J. Greear   } while (0)
533d8ee3b5dSSamuel J. Greear 
534d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
535d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
536d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
537d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
538d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
539d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
540d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
541d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
542d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
543d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
544d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
545d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
546d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
547d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
548d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
549d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
550d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
551d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
552d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
553d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
554d8ee3b5dSSamuel J. Greear   b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
555d8ee3b5dSSamuel J. Greear   b64_from_24bit (0, 0, alt_result[63], 2);
556d8ee3b5dSSamuel J. Greear 
557d8ee3b5dSSamuel J. Greear   if (buflen <= 0)
558d8ee3b5dSSamuel J. Greear     {
559d8ee3b5dSSamuel J. Greear       errno = ERANGE;
560d8ee3b5dSSamuel J. Greear       buffer = NULL;
561d8ee3b5dSSamuel J. Greear     }
562d8ee3b5dSSamuel J. Greear   else
563d8ee3b5dSSamuel J. Greear     *cp = '\0';		/* Terminate the string.  */
564d8ee3b5dSSamuel J. Greear 
565d8ee3b5dSSamuel J. Greear   /* Clear the buffer for the intermediate result so that people
566d8ee3b5dSSamuel J. Greear      attaching to processes or reading core dumps cannot get any
567d8ee3b5dSSamuel J. Greear      information.  We do it in this way to clear correct_words[]
568d8ee3b5dSSamuel J. Greear      inside the SHA512 implementation as well.  */
5690fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&ctx);
5700fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&ctx, alt_result);
571d8ee3b5dSSamuel J. Greear   memset (temp_result, '\0', sizeof (temp_result));
572d8ee3b5dSSamuel J. Greear   memset (p_bytes, '\0', key_len);
573d8ee3b5dSSamuel J. Greear   memset (s_bytes, '\0', salt_len);
574d8ee3b5dSSamuel J. Greear   memset (&ctx, '\0', sizeof (ctx));
575d8ee3b5dSSamuel J. Greear   memset (&alt_ctx, '\0', sizeof (alt_ctx));
576d8ee3b5dSSamuel J. Greear   if (copied_key != NULL)
577d8ee3b5dSSamuel J. Greear     memset (copied_key, '\0', key_len);
578d8ee3b5dSSamuel J. Greear   if (copied_salt != NULL)
579d8ee3b5dSSamuel J. Greear     memset (copied_salt, '\0', salt_len);
580d8ee3b5dSSamuel J. Greear 
581d8ee3b5dSSamuel J. Greear   return buffer;
582d8ee3b5dSSamuel J. Greear }
583d8ee3b5dSSamuel J. Greear 
584d8ee3b5dSSamuel J. Greear 
585d8ee3b5dSSamuel J. Greear /* This entry point is equivalent to the `crypt' function in Unix
586d8ee3b5dSSamuel J. Greear    libcs.  */
587d8ee3b5dSSamuel J. Greear char *
crypt_sha512(const char * key,const char * salt)588d8ee3b5dSSamuel J. Greear crypt_sha512 (const char *key, const char *salt)
589d8ee3b5dSSamuel J. Greear {
590d8ee3b5dSSamuel J. Greear   /* We don't want to have an arbitrary limit in the size of the
591d8ee3b5dSSamuel J. Greear      password.  We can compute an upper bound for the size of the
592d8ee3b5dSSamuel J. Greear      result in advance and so we can prepare the buffer we pass to
593d8ee3b5dSSamuel J. Greear      `crypt_sha512_r'.  */
594d8ee3b5dSSamuel J. Greear   static char *buffer;
595d8ee3b5dSSamuel J. Greear   static int buflen;
596d8ee3b5dSSamuel J. Greear   int needed = (sizeof (sha512_salt_prefix) - 1
597d8ee3b5dSSamuel J. Greear 		+ sizeof (sha512_rounds_prefix) + 9 + 1
598d8ee3b5dSSamuel J. Greear 		+ strlen (salt) + 1 + 86 + 1);
599d8ee3b5dSSamuel J. Greear 
600d8ee3b5dSSamuel J. Greear   if (buflen < needed)
601d8ee3b5dSSamuel J. Greear     {
602d8ee3b5dSSamuel J. Greear       char *new_buffer = (char *) realloc (buffer, needed);
603d8ee3b5dSSamuel J. Greear       if (new_buffer == NULL)
604d8ee3b5dSSamuel J. Greear 	return NULL;
605d8ee3b5dSSamuel J. Greear 
606d8ee3b5dSSamuel J. Greear       buffer = new_buffer;
607d8ee3b5dSSamuel J. Greear       buflen = needed;
608d8ee3b5dSSamuel J. Greear     }
609d8ee3b5dSSamuel J. Greear 
610d8ee3b5dSSamuel J. Greear   return crypt_sha512_r (key, salt, buffer, buflen);
611d8ee3b5dSSamuel J. Greear }
612d8ee3b5dSSamuel J. Greear 
613d8ee3b5dSSamuel J. Greear 
614d8ee3b5dSSamuel J. Greear #ifdef TEST
615d8ee3b5dSSamuel J. Greear static const struct
616d8ee3b5dSSamuel J. Greear {
617d8ee3b5dSSamuel J. Greear   const char *input;
618d8ee3b5dSSamuel J. Greear   const char result[64];
619d8ee3b5dSSamuel J. Greear } tests[] =
620d8ee3b5dSSamuel J. Greear   {
621d8ee3b5dSSamuel J. Greear     /* Test vectors from FIPS 180-2: appendix C.1.  */
622d8ee3b5dSSamuel J. Greear     { "abc",
623d8ee3b5dSSamuel J. Greear       "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31"
624d8ee3b5dSSamuel J. Greear       "\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
625d8ee3b5dSSamuel J. Greear       "\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
626d8ee3b5dSSamuel J. Greear       "\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f" },
627d8ee3b5dSSamuel J. Greear     /* Test vectors from FIPS 180-2: appendix C.2.  */
628d8ee3b5dSSamuel J. Greear     { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
629d8ee3b5dSSamuel J. Greear       "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
630d8ee3b5dSSamuel J. Greear       "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14\x3f"
631d8ee3b5dSSamuel J. Greear       "\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88\x90\x18"
632d8ee3b5dSSamuel J. Greear       "\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4\xb5\x43\x3a"
633d8ee3b5dSSamuel J. Greear       "\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b\x87\x4b\xe9\x09" },
634d8ee3b5dSSamuel J. Greear     /* Test vectors from the NESSIE project.  */
635d8ee3b5dSSamuel J. Greear     { "",
636d8ee3b5dSSamuel J. Greear       "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd\xf1\x54\x28\x50\xd6\x6d\x80\x07"
637d8ee3b5dSSamuel J. Greear       "\xd6\x20\xe4\x05\x0b\x57\x15\xdc\x83\xf4\xa9\x21\xd3\x6c\xe9\xce"
638d8ee3b5dSSamuel J. Greear       "\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0\xff\x83\x18\xd2\x87\x7e\xec\x2f"
639d8ee3b5dSSamuel J. Greear       "\x63\xb9\x31\xbd\x47\x41\x7a\x81\xa5\x38\x32\x7a\xf9\x27\xda\x3e" },
640d8ee3b5dSSamuel J. Greear     { "a",
641d8ee3b5dSSamuel J. Greear       "\x1f\x40\xfc\x92\xda\x24\x16\x94\x75\x09\x79\xee\x6c\xf5\x82\xf2"
642d8ee3b5dSSamuel J. Greear       "\xd5\xd7\xd2\x8e\x18\x33\x5d\xe0\x5a\xbc\x54\xd0\x56\x0e\x0f\x53"
643d8ee3b5dSSamuel J. Greear       "\x02\x86\x0c\x65\x2b\xf0\x8d\x56\x02\x52\xaa\x5e\x74\x21\x05\x46"
644d8ee3b5dSSamuel J. Greear       "\xf3\x69\xfb\xbb\xce\x8c\x12\xcf\xc7\x95\x7b\x26\x52\xfe\x9a\x75" },
645d8ee3b5dSSamuel J. Greear     { "message digest",
646d8ee3b5dSSamuel J. Greear       "\x10\x7d\xbf\x38\x9d\x9e\x9f\x71\xa3\xa9\x5f\x6c\x05\x5b\x92\x51"
647d8ee3b5dSSamuel J. Greear       "\xbc\x52\x68\xc2\xbe\x16\xd6\xc1\x34\x92\xea\x45\xb0\x19\x9f\x33"
648d8ee3b5dSSamuel J. Greear       "\x09\xe1\x64\x55\xab\x1e\x96\x11\x8e\x8a\x90\x5d\x55\x97\xb7\x20"
649d8ee3b5dSSamuel J. Greear       "\x38\xdd\xb3\x72\xa8\x98\x26\x04\x6d\xe6\x66\x87\xbb\x42\x0e\x7c" },
650d8ee3b5dSSamuel J. Greear     { "abcdefghijklmnopqrstuvwxyz",
651d8ee3b5dSSamuel J. Greear       "\x4d\xbf\xf8\x6c\xc2\xca\x1b\xae\x1e\x16\x46\x8a\x05\xcb\x98\x81"
652d8ee3b5dSSamuel J. Greear       "\xc9\x7f\x17\x53\xbc\xe3\x61\x90\x34\x89\x8f\xaa\x1a\xab\xe4\x29"
653d8ee3b5dSSamuel J. Greear       "\x95\x5a\x1b\xf8\xec\x48\x3d\x74\x21\xfe\x3c\x16\x46\x61\x3a\x59"
654d8ee3b5dSSamuel J. Greear       "\xed\x54\x41\xfb\x0f\x32\x13\x89\xf7\x7f\x48\xa8\x79\xc7\xb1\xf1" },
655d8ee3b5dSSamuel J. Greear     { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
656d8ee3b5dSSamuel J. Greear       "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
657d8ee3b5dSSamuel J. Greear       "\x57\xc1\x6e\xf4\x68\xb2\x28\xa8\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
658d8ee3b5dSSamuel J. Greear       "\x96\xfd\x15\xc1\x3b\x1b\x07\xf9\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
659d8ee3b5dSSamuel J. Greear       "\x31\xad\x85\xc7\xa7\x1d\xd7\x03\x54\xec\x63\x12\x38\xca\x34\x45" },
660d8ee3b5dSSamuel J. Greear     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
661d8ee3b5dSSamuel J. Greear       "\x1e\x07\xbe\x23\xc2\x6a\x86\xea\x37\xea\x81\x0c\x8e\xc7\x80\x93"
662d8ee3b5dSSamuel J. Greear       "\x52\x51\x5a\x97\x0e\x92\x53\xc2\x6f\x53\x6c\xfc\x7a\x99\x96\xc4"
663d8ee3b5dSSamuel J. Greear       "\x5c\x83\x70\x58\x3e\x0a\x78\xfa\x4a\x90\x04\x1d\x71\xa4\xce\xab"
664d8ee3b5dSSamuel J. Greear       "\x74\x23\xf1\x9c\x71\xb9\xd5\xa3\xe0\x12\x49\xf0\xbe\xbd\x58\x94" },
665d8ee3b5dSSamuel J. Greear     { "123456789012345678901234567890123456789012345678901234567890"
666d8ee3b5dSSamuel J. Greear       "12345678901234567890",
667d8ee3b5dSSamuel J. Greear       "\x72\xec\x1e\xf1\x12\x4a\x45\xb0\x47\xe8\xb7\xc7\x5a\x93\x21\x95"
668d8ee3b5dSSamuel J. Greear       "\x13\x5b\xb6\x1d\xe2\x4e\xc0\xd1\x91\x40\x42\x24\x6e\x0a\xec\x3a"
669d8ee3b5dSSamuel J. Greear       "\x23\x54\xe0\x93\xd7\x6f\x30\x48\xb4\x56\x76\x43\x46\x90\x0c\xb1"
670d8ee3b5dSSamuel J. Greear       "\x30\xd2\xa4\xfd\x5d\xd1\x6a\xbb\x5e\x30\xbc\xb8\x50\xde\xe8\x43" }
671d8ee3b5dSSamuel J. Greear   };
672e62ef63cSSascha Wildner #define ntests (NELEM(tests))
673d8ee3b5dSSamuel J. Greear 
674d8ee3b5dSSamuel J. Greear 
675d8ee3b5dSSamuel J. Greear static const struct
676d8ee3b5dSSamuel J. Greear {
677d8ee3b5dSSamuel J. Greear   const char *salt;
678d8ee3b5dSSamuel J. Greear   const char *input;
679d8ee3b5dSSamuel J. Greear   const char *expected;
680d8ee3b5dSSamuel J. Greear } tests2[] =
681d8ee3b5dSSamuel J. Greear {
682d8ee3b5dSSamuel J. Greear   { "$6$saltstring", "Hello world!",
683d8ee3b5dSSamuel J. Greear     "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu"
684d8ee3b5dSSamuel J. Greear     "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" },
685d8ee3b5dSSamuel J. Greear   { "$6$rounds=10000$saltstringsaltstring", "Hello world!",
686d8ee3b5dSSamuel J. Greear     "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb"
687d8ee3b5dSSamuel J. Greear     "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." },
688d8ee3b5dSSamuel J. Greear   { "$6$rounds=5000$toolongsaltstring", "This is just a test",
689d8ee3b5dSSamuel J. Greear     "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ"
690d8ee3b5dSSamuel J. Greear     "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" },
691d8ee3b5dSSamuel J. Greear   { "$6$rounds=1400$anotherlongsaltstring",
692d8ee3b5dSSamuel J. Greear     "a very much longer text to encrypt.  This one even stretches over more"
693d8ee3b5dSSamuel J. Greear     "than one line.",
694d8ee3b5dSSamuel J. Greear     "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP"
695d8ee3b5dSSamuel J. Greear     "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" },
696d8ee3b5dSSamuel J. Greear   { "$6$rounds=77777$short",
697d8ee3b5dSSamuel J. Greear     "we have a short salt string but not a short password",
698d8ee3b5dSSamuel J. Greear     "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g"
699d8ee3b5dSSamuel J. Greear     "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" },
700d8ee3b5dSSamuel J. Greear   { "$6$rounds=123456$asaltof16chars..", "a short string",
701d8ee3b5dSSamuel J. Greear     "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc"
702d8ee3b5dSSamuel J. Greear     "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" },
703d8ee3b5dSSamuel J. Greear   { "$6$rounds=10$roundstoolow", "the minimum number is still observed",
704d8ee3b5dSSamuel J. Greear     "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x"
705d8ee3b5dSSamuel J. Greear     "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." },
706d8ee3b5dSSamuel J. Greear };
707e62ef63cSSascha Wildner #define ntests2 (NELEM(tests2))
708d8ee3b5dSSamuel J. Greear 
709d8ee3b5dSSamuel J. Greear 
710d8ee3b5dSSamuel J. Greear int
main(void)711d8ee3b5dSSamuel J. Greear main (void)
712d8ee3b5dSSamuel J. Greear {
713d8ee3b5dSSamuel J. Greear   struct sha512_ctx ctx;
714d8ee3b5dSSamuel J. Greear   char sum[64];
715d8ee3b5dSSamuel J. Greear   int result = 0;
716d8ee3b5dSSamuel J. Greear   int cnt;
717d8ee3b5dSSamuel J. Greear 
718d8ee3b5dSSamuel J. Greear   for (cnt = 0; cnt < (int) ntests; ++cnt)
719d8ee3b5dSSamuel J. Greear     {
7200fe46dc6SMatthew Dillon       __crypt__sha512_init_ctx (&ctx);
7210fe46dc6SMatthew Dillon       __crypt__sha512_process_bytes (tests[cnt].input, strlen (tests[cnt].input), &ctx);
7220fe46dc6SMatthew Dillon       __crypt__sha512_finish_ctx (&ctx, sum);
723d8ee3b5dSSamuel J. Greear       if (memcmp (tests[cnt].result, sum, 64) != 0)
724d8ee3b5dSSamuel J. Greear 	{
725d8ee3b5dSSamuel J. Greear 	  printf ("test %d run %d failed\n", cnt, 1);
726d8ee3b5dSSamuel J. Greear 	  result = 1;
727d8ee3b5dSSamuel J. Greear 	}
728d8ee3b5dSSamuel J. Greear 
7290fe46dc6SMatthew Dillon       __crypt__sha512_init_ctx (&ctx);
730d8ee3b5dSSamuel J. Greear       for (int i = 0; tests[cnt].input[i] != '\0'; ++i)
7310fe46dc6SMatthew Dillon 	__crypt__sha512_process_bytes (&tests[cnt].input[i], 1, &ctx);
7320fe46dc6SMatthew Dillon       __crypt__sha512_finish_ctx (&ctx, sum);
733d8ee3b5dSSamuel J. Greear       if (memcmp (tests[cnt].result, sum, 64) != 0)
734d8ee3b5dSSamuel J. Greear 	{
735d8ee3b5dSSamuel J. Greear 	  printf ("test %d run %d failed\n", cnt, 2);
736d8ee3b5dSSamuel J. Greear 	  result = 1;
737d8ee3b5dSSamuel J. Greear 	}
738d8ee3b5dSSamuel J. Greear     }
739d8ee3b5dSSamuel J. Greear 
740d8ee3b5dSSamuel J. Greear   /* Test vector from FIPS 180-2: appendix C.3.  */
741d8ee3b5dSSamuel J. Greear   char buf[1000];
742d8ee3b5dSSamuel J. Greear   memset (buf, 'a', sizeof (buf));
7430fe46dc6SMatthew Dillon   __crypt__sha512_init_ctx (&ctx);
744d8ee3b5dSSamuel J. Greear   for (int i = 0; i < 1000; ++i)
7450fe46dc6SMatthew Dillon     __crypt__sha512_process_bytes (buf, sizeof (buf), &ctx);
7460fe46dc6SMatthew Dillon   __crypt__sha512_finish_ctx (&ctx, sum);
747d8ee3b5dSSamuel J. Greear   static const char expected[64] =
748d8ee3b5dSSamuel J. Greear     "\xe7\x18\x48\x3d\x0c\xe7\x69\x64\x4e\x2e\x42\xc7\xbc\x15\xb4\x63"
749d8ee3b5dSSamuel J. Greear     "\x8e\x1f\x98\xb1\x3b\x20\x44\x28\x56\x32\xa8\x03\xaf\xa9\x73\xeb"
750d8ee3b5dSSamuel J. Greear     "\xde\x0f\xf2\x44\x87\x7e\xa6\x0a\x4c\xb0\x43\x2c\xe5\x77\xc3\x1b"
751d8ee3b5dSSamuel J. Greear     "\xeb\x00\x9c\x5c\x2c\x49\xaa\x2e\x4e\xad\xb2\x17\xad\x8c\xc0\x9b";
752d8ee3b5dSSamuel J. Greear   if (memcmp (expected, sum, 64) != 0)
753d8ee3b5dSSamuel J. Greear     {
754d8ee3b5dSSamuel J. Greear       printf ("test %d failed\n", cnt);
755d8ee3b5dSSamuel J. Greear       result = 1;
756d8ee3b5dSSamuel J. Greear     }
757d8ee3b5dSSamuel J. Greear 
758d8ee3b5dSSamuel J. Greear   for (cnt = 0; cnt < ntests2; ++cnt)
759d8ee3b5dSSamuel J. Greear     {
760d8ee3b5dSSamuel J. Greear       char *cp = crypt_sha512 (tests2[cnt].input, tests2[cnt].salt);
761d8ee3b5dSSamuel J. Greear 
762d8ee3b5dSSamuel J. Greear       if (strcmp (cp, tests2[cnt].expected) != 0)
763d8ee3b5dSSamuel J. Greear 	{
764d8ee3b5dSSamuel J. Greear 	  printf ("test %d: expected \"%s\", got \"%s\"\n",
765d8ee3b5dSSamuel J. Greear 	   	  cnt, tests2[cnt].expected, cp);
766d8ee3b5dSSamuel J. Greear 	  result = 1;
767d8ee3b5dSSamuel J. Greear 	}
768d8ee3b5dSSamuel J. Greear     }
769d8ee3b5dSSamuel J. Greear 
770d8ee3b5dSSamuel J. Greear   if (result == 0)
771d8ee3b5dSSamuel J. Greear     puts ("all tests OK");
772d8ee3b5dSSamuel J. Greear 
773d8ee3b5dSSamuel J. Greear   return result;
774d8ee3b5dSSamuel J. Greear }
775d8ee3b5dSSamuel J. Greear #endif
776d8ee3b5dSSamuel J. Greear 
777