Branch data Line data Source code
1 : : /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 : : *
3 : : * LibTomCrypt is a library that provides various cryptographic
4 : : * algorithms in a highly modular and flexible manner.
5 : : *
6 : : * The library is free for all purposes without any express
7 : : * guarantee it works.
8 : : *
9 : : * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
10 : : */
11 : :
12 : : #include "sha512.h"
13 : : #include <stdio.h>
14 : :
15 : : /* the K array */
16 : : static const uint64_t K[80] =
17 : : {
18 : : UINT64_C(0x428a2f98d728ae22),UINT64_C(0x7137449123ef65cd),
19 : : UINT64_C(0xb5c0fbcfec4d3b2f),UINT64_C(0xe9b5dba58189dbbc),
20 : : UINT64_C(0x3956c25bf348b538),UINT64_C(0x59f111f1b605d019),
21 : : UINT64_C(0x923f82a4af194f9b),UINT64_C(0xab1c5ed5da6d8118),
22 : : UINT64_C(0xd807aa98a3030242),UINT64_C(0x12835b0145706fbe),
23 : : UINT64_C(0x243185be4ee4b28c),UINT64_C(0x550c7dc3d5ffb4e2),
24 : : UINT64_C(0x72be5d74f27b896f),UINT64_C(0x80deb1fe3b1696b1),
25 : : UINT64_C(0x9bdc06a725c71235),UINT64_C(0xc19bf174cf692694),
26 : : UINT64_C(0xe49b69c19ef14ad2),UINT64_C(0xefbe4786384f25e3),
27 : : UINT64_C(0x0fc19dc68b8cd5b5),UINT64_C(0x240ca1cc77ac9c65),
28 : : UINT64_C(0x2de92c6f592b0275),UINT64_C(0x4a7484aa6ea6e483),
29 : : UINT64_C(0x5cb0a9dcbd41fbd4),UINT64_C(0x76f988da831153b5),
30 : : UINT64_C(0x983e5152ee66dfab),UINT64_C(0xa831c66d2db43210),
31 : : UINT64_C(0xb00327c898fb213f),UINT64_C(0xbf597fc7beef0ee4),
32 : : UINT64_C(0xc6e00bf33da88fc2),UINT64_C(0xd5a79147930aa725),
33 : : UINT64_C(0x06ca6351e003826f),UINT64_C(0x142929670a0e6e70),
34 : : UINT64_C(0x27b70a8546d22ffc),UINT64_C(0x2e1b21385c26c926),
35 : : UINT64_C(0x4d2c6dfc5ac42aed),UINT64_C(0x53380d139d95b3df),
36 : : UINT64_C(0x650a73548baf63de),UINT64_C(0x766a0abb3c77b2a8),
37 : : UINT64_C(0x81c2c92e47edaee6),UINT64_C(0x92722c851482353b),
38 : : UINT64_C(0xa2bfe8a14cf10364),UINT64_C(0xa81a664bbc423001),
39 : : UINT64_C(0xc24b8b70d0f89791),UINT64_C(0xc76c51a30654be30),
40 : : UINT64_C(0xd192e819d6ef5218),UINT64_C(0xd69906245565a910),
41 : : UINT64_C(0xf40e35855771202a),UINT64_C(0x106aa07032bbd1b8),
42 : : UINT64_C(0x19a4c116b8d2d0c8),UINT64_C(0x1e376c085141ab53),
43 : : UINT64_C(0x2748774cdf8eeb99),UINT64_C(0x34b0bcb5e19b48a8),
44 : : UINT64_C(0x391c0cb3c5c95a63),UINT64_C(0x4ed8aa4ae3418acb),
45 : : UINT64_C(0x5b9cca4f7763e373),UINT64_C(0x682e6ff3d6b2b8a3),
46 : : UINT64_C(0x748f82ee5defb2fc),UINT64_C(0x78a5636f43172f60),
47 : : UINT64_C(0x84c87814a1f0ab72),UINT64_C(0x8cc702081a6439ec),
48 : : UINT64_C(0x90befffa23631e28),UINT64_C(0xa4506cebde82bde9),
49 : : UINT64_C(0xbef9a3f7b2c67915),UINT64_C(0xc67178f2e372532b),
50 : : UINT64_C(0xca273eceea26619c),UINT64_C(0xd186b8c721c0c207),
51 : : UINT64_C(0xeada7dd6cde0eb1e),UINT64_C(0xf57d4f7fee6ed178),
52 : : UINT64_C(0x06f067aa72176fba),UINT64_C(0x0a637dc5a2c898a6),
53 : : UINT64_C(0x113f9804bef90dae),UINT64_C(0x1b710b35131c471b),
54 : : UINT64_C(0x28db77f523047d84),UINT64_C(0x32caab7b40c72493),
55 : : UINT64_C(0x3c9ebe0a15c9bebc),UINT64_C(0x431d67c49c100d4c),
56 : : UINT64_C(0x4cc5d4becb3e42b6),UINT64_C(0x597f299cfc657e2a),
57 : : UINT64_C(0x5fcb6fab3ad6faec),UINT64_C(0x6c44198c4a475817)
58 : : };
59 : :
60 : : /* Various logical functions */
61 : :
62 : : #define ROR64c(x,y) \
63 : : ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
64 : : ((x)<<(((uint64_t)64-((uint64_t)(y)&UINT64_C(63)))&UINT64_C(63))))&UINT64_C(0xFFFFFFFFFFFFFFFF))
65 : :
66 : : #define STORE64H(x,y) \
67 : : { \
68 : : (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
69 : : (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
70 : : (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
71 : : (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); \
72 : : }
73 : :
74 : : #define LOAD64H(x,y) \
75 : : { \
76 : : x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
77 : : (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
78 : : (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
79 : : (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); \
80 : : }
81 : :
82 : : #define Ch(x,y,z) (z ^ (x & (y ^ z)))
83 : : #define Maj(x,y,z) (((x | y)&z) | (x & y))
84 : : #define S(x,n) ROR64c(x,n)
85 : : #define R(x,n) (((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
86 : : #define Sigma0(x) (S(x,28) ^ S(x,34) ^ S(x,39))
87 : : #define Sigma1(x) (S(x,14) ^ S(x,18) ^ S(x,41))
88 : : #define Gamma0(x) (S(x,1) ^ S(x,8) ^ R(x,7))
89 : : #define Gamma1(x) (S(x,19) ^ S(x,61) ^ R(x,6))
90 : : #ifndef MIN
91 : : #define MIN(x,y) ( ((x)<(y))?(x):(y) )
92 : : #endif
93 : :
94 : : #define SHA512_BITS_PER_BYTE UINT64_C(8)
95 : : #define SHA512_BLOCK_BYTES 128U
96 : : #define SHA512_LENGTH_FIELD_OFFSET 120U
97 : : #define SHA512_MAX_BIT_COUNT UINT64_C(0xffffffffffffffff)
98 : :
99 : : /**
100 : : * @brief Mix one full SHA-512 block into the current hash state
101 : : * @details The caller must pass a valid context and exactly one 128-byte block.
102 : : * This routine performs only deterministic SHA-512 block arithmetic, so it has
103 : : * no runtime failure state of its own
104 : : *
105 : : * @param md Hash context that receives the updated state
106 : : * @param buf One complete 128-byte message block
107 : : */
108 : 887994 : static void sha512_compress(
109 : : SHA512_Context *md,
110 : : const unsigned char *buf)
111 : : {
112 : : uint64_t S[8],W[80];
113 : : int i;
114 : :
115 : : /* copy state into S */
116 [ + + ]: 7991946 : for(i = 0; i < 8; i++)
117 : : {
118 : 7103952 : S[i] = md->state[i];
119 : : }
120 : :
121 : : /* copy the state into 1024-bits into W[0..15] */
122 [ + + ]: 15095898 : for(i = 0; i < 16; i++)
123 : : {
124 : 14207904 : LOAD64H(W[i],buf + (8*i));
125 : : }
126 : :
127 : : /* fill W[16..79] */
128 [ + + ]: 57719610 : for(i = 16; i < 80; i++)
129 : : {
130 : 56831616 : W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
131 : : }
132 : :
133 : : /* Compress */
134 : : #define RND(a,b,c,d,e,f,g,h,i) \
135 : : t0 = h + Sigma1(e) + Ch(e,f,g) + K[i] + W[i]; \
136 : : t1 = Sigma0(a) + Maj(a,b,c); \
137 : : d += t0; \
138 : : h = t0 + t1;
139 : :
140 [ + + ]: 9767934 : for(i = 0; i < 80; i += 8)
141 : : {
142 : : uint64_t t0,t1;
143 : :
144 : 8879940 : RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
145 : 8879940 : RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
146 : 8879940 : RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
147 : 8879940 : RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
148 : 8879940 : RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
149 : 8879940 : RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
150 : 8879940 : RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
151 : 8879940 : RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
152 : : }
153 : :
154 : : #undef RND
155 : :
156 : : /* feedback */
157 [ + + ]: 7991946 : for(i = 0; i < 8; i++)
158 : : {
159 : 7103952 : md->state[i] = md->state[i] + S[i];
160 : : }
161 : 887994 : }
162 : :
163 : : /**
164 : : * @brief Check whether more message bytes fit into the recorded SHA-512 length
165 : : * @details This library records the message length in a 64-bit bit counter.
166 : : * The helper keeps update and finalization code from silently wrapping that
167 : : * counter when a caller passes an extremely large or damaged context
168 : : *
169 : : * @param md Hash context whose current length should be checked
170 : : * @param inlen Number of new bytes the caller wants to add
171 : : * @return CRYPT_OK when the bytes fit, otherwise a specific libsha512 error
172 : : */
173 : 6783 : static SHA512_Status sha512_check_available_bytes(
174 : : const SHA512_Context *md,
175 : : size_t inlen)
176 : : {
177 : : uint64_t available_bytes;
178 : :
179 [ + + ]: 6783 : if(md->curlen >= sizeof(md->buf))
180 : : {
181 : 2 : return CRYPT_INVALID_ARG;
182 : : }
183 : :
184 : 6781 : available_bytes = (SHA512_MAX_BIT_COUNT - md->length) / SHA512_BITS_PER_BYTE;
185 : :
186 [ + + ]: 6781 : if(available_bytes < (uint64_t)md->curlen)
187 : : {
188 : 1 : return CRYPT_HASH_OVERFLOW;
189 : : }
190 : :
191 : 6780 : available_bytes -= (uint64_t)md->curlen;
192 : :
193 [ + + ]: 6780 : if((uint64_t)inlen > available_bytes)
194 : : {
195 : 1 : return CRYPT_HASH_OVERFLOW;
196 : : }
197 : :
198 : 6779 : return CRYPT_OK;
199 : : }
200 : :
201 : : /**
202 : : * @brief Prepare a SHA-512 context for a new message
203 : : * @details The context is reset to the standard SHA-512 initial state and can
204 : : * then be passed to sha512_update() and sha512_final()
205 : : *
206 : : * @param md Context to initialize
207 : : * @return CRYPT_OK on success, CRYPT_INVALID_ARG when @p md is NULL
208 : : */
209 : 3422 : SHA512_Status sha512_init(SHA512_Context *md)
210 : : {
211 [ + + ]: 3422 : if(md == NULL)
212 : : {
213 : 1 : return CRYPT_INVALID_ARG;
214 : : }
215 : :
216 : 3421 : md->curlen = 0;
217 : 3421 : md->length = 0;
218 : 3421 : md->state[0] = UINT64_C(0x6a09e667f3bcc908);
219 : 3421 : md->state[1] = UINT64_C(0xbb67ae8584caa73b);
220 : 3421 : md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
221 : 3421 : md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
222 : 3421 : md->state[4] = UINT64_C(0x510e527fade682d1);
223 : 3421 : md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
224 : 3421 : md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
225 : 3421 : md->state[7] = UINT64_C(0x5be0cd19137e2179);
226 : :
227 : 3421 : return CRYPT_OK;
228 : : }
229 : :
230 : : /**
231 : : * @brief Add message bytes to a SHA-512 context
232 : : * @details The input may be any size, including zero bytes. The function
233 : : * buffers partial blocks internally and rejects invalid pointers, damaged
234 : : * buffer state, or input that would overflow the recorded message length
235 : : *
236 : : * @param md Context that already passed through sha512_init()
237 : : * @param in Message bytes to add to the hash
238 : : * @param inlen Number of bytes available at @p in
239 : : * @return CRYPT_OK on success, otherwise a specific libsha512 error
240 : : */
241 : 3426 : SHA512_Status sha512_update(
242 : : SHA512_Context *md,
243 : : const unsigned char *in,
244 : : size_t inlen)
245 : : {
246 : : SHA512_Status status;
247 : : size_t i;
248 : :
249 [ + + ]: 3426 : if(md == NULL)
250 : : {
251 : 1 : return CRYPT_INVALID_ARG;
252 : : }
253 : :
254 [ + + ]: 3425 : if(in == NULL)
255 : : {
256 : 1 : return CRYPT_INVALID_ARG;
257 : : }
258 : :
259 : 3424 : status = sha512_check_available_bytes(md,inlen);
260 : :
261 [ + + ]: 3424 : if(status != CRYPT_OK)
262 : : {
263 : 2 : return status;
264 : : }
265 : :
266 [ + + ]: 891358 : while(inlen > 0)
267 : : {
268 [ + + + + ]: 887936 : if(md->curlen == 0 && inlen >= SHA512_BLOCK_BYTES)
269 : : {
270 : 884530 : sha512_compress(md,in);
271 : 884530 : md->length += SHA512_BLOCK_BYTES * SHA512_BITS_PER_BYTE;
272 : 884530 : in += SHA512_BLOCK_BYTES;
273 : 884530 : inlen -= SHA512_BLOCK_BYTES;
274 : : } else {
275 : 3406 : size_t n = MIN(inlen,(SHA512_BLOCK_BYTES - md->curlen));
276 : :
277 [ + + ]: 64752 : for(i = 0; i < n; i++)
278 : : {
279 : 61346 : md->buf[i + md->curlen] = in[i];
280 : : }
281 : :
282 : 3406 : md->curlen += n;
283 : 3406 : in += n;
284 : 3406 : inlen -= n;
285 : :
286 [ + + ]: 3406 : if(md->curlen == SHA512_BLOCK_BYTES)
287 : : {
288 : 12 : sha512_compress(md,md->buf);
289 : 12 : md->length += SHA512_BITS_PER_BYTE * SHA512_BLOCK_BYTES;
290 : 12 : md->curlen = 0;
291 : : }
292 : : }
293 : : }
294 : 3422 : return CRYPT_OK;
295 : : }
296 : :
297 : : /**
298 : : * @brief Finish a SHA-512 message and write its digest
299 : : * @details Finalization adds SHA-512 padding, writes the 64-byte digest, and
300 : : * rejects invalid output storage or a context whose buffered bytes would
301 : : * overflow the recorded message length
302 : : *
303 : : * @param md Context that contains the message accumulated so far
304 : : * @param out Destination for the 64-byte SHA-512 digest
305 : : * @return CRYPT_OK on success, otherwise a specific libsha512 error
306 : : */
307 : 3361 : SHA512_Status sha512_final(
308 : : SHA512_Context *md,
309 : : unsigned char *out)
310 : : {
311 : : SHA512_Status status;
312 : : int i;
313 : :
314 [ + + ]: 3361 : if(md == NULL)
315 : : {
316 : 1 : return CRYPT_INVALID_ARG;
317 : : }
318 : :
319 [ + + ]: 3360 : if(out == NULL)
320 : : {
321 : 1 : return CRYPT_INVALID_ARG;
322 : : }
323 : :
324 : 3359 : status = sha512_check_available_bytes(md,0U);
325 : :
326 [ + + ]: 3359 : if(status != CRYPT_OK)
327 : : {
328 : 2 : return status;
329 : : }
330 : :
331 : : /* increase the length of the message */
332 : 3357 : md->length += (uint64_t)md->curlen * SHA512_BITS_PER_BYTE;
333 : :
334 : : /* append the '1' bit */
335 : 3357 : md->buf[md->curlen++] = (unsigned char)0x80;
336 : :
337 : : /* if the length is currently above 112 bytes we append zeros
338 : : * then compress. Then we can fall back to padding zeros and length
339 : : * encoding like normal.
340 : : */
341 [ + + ]: 3357 : if(md->curlen > 112U)
342 : : {
343 [ + + ]: 988 : while(md->curlen < SHA512_BLOCK_BYTES)
344 : : {
345 : 893 : md->buf[md->curlen++] = (unsigned char)0;
346 : : }
347 : 95 : sha512_compress(md,md->buf);
348 : 95 : md->curlen = 0;
349 : : }
350 : :
351 : : /* pad upto 120 bytes of zeroes
352 : : * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
353 : : * > 2^64 bits of data... :-)
354 : : */
355 [ + + ]: 354286 : while(md->curlen < SHA512_LENGTH_FIELD_OFFSET)
356 : : {
357 : 350929 : md->buf[md->curlen++] = (unsigned char)0;
358 : : }
359 : :
360 : : /* store length */
361 : 3357 : STORE64H(md->length,md->buf + SHA512_LENGTH_FIELD_OFFSET);
362 : 3357 : sha512_compress(md,md->buf);
363 : :
364 : : /* copy output */
365 [ + + ]: 30213 : for(i = 0; i < 8; i++)
366 : : {
367 : 26856 : STORE64H(md->state[i],out+(8*i));
368 : : }
369 : :
370 : 3357 : return CRYPT_OK;
371 : : }
372 : :
373 : : #if 0
374 : : void test(
375 : : const unsigned char *message,
376 : : size_t message_len,
377 : : unsigned char *out)
378 : : {
379 : : // int ret;
380 : : // if ((ret = sha512_init(&ctx))) return ret;
381 : : // if ((ret = sha512_update(&ctx, message, message_len))) return ret;
382 : : // if ((ret = sha512_final(&ctx, out))) return ret;
383 : :
384 : : SHA512_Context ctx;
385 : : sha512_init(&ctx);
386 : : sha512_update(&ctx,message,message_len);
387 : : sha512_final(&ctx,out);
388 : : }
389 : :
390 : : int main(void)
391 : : {
392 : : unsigned char out[SHA512_DIGEST_LENGTH];
393 : : const unsigned char message[] = "Hello World";
394 : : test(message,sizeof(message),out);
395 : :
396 : : for(size_t i = 0; i < 64; i++)
397 : : {
398 : : printf("%02x",out[i]);
399 : : }
400 : : putchar('\n');
401 : :
402 : : return(0);
403 : : }
404 : : #endif
|