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