1 /* sha512.c - TinyCrypt SHA-512 crypto hash algorithm implementation */
2 
3 /*
4  *  Copyright (C) 2020 by Intel Corporation, All Rights Reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are met:
8  *
9  *    - Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *
12  *    - Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  *    - Neither the name of Intel Corporation nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *  POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <tinycrypt/sha512.h>
34 #include <tinycrypt/constants.h>
35 #include <tinycrypt/utils.h>
36 
37 static void compress(uint64_t *iv, const uint8_t *data);
38 
tc_sha512_init(TCSha512State_t s)39 int tc_sha512_init(TCSha512State_t s)
40 {
41 	/* input sanity check: */
42 	if (s == (TCSha512State_t) 0) {
43 		return TC_CRYPTO_FAIL;
44 	}
45 
46 	/*
47 	 * Setting the initial state values.
48 	 * These values correspond to the first 64 bits of the fractional parts
49 	 * of the square roots of the first 8 primes: 2, 3, 5, 7, 11, 13, 17
50 	 * and 19.
51 	 */
52 	_set((uint8_t *) s, 0x00, sizeof(*s));
53 	s->iv[0] = 0x6a09e667f3bcc908;
54 	s->iv[1] = 0xbb67ae8584caa73b;
55 	s->iv[2] = 0x3c6ef372fe94f82b;
56 	s->iv[3] = 0xa54ff53a5f1d36f1;
57 	s->iv[4] = 0x510e527fade682d1;
58 	s->iv[5] = 0x9b05688c2b3e6c1f;
59 	s->iv[6] = 0x1f83d9abfb41bd6b;
60 	s->iv[7] = 0x5be0cd19137e2179;
61 
62 	return TC_CRYPTO_SUCCESS;
63 }
64 
tc_sha512_update(TCSha512State_t s,const uint8_t * data,size_t datalen)65 int tc_sha512_update(TCSha512State_t s, const uint8_t *data, size_t datalen)
66 {
67 	/* input sanity check: */
68 	if (s == (TCSha512State_t) 0 || data == (void *) 0) {
69 		return TC_CRYPTO_FAIL;
70 	} else if (datalen == 0) {
71 		return TC_CRYPTO_SUCCESS;
72 	}
73 
74 	while (datalen-- > 0) {
75 		s->leftover[s->leftover_offset++] = *(data++);
76 		if (s->leftover_offset >= TC_SHA512_BLOCK_SIZE) {
77 			compress(s->iv, s->leftover);
78 			s->leftover_offset = 0;
79 			s->bits_hashed += (TC_SHA512_BLOCK_SIZE << 3);
80 		}
81 	}
82 
83 	return TC_CRYPTO_SUCCESS;
84 }
85 
tc_sha512_final(uint8_t * digest,TCSha512State_t s)86 int tc_sha512_final(uint8_t *digest, TCSha512State_t s)
87 {
88 	unsigned int i;
89 
90 	/* input sanity check: */
91 	if (digest == (uint8_t *) 0 || s == (TCSha512State_t) 0) {
92 		return TC_CRYPTO_FAIL;
93 	}
94 
95 	s->bits_hashed += (s->leftover_offset << 3);
96 
97 	s->leftover[s->leftover_offset++] = 0x80; /* always room for one byte */
98 	if (s->leftover_offset > (sizeof(s->leftover) - 16)) {
99 		/* there is not room for all the padding in this block */
100 		_set(s->leftover + s->leftover_offset, 0x00,
101 		     sizeof(s->leftover) - s->leftover_offset);
102 		compress(s->iv, s->leftover);
103 		s->leftover_offset = 0;
104 	}
105 
106 	/*
107 	 * add the padding and the length in big-Endian format
108 	 *
109 	 * NOTE: SHA-512 uses 128 bits for the length of the message, but the
110 	 * current implementation is only using 64 bits for size, leaving the
111 	 * 64 "upper" bits zeroed.
112 	 */
113 	_set(s->leftover + s->leftover_offset, 0x00,
114 	     sizeof(s->leftover) - 8 - s->leftover_offset);
115 	s->leftover[sizeof(s->leftover) - 1]  = (uint8_t)(s->bits_hashed);
116 	s->leftover[sizeof(s->leftover) - 2]  = (uint8_t)(s->bits_hashed >> 8);
117 	s->leftover[sizeof(s->leftover) - 3]  = (uint8_t)(s->bits_hashed >> 16);
118 	s->leftover[sizeof(s->leftover) - 4]  = (uint8_t)(s->bits_hashed >> 24);
119 	s->leftover[sizeof(s->leftover) - 5]  = (uint8_t)(s->bits_hashed >> 32);
120 	s->leftover[sizeof(s->leftover) - 6]  = (uint8_t)(s->bits_hashed >> 40);
121 	s->leftover[sizeof(s->leftover) - 7]  = (uint8_t)(s->bits_hashed >> 48);
122 	s->leftover[sizeof(s->leftover) - 8]  = (uint8_t)(s->bits_hashed >> 56);
123 
124 	/* hash the padding and length */
125 	compress(s->iv, s->leftover);
126 
127 	/* copy the iv out to digest */
128 	for (i = 0; i < TC_SHA512_STATE_BLOCKS; ++i) {
129 		uint64_t t = *((uint64_t *) &s->iv[i]);
130 		*digest++ = (uint8_t)(t >> 56);
131 		*digest++ = (uint8_t)(t >> 48);
132 		*digest++ = (uint8_t)(t >> 40);
133 		*digest++ = (uint8_t)(t >> 32);
134 		*digest++ = (uint8_t)(t >> 24);
135 		*digest++ = (uint8_t)(t >> 16);
136 		*digest++ = (uint8_t)(t >> 8);
137 		*digest++ = (uint8_t)(t);
138 	}
139 
140 	/* destroy the current state */
141 	_set(s, 0, sizeof(*s));
142 
143 	return TC_CRYPTO_SUCCESS;
144 }
145 
146 /*
147  * Initializing SHA-512 Hash constant words K.
148  * These values correspond to the first 64 bits of the fractional parts of the
149  * cube roots of the first 80 primes between 2 and 409.
150  */
151 static const uint64_t k512[80] = {
152 	0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
153 	0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
154 	0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
155 	0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
156 	0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
157 	0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
158 	0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
159 	0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
160 	0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
161 	0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
162 	0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
163 	0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
164 	0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
165 	0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
166 	0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
167 	0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
168 };
169 
ROTR(uint64_t a,uint64_t n)170 static inline uint64_t ROTR(uint64_t a, uint64_t n)
171 {
172 	return (((a) >> n) | ((a) << (64 - n)));
173 }
174 
175 #define Sigma0(a)(ROTR((a), 28) ^ ROTR((a), 34) ^ ROTR((a), 39))
176 #define Sigma1(a)(ROTR((a), 14) ^ ROTR((a), 18) ^ ROTR((a), 41))
177 #define sigma0(a)(ROTR((a), 1) ^ ROTR((a), 8) ^ ((a) >> 7))
178 #define sigma1(a)(ROTR((a), 19) ^ ROTR((a), 61) ^ ((a) >> 6))
179 
180 #define Ch(a, b, c)(((a) & (b)) ^ ((~(a)) & (c)))
181 #define Maj(a, b, c)(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)))
182 
BigEndian(const uint8_t ** c)183 static inline uint64_t BigEndian(const uint8_t **c)
184 {
185 	uint64_t n = 0;
186 
187 	n  = (uint64_t)(*((*c)++)) << 56;
188 	n |= (uint64_t)(*((*c)++)) << 48;
189 	n |= (uint64_t)(*((*c)++)) << 40;
190 	n |= (uint64_t)(*((*c)++)) << 32;
191 	n |= (uint64_t)(*((*c)++)) << 24;
192 	n |= (uint64_t)(*((*c)++)) << 16;
193 	n |= (uint64_t)(*((*c)++)) << 8;
194 	n |= (uint64_t)(*((*c)++));
195 	return n;
196 }
197 
compress(uint64_t * iv,const uint8_t * data)198 static void compress(uint64_t *iv, const uint8_t *data)
199 {
200 	uint64_t a, b, c, d, e, f, g, h;
201 	uint64_t s0, s1;
202 	uint64_t t1, t2;
203 	uint64_t work_space[16];
204 	uint64_t n;
205 	unsigned int i;
206 
207 	a = iv[0]; b = iv[1]; c = iv[2]; d = iv[3];
208 	e = iv[4]; f = iv[5]; g = iv[6]; h = iv[7];
209 
210 	for (i = 0; i < 16; ++i) {
211 		n = BigEndian(&data);
212 		t1 = work_space[i] = n;
213 		t1 += h + Sigma1(e) + Ch(e, f, g) + k512[i];
214 		t2 = Sigma0(a) + Maj(a, b, c);
215 		h = g; g = f; f = e; e = d + t1;
216 		d = c; c = b; b = a; a = t1 + t2;
217 	}
218 
219 	for ( ; i < 80; ++i) {
220 		s0 = work_space[(i+1)&0x0f];
221 		s0 = sigma0(s0);
222 		s1 = work_space[(i+14)&0x0f];
223 		s1 = sigma1(s1);
224 
225 		t1 = work_space[i&0xf] += s0 + s1 + work_space[(i+9)&0xf];
226 		t1 += h + Sigma1(e) + Ch(e, f, g) + k512[i];
227 		t2 = Sigma0(a) + Maj(a, b, c);
228 		h = g; g = f; f = e; e = d + t1;
229 		d = c; c = b; b = a; a = t1 + t2;
230 	}
231 
232 	iv[0] += a; iv[1] += b; iv[2] += c; iv[3] += d;
233 	iv[4] += e; iv[5] += f; iv[6] += g; iv[7] += h;
234 }
235