Version: SMASH-3.1
sha256.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020,2022
3  * SMASH Team
4  *
5  * GNU General Public License (GPLv3 or later)
6  */
7 
8 // This is based on the public-domain implementation from
9 // https://github.com/WaterJuice/WjCryptLib.
10 
11 #include "smash/sha256.h"
12 
13 #include <cstring>
14 #include <iomanip>
15 #include <iostream>
16 #include <sstream>
17 
18 // Macros
19 
20 #define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
21 
22 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
23 
24 #define STORE32H(x, y) \
25  { \
26  (y)[0] = static_cast<uint8_t>(((x) >> 24) & 255); \
27  (y)[1] = static_cast<uint8_t>(((x) >> 16) & 255); \
28  (y)[2] = static_cast<uint8_t>(((x) >> 8) & 255); \
29  (y)[3] = static_cast<uint8_t>((x)&255); \
30  }
31 
32 #define LOAD32H(x, y) \
33  { \
34  x = (static_cast<uint32_t>((y)[0] & 255) << 24) | \
35  (static_cast<uint32_t>((y)[1] & 255) << 16) | \
36  (static_cast<uint32_t>((y)[2] & 255) << 8) | \
37  (static_cast<uint32_t>((y)[3] & 255)); \
38  }
39 
40 #define STORE64H(x, y) \
41  { \
42  (y)[0] = static_cast<uint8_t>(((x) >> 56) & 255); \
43  (y)[1] = static_cast<uint8_t>(((x) >> 48) & 255); \
44  (y)[2] = static_cast<uint8_t>(((x) >> 40) & 255); \
45  (y)[3] = static_cast<uint8_t>(((x) >> 32) & 255); \
46  (y)[4] = static_cast<uint8_t>(((x) >> 24) & 255); \
47  (y)[5] = static_cast<uint8_t>(((x) >> 16) & 255); \
48  (y)[6] = static_cast<uint8_t>(((x) >> 8) & 255); \
49  (y)[7] = static_cast<uint8_t>((x)&255); \
50  }
51 
52 #define Ch(x, y, z) (z ^ (x & (y ^ z)))
53 #define Maj(x, y, z) (((x | y) & z) | (x & y))
54 #define S(x, n) ror((x), (n))
55 #define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
56 #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
57 #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
58 #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
59 #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
60 
61 #define Sha256Round(a, b, c, d, e, f, g, h, i) \
62  t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
63  t1 = Sigma0(a) + Maj(a, b, c); \
64  d += t0; \
65  h = t0 + t1;
66 
67 // Constants
68 
70 static const uint32_t K[64] = {
71  0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
72  0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
73  0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
74  0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
75  0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
76  0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
77  0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
78  0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
79  0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
80  0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
81  0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
82  0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
83  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL};
84 
85 namespace smash {
86 namespace sha256 {
87 
88 constexpr size_t BLOCK_SIZE = 64;
89 
90 // Internal functions
91 
95 void Context::transform_function(uint8_t const* buffer) {
96  uint32_t S[8];
97  uint32_t W[64];
98  uint32_t t0;
99  uint32_t t1;
100  uint32_t t;
101  int i;
102 
103  // Copy state into S
104  for (i = 0; i < 8; i++) {
105  S[i] = state_[i];
106  }
107 
108  // Copy the state into 512-bits into W[0..15]
109  for (i = 0; i < 16; i++) {
110  LOAD32H(W[i], buffer + (4 * i));
111  }
112 
113  // Fill W[16..63]
114  for (i = 16; i < 64; i++) {
115  W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
116  }
117 
118  // Compress
119  for (i = 0; i < 64; i++) {
120  Sha256Round(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
121  t = S[7];
122  S[7] = S[6];
123  S[6] = S[5];
124  S[5] = S[4];
125  S[4] = S[3];
126  S[3] = S[2];
127  S[2] = S[1];
128  S[1] = S[0];
129  S[0] = t;
130  }
131 
132  // Feedback
133  for (i = 0; i < 8; i++) {
134  state_[i] += S[i];
135  }
136 }
137 
138 // Public functions
139 
141  curlen_ = 0;
142  length_ = 0;
143  state_[0] = 0x6A09E667UL;
144  state_[1] = 0xBB67AE85UL;
145  state_[2] = 0x3C6EF372UL;
146  state_[3] = 0xA54FF53AUL;
147  state_[4] = 0x510E527FUL;
148  state_[5] = 0x9B05688CUL;
149  state_[6] = 0x1F83D9ABUL;
150  state_[7] = 0x5BE0CD19UL;
151 }
152 
153 void Context::update(uint8_t const* buffer, size_t buffer_size) {
154  size_t n;
155 
156  if (curlen_ > sizeof(buf_)) {
157  return;
158  }
159 
160  while (buffer_size > 0) {
161  if (curlen_ == 0 && buffer_size >= BLOCK_SIZE) {
162  transform_function(buffer);
163  length_ += BLOCK_SIZE * 8;
164  buffer += BLOCK_SIZE;
165  buffer_size -= BLOCK_SIZE;
166  } else {
167  n = MIN(buffer_size, (BLOCK_SIZE - curlen_));
168  std::memcpy(buf_ + curlen_, buffer, n);
169  curlen_ += n;
170  buffer += n;
171  buffer_size -= n;
172  if (curlen_ == BLOCK_SIZE) {
174  length_ += 8 * BLOCK_SIZE;
175  curlen_ = 0;
176  }
177  }
178  }
179 }
180 
181 void Context::update(const std::string& buffer) {
182  update(reinterpret_cast<const uint8_t*>(buffer.c_str()), buffer.size());
183 }
184 
186  Hash digest{{}};
187  if (curlen_ >= sizeof(buf_)) {
188  return digest;
189  }
190 
191  // Increase the length of the message
192  length_ += curlen_ * 8;
193 
194  // Append the '1' bit
195  buf_[curlen_++] = 0x80;
196 
197  // if the length is currently above 56 bytes we append zeros
198  // then compress. Then we can fall back to padding zeros and length
199  // encoding like normal.
200  if (curlen_ > 56) {
201  while (curlen_ < 64) {
202  buf_[curlen_++] = 0;
203  }
205  curlen_ = 0;
206  }
207 
208  // Pad up to 56 bytes of zeroes
209  while (curlen_ < 56) {
210  buf_[curlen_++] = 0;
211  }
212 
213  // Store length
214  STORE64H(length_, buf_ + 56);
216 
217  // Copy output
218  for (int i = 0; i < 8; i++) {
219  STORE32H(state_[i], digest.data() + (4 * i));
220  }
221  return digest;
222 }
223 
224 Hash calculate(uint8_t const* buffer, size_t buffer_size) {
225  Context context;
226  context.update(buffer, buffer_size);
227  return context.finalize();
228 }
229 
230 std::string hash_to_string(Hash hash) {
231  std::stringstream ss;
232  ss << std::hex;
233  for (uint16_t i : hash) {
234  ss << std::setw(2) << std::setfill('0') << i;
235  }
236  return ss.str();
237 }
238 
239 } // namespace sha256
240 } // namespace smash
A SHA256 context.
Definition: sha256.h:28
void update(uint8_t const *buffer, size_t buffer_size)
Add data to the SHA256 context.
Definition: sha256.cc:153
uint32_t state_[8]
State of the SHA256 hash.
Definition: sha256.h:33
size_t curlen_
Current length of the SHA256 hash.
Definition: sha256.h:35
void transform_function(uint8_t const *buffer)
Compress 512-bits.
Definition: sha256.cc:95
void reset()
Reset the SHA256 context.
Definition: sha256.cc:140
uint64_t length_
Length of the SHA256 hash.
Definition: sha256.h:31
uint8_t buf_[64]
Buffer of the SHA256 hash.
Definition: sha256.h:37
Hash finalize()
Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit h...
Definition: sha256.cc:185
constexpr int n
Neutron.
Hash calculate(uint8_t const *buffer, size_t buffer_size)
Calculate the SHA256 hash of the buffer.
Definition: sha256.cc:224
std::array< uint8_t, HASH_SIZE > Hash
A SHA256 hash.
Definition: sha256.h:25
constexpr size_t BLOCK_SIZE
Definition: sha256.cc:88
std::string hash_to_string(Hash hash)
Convert a SHA256 hash to a hexadecimal string.
Definition: sha256.cc:230
Definition: action.h:24
#define STORE32H(x, y)
Definition: sha256.cc:24
static const uint32_t K[64]
The K array.
Definition: sha256.cc:70
#define S(x, n)
Definition: sha256.cc:54
#define Sha256Round(a, b, c, d, e, f, g, h, i)
Definition: sha256.cc:61
#define MIN(x, y)
Definition: sha256.cc:22
#define Gamma0(x)
Definition: sha256.cc:58
#define Gamma1(x)
Definition: sha256.cc:59
#define LOAD32H(x, y)
Definition: sha256.cc:32
#define STORE64H(x, y)
Definition: sha256.cc:40