Arduino Cryptography Library
 All Classes Files Functions Variables Enumerations Enumerator Pages
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 
43 {
44  reset();
45 }
46 
52 {
53  clean(state);
54 }
55 
56 size_t SHA512::hashSize() const
57 {
58  return 64;
59 }
60 
61 size_t SHA512::blockSize() const
62 {
63  return 128;
64 }
65 
67 {
68  static uint64_t const hashStart[8] PROGMEM = {
69  0x6A09E667F3BCC908ULL, 0xBB67AE8584CAA73BULL, 0x3C6EF372FE94F82BULL,
70  0xA54FF53A5F1D36F1ULL, 0x510E527FADE682D1ULL, 0x9B05688C2B3E6C1FULL,
71  0x1F83D9ABFB41BD6BULL, 0x5BE0CD19137E2179ULL
72  };
73  memcpy_P(state.h, hashStart, sizeof(hashStart));
74  state.chunkSize = 0;
75  state.lengthLow = 0;
76  state.lengthHigh = 0;
77 }
78 
79 void SHA512::update(const void *data, size_t len)
80 {
81  // Update the total length in bits, not bytes.
82  uint64_t temp = state.lengthLow;
83  state.lengthLow += (((uint64_t)len) << 3);
84  state.lengthHigh += (((uint64_t)len) >> 61);
85  if (state.lengthLow < temp)
86  ++state.lengthHigh;
87 
88  // Break the input up into 1024-bit chunks and process each in turn.
89  const uint8_t *d = (const uint8_t *)data;
90  while (len > 0) {
91  uint8_t size = 128 - state.chunkSize;
92  if (size > len)
93  size = len;
94  memcpy(((uint8_t *)state.w) + state.chunkSize, d, size);
95  state.chunkSize += size;
96  len -= size;
97  d += size;
98  if (state.chunkSize == 128) {
99  processChunk();
100  state.chunkSize = 0;
101  }
102  }
103 }
104 
105 void SHA512::finalize(void *hash, size_t len)
106 {
107  // Pad the last chunk. We may need two padding chunks if there
108  // isn't enough room in the first for the padding and length.
109  uint8_t *wbytes = (uint8_t *)state.w;
110  if (state.chunkSize <= (128 - 17)) {
111  wbytes[state.chunkSize] = 0x80;
112  memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1));
113  state.w[14] = htobe64(state.lengthHigh);
114  state.w[15] = htobe64(state.lengthLow);
115  processChunk();
116  } else {
117  wbytes[state.chunkSize] = 0x80;
118  memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1));
119  processChunk();
120  memset(wbytes, 0x00, 128 - 16);
121  state.w[14] = htobe64(state.lengthHigh);
122  state.w[15] = htobe64(state.lengthLow);
123  processChunk();
124  }
125 
126  // Convert the result into big endian and return it.
127  for (uint8_t posn = 0; posn < 8; ++posn)
128  state.w[posn] = htobe64(state.h[posn]);
129 
130  // Copy the hash to the caller's return buffer.
131  if (len > 64)
132  len = 64;
133  memcpy(hash, state.w, len);
134 }
135 
137 {
138  clean(state);
139  reset();
140 }
141 
142 void SHA512::resetHMAC(const void *key, size_t keyLen)
143 {
144  formatHMACKey(state.w, key, keyLen, 0x36);
145  state.lengthLow += 128 * 8;
146  processChunk();
147 }
148 
149 void SHA512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
150 {
151  uint8_t temp[64];
152  finalize(temp, sizeof(temp));
153  formatHMACKey(state.w, key, keyLen, 0x5C);
154  state.lengthLow += 128 * 8;
155  processChunk();
156  update(temp, sizeof(temp));
157  finalize(hash, hashLen);
158  clean(temp);
159 }
160 
166 void SHA512::processChunk()
167 {
168  // Round constants for SHA-512.
169  static uint64_t const k[80] PROGMEM = {
170  0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,
171  0xE9B5DBA58189DBBCULL, 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL,
172  0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, 0xD807AA98A3030242ULL,
173  0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
174  0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,
175  0xC19BF174CF692694ULL, 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL,
176  0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, 0x2DE92C6F592B0275ULL,
177  0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
178  0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,
179  0xBF597FC7BEEF0EE4ULL, 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL,
180  0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, 0x27B70A8546D22FFCULL,
181  0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
182  0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,
183  0x92722C851482353BULL, 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL,
184  0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, 0xD192E819D6EF5218ULL,
185  0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
186  0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,
187  0x34B0BCB5E19B48A8ULL, 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL,
188  0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, 0x748F82EE5DEFB2FCULL,
189  0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
190  0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,
191  0xC67178F2E372532BULL, 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL,
192  0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, 0x06F067AA72176FBAULL,
193  0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
194  0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,
195  0x431D67C49C100D4CULL, 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL,
196  0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
197  };
198 
199  // Convert the first 16 words from big endian to host byte order.
200  uint8_t index;
201  for (index = 0; index < 16; ++index)
202  state.w[index] = be64toh(state.w[index]);
203 
204  // Initialise working variables to the current hash value.
205  uint64_t a = state.h[0];
206  uint64_t b = state.h[1];
207  uint64_t c = state.h[2];
208  uint64_t d = state.h[3];
209  uint64_t e = state.h[4];
210  uint64_t f = state.h[5];
211  uint64_t g = state.h[6];
212  uint64_t h = state.h[7];
213 
214  // Perform the first 16 rounds of the compression function main loop.
215  uint64_t temp1, temp2;
216  for (index = 0; index < 16; ++index) {
217  temp1 = h + pgm_read_qword(k + index) + state.w[index] +
218  (rightRotate14_64(e) ^ rightRotate18_64(e) ^
219  rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
220  temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
221  rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
222  h = g;
223  g = f;
224  f = e;
225  e = d + temp1;
226  d = c;
227  c = b;
228  b = a;
229  a = temp1 + temp2;
230  }
231 
232  // Perform the 64 remaining rounds. We expand the first 16 words to
233  // 80 in-place in the "w" array. This saves 512 bytes of memory
234  // that would have otherwise need to be allocated to the "w" array.
235  for (; index < 80; ++index) {
236  // Expand the next word.
237  temp1 = state.w[(index - 15) & 0x0F];
238  temp2 = state.w[(index - 2) & 0x0F];
239  temp1 = state.w[index & 0x0F] =
240  state.w[(index - 16) & 0x0F] + state.w[(index - 7) & 0x0F] +
241  (rightRotate1_64(temp1) ^ rightRotate8_64(temp1) ^
242  (temp1 >> 7)) +
243  (rightRotate19_64(temp2) ^ rightRotate61_64(temp2) ^
244  (temp2 >> 6));
245 
246  // Perform the round.
247  temp1 = h + pgm_read_qword(k + index) + temp1 +
248  (rightRotate14_64(e) ^ rightRotate18_64(e) ^
249  rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
250  temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
251  rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
252  h = g;
253  g = f;
254  f = e;
255  e = d + temp1;
256  d = c;
257  c = b;
258  b = a;
259  a = temp1 + temp2;
260  }
261 
262  // Add the compressed chunk to the current hash value.
263  state.h[0] += a;
264  state.h[1] += b;
265  state.h[2] += c;
266  state.h[3] += d;
267  state.h[4] += e;
268  state.h[5] += f;
269  state.h[6] += g;
270  state.h[7] += h;
271 
272  // Attempt to clean up the stack.
273  a = b = c = d = e = f = g = h = temp1 = temp2 = 0;
274 }
size_t hashSize() const
Size of the hash result from finalize().
Definition: SHA512.cpp:56
size_t blockSize() const
Size of the internal block used by the hash algorithm.
Definition: SHA512.cpp:61
virtual ~SHA512()
Destroys this SHA-512 hash object after clearing sensitive information.
Definition: SHA512.cpp:51
void clear()
Clears the hash state, removing all sensitive data, and then resets the hash ready for a new hashing ...
Definition: SHA512.cpp:136
void reset()
Resets the hash ready for a new hashing process.
Definition: SHA512.cpp:66
void update(const void *data, size_t len)
Updates the hash with more data.
Definition: SHA512.cpp:79
void finalize(void *hash, size_t len)
Finalizes the hashing process and returns the hash.
Definition: SHA512.cpp:105
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:149
SHA512()
Constructs a SHA-512 hash object.
Definition: SHA512.cpp:42
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 resetHMAC(const void *key, size_t keyLen)
Resets the hash ready for a new HMAC hashing process.
Definition: SHA512.cpp:142