Arduino Cryptography Library
SHA512.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "SHA512.h"
24 #include "Crypto.h"
25 #include "utility/RotateUtil.h"
26 #include "utility/EndianUtil.h"
27 #include "utility/ProgMemUtil.h"
28 #include <string.h>
29 
53 {
54  reset();
55 }
56 
62 {
63  clean(state);
64 }
65 
66 size_t SHA512::hashSize() const
67 {
68  return 64;
69 }
70 
71 size_t SHA512::blockSize() const
72 {
73  return 128;
74 }
75 
77 {
78  static uint64_t const hashStart[8] PROGMEM = {
79  0x6A09E667F3BCC908ULL, 0xBB67AE8584CAA73BULL, 0x3C6EF372FE94F82BULL,
80  0xA54FF53A5F1D36F1ULL, 0x510E527FADE682D1ULL, 0x9B05688C2B3E6C1FULL,
81  0x1F83D9ABFB41BD6BULL, 0x5BE0CD19137E2179ULL
82  };
83  memcpy_P(state.h, hashStart, sizeof(hashStart));
84  state.chunkSize = 0;
85  state.lengthLow = 0;
86  state.lengthHigh = 0;
87 }
88 
89 void SHA512::update(const void *data, size_t len)
90 {
91  // Update the total length in bits, not bytes.
92  uint64_t temp = state.lengthLow;
93  state.lengthLow += (((uint64_t)len) << 3);
94  state.lengthHigh += (((uint64_t)len) >> 61);
95  if (state.lengthLow < temp)
96  ++state.lengthHigh;
97 
98  // Break the input up into 1024-bit chunks and process each in turn.
99  const uint8_t *d = (const uint8_t *)data;
100  while (len > 0) {
101  uint8_t size = 128 - state.chunkSize;
102  if (size > len)
103  size = len;
104  memcpy(((uint8_t *)state.w) + state.chunkSize, d, size);
105  state.chunkSize += size;
106  len -= size;
107  d += size;
108  if (state.chunkSize == 128) {
109  processChunk();
110  state.chunkSize = 0;
111  }
112  }
113 }
114 
115 void SHA512::finalize(void *hash, size_t len)
116 {
117  // Pad the last chunk. We may need two padding chunks if there
118  // isn't enough room in the first for the padding and length.
119  uint8_t *wbytes = (uint8_t *)state.w;
120  if (state.chunkSize <= (128 - 17)) {
121  wbytes[state.chunkSize] = 0x80;
122  memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1));
123  state.w[14] = htobe64(state.lengthHigh);
124  state.w[15] = htobe64(state.lengthLow);
125  processChunk();
126  } else {
127  wbytes[state.chunkSize] = 0x80;
128  memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1));
129  processChunk();
130  memset(wbytes, 0x00, 128 - 16);
131  state.w[14] = htobe64(state.lengthHigh);
132  state.w[15] = htobe64(state.lengthLow);
133  processChunk();
134  }
135 
136  // Convert the result into big endian and return it.
137  for (uint8_t posn = 0; posn < 8; ++posn)
138  state.w[posn] = htobe64(state.h[posn]);
139 
140  // Copy the hash to the caller's return buffer.
141  size_t maxHashSize = hashSize();
142  if (len > maxHashSize)
143  len = maxHashSize;
144  memcpy(hash, state.w, len);
145 }
146 
148 {
149  clean(state);
150  reset();
151 }
152 
153 void SHA512::resetHMAC(const void *key, size_t keyLen)
154 {
155  formatHMACKey(state.w, key, keyLen, 0x36);
156  state.lengthLow += 128 * 8;
157  processChunk();
158 }
159 
160 void SHA512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
161 {
162  uint8_t temp[64];
163  finalize(temp, sizeof(temp));
164  formatHMACKey(state.w, key, keyLen, 0x5C);
165  state.lengthLow += 128 * 8;
166  processChunk();
167  update(temp, hashSize());
168  finalize(hash, hashLen);
169  clean(temp);
170 }
171 
178 {
179  // Round constants for SHA-512.
180  static uint64_t const k[80] PROGMEM = {
181  0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,
182  0xE9B5DBA58189DBBCULL, 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL,
183  0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, 0xD807AA98A3030242ULL,
184  0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
185  0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,
186  0xC19BF174CF692694ULL, 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL,
187  0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, 0x2DE92C6F592B0275ULL,
188  0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
189  0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,
190  0xBF597FC7BEEF0EE4ULL, 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL,
191  0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, 0x27B70A8546D22FFCULL,
192  0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
193  0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,
194  0x92722C851482353BULL, 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL,
195  0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, 0xD192E819D6EF5218ULL,
196  0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
197  0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,
198  0x34B0BCB5E19B48A8ULL, 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL,
199  0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, 0x748F82EE5DEFB2FCULL,
200  0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
201  0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,
202  0xC67178F2E372532BULL, 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL,
203  0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, 0x06F067AA72176FBAULL,
204  0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
205  0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,
206  0x431D67C49C100D4CULL, 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL,
207  0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
208  };
209 
210  // Convert the first 16 words from big endian to host byte order.
211  uint8_t index;
212  for (index = 0; index < 16; ++index)
213  state.w[index] = be64toh(state.w[index]);
214 
215  // Initialise working variables to the current hash value.
216  uint64_t a = state.h[0];
217  uint64_t b = state.h[1];
218  uint64_t c = state.h[2];
219  uint64_t d = state.h[3];
220  uint64_t e = state.h[4];
221  uint64_t f = state.h[5];
222  uint64_t g = state.h[6];
223  uint64_t h = state.h[7];
224 
225  // Perform the first 16 rounds of the compression function main loop.
226  uint64_t temp1, temp2;
227  for (index = 0; index < 16; ++index) {
228  temp1 = h + pgm_read_qword(k + index) + state.w[index] +
229  (rightRotate14_64(e) ^ rightRotate18_64(e) ^
230  rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
231  temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
232  rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
233  h = g;
234  g = f;
235  f = e;
236  e = d + temp1;
237  d = c;
238  c = b;
239  b = a;
240  a = temp1 + temp2;
241  }
242 
243  // Perform the 64 remaining rounds. We expand the first 16 words to
244  // 80 in-place in the "w" array. This saves 512 bytes of memory
245  // that would have otherwise need to be allocated to the "w" array.
246  for (; index < 80; ++index) {
247  // Expand the next word.
248  temp1 = state.w[(index - 15) & 0x0F];
249  temp2 = state.w[(index - 2) & 0x0F];
250  temp1 = state.w[index & 0x0F] =
251  state.w[(index - 16) & 0x0F] + state.w[(index - 7) & 0x0F] +
252  (rightRotate1_64(temp1) ^ rightRotate8_64(temp1) ^
253  (temp1 >> 7)) +
254  (rightRotate19_64(temp2) ^ rightRotate61_64(temp2) ^
255  (temp2 >> 6));
256 
257  // Perform the round.
258  temp1 = h + pgm_read_qword(k + index) + temp1 +
259  (rightRotate14_64(e) ^ rightRotate18_64(e) ^
260  rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
261  temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
262  rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
263  h = g;
264  g = f;
265  f = e;
266  e = d + temp1;
267  d = c;
268  c = b;
269  b = a;
270  a = temp1 + temp2;
271  }
272 
273  // Add the compressed chunk to the current hash value.
274  state.h[0] += a;
275  state.h[1] += b;
276  state.h[2] += c;
277  state.h[3] += d;
278  state.h[4] += e;
279  state.h[5] += f;
280  state.h[6] += g;
281  state.h[7] += h;
282 
283  // Attempt to clean up the stack.
284  a = b = c = d = e = f = g = h = temp1 = temp2 = 0;
285 }
void formatHMACKey(void *block, const void *key, size_t len, uint8_t pad)
Formats a HMAC key into a block.
Definition: Hash.cpp:162
void clear()
Clears the hash state, removing all sensitive data, and then resets the hash ready for a new hashing ...
Definition: SHA512.cpp:147
void reset()
Resets the hash ready for a new hashing process.
Definition: SHA512.cpp:76
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
Finalizes the HMAC hashing process and returns the hash.
Definition: SHA512.cpp:160
void resetHMAC(const void *key, size_t keyLen)
Resets the hash ready for a new HMAC hashing process.
Definition: SHA512.cpp:153
SHA512()
Constructs a SHA-512 hash object.
Definition: SHA512.cpp:52
virtual ~SHA512()
Destroys this SHA-512 hash object after clearing sensitive information.
Definition: SHA512.cpp:61
void update(const void *data, size_t len)
Updates the hash with more data.
Definition: SHA512.cpp:89
size_t hashSize() const
Size of the hash result from finalize().
Definition: SHA512.cpp:66
void processChunk()
Processes a single 1024-bit chunk with the core SHA-512 algorithm.
Definition: SHA512.cpp:177
size_t blockSize() const
Size of the internal block used by the hash algorithm.
Definition: SHA512.cpp:71
void finalize(void *hash, size_t len)
Finalizes the hashing process and returns the hash.
Definition: SHA512.cpp:115