tlx
sha256.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * tlx/digest/sha256.cpp
3  *
4  * Public domain implementation of SHA-256 (SHA-2) processor. Copied from
5  * https://github.com/kalven/sha-2, which is based on LibTomCrypt.
6  *
7  * Part of tlx - http://panthema.net/tlx
8  *
9  * Copyright (C) 2018 Timo Bingmann <tb@panthema.net>
10  *
11  * All rights reserved. Published under the Boost Software License, Version 1.0
12  ******************************************************************************/
13 
14 #include <tlx/digest/sha256.hpp>
15 
16 #include <tlx/math/ror.hpp>
17 #include <tlx/string/hexdump.hpp>
18 
19 #include <algorithm>
20 
21 namespace tlx {
22 
23 /*
24  * LibTomCrypt, modular cryptographic library -- Tom St Denis
25  *
26  * LibTomCrypt is a library that provides various cryptographic algorithms in a
27  * highly modular and flexible manner.
28  *
29  * The library is free for all purposes without any express guarantee it works.
30  */
31 
32 typedef uint32_t u32;
33 typedef uint64_t u64;
34 
35 namespace {
36 
37 static const u32 K[64] = {
38  0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
39  0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
40  0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
41  0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
42  0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
43  0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
44  0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
45  0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
46  0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
47  0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
48  0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
49  0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
50  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
51 };
52 
53 static inline u32 min(u32 x, u32 y) {
54  return x < y ? x : y;
55 }
56 
57 static inline u32 load32(const uint8_t* y) {
58  return (u32(y[0]) << 24) | (u32(y[1]) << 16) |
59  (u32(y[2]) << 8) | (u32(y[3]) << 0);
60 }
61 static inline void store64(u64 x, uint8_t* y) {
62  for (int i = 0; i != 8; ++i)
63  y[i] = (x >> ((7 - i) * 8)) & 255;
64 }
65 static inline void store32(u32 x, uint8_t* y) {
66  for (int i = 0; i != 4; ++i)
67  y[i] = (x >> ((3 - i) * 8)) & 255;
68 }
69 
70 static inline u32 Ch(u32 x, u32 y, u32 z) {
71  return z ^ (x & (y ^ z));
72 }
73 static inline u32 Maj(u32 x, u32 y, u32 z) {
74  return ((x | y) & z) | (x & y);
75 }
76 static inline u32 Sh(u32 x, u32 n) {
77  return x >> n;
78 }
79 static inline u32 Sigma0(u32 x) {
80  return ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22);
81 }
82 static inline u32 Sigma1(u32 x) {
83  return ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25);
84 }
85 static inline u32 Gamma0(u32 x) {
86  return ror32(x, 7) ^ ror32(x, 18) ^ Sh(x, 3);
87 }
88 static inline u32 Gamma1(u32 x) {
89  return ror32(x, 17) ^ ror32(x, 19) ^ Sh(x, 10);
90 }
91 
92 static void sha256_compress(uint32_t state[8], const uint8_t* buf) {
93  u32 S[8], W[64], t0, t1, t;
94 
95  // Copy state into S
96  for (size_t i = 0; i < 8; i++)
97  S[i] = state[i];
98 
99  // Copy the state into 512-bits into W[0..15]
100  for (size_t i = 0; i < 16; i++)
101  W[i] = load32(buf + (4 * i));
102 
103  // Fill W[16..63]
104  for (size_t i = 16; i < 64; i++)
105  W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
106 
107  // Compress
108  auto RND =
109  [&](u32 a, u32 b, u32 c, u32& d, u32 e, u32 f, u32 g, u32& h, u32 i)
110  {
111  t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
112  t1 = Sigma0(a) + Maj(a, b, c);
113  d += t0;
114  h = t0 + t1;
115  };
116 
117  for (size_t i = 0; i < 64; ++i)
118  {
119  RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
120  t = S[7], S[7] = S[6], S[6] = S[5], S[5] = S[4],
121  S[4] = S[3], S[3] = S[2], S[2] = S[1], S[1] = S[0], S[0] = t;
122  }
123 
124  // Feedback
125  for (size_t i = 0; i < 8; i++)
126  state[i] = state[i] + S[i];
127 }
128 
129 } // namespace
130 
132  curlen_ = 0;
133  length_ = 0;
134  state_[0] = 0x6A09E667UL;
135  state_[1] = 0xBB67AE85UL;
136  state_[2] = 0x3C6EF372UL;
137  state_[3] = 0xA54FF53AUL;
138  state_[4] = 0x510E527FUL;
139  state_[5] = 0x9B05688CUL;
140  state_[6] = 0x1F83D9ABUL;
141  state_[7] = 0x5BE0CD19UL;
142 }
143 
144 SHA256::SHA256(const void* data, uint32_t size)
145  : SHA256() {
146  process(data, size);
147 }
148 
149 SHA256::SHA256(const std::string& str)
150  : SHA256() {
151  process(str);
152 }
153 
154 void SHA256::process(const void* data, u32 size) {
155  const u32 block_size = sizeof(SHA256::buf_);
156  auto in = static_cast<const uint8_t*>(data);
157 
158  while (size > 0)
159  {
160  if (curlen_ == 0 && size >= block_size)
161  {
162  sha256_compress(state_, in);
163  length_ += block_size * 8;
164  in += block_size;
165  size -= block_size;
166  }
167  else
168  {
169  u32 n = min(size, (block_size - curlen_));
170  std::copy(in, in + n, buf_ + curlen_);
171  curlen_ += n;
172  in += n;
173  size -= n;
174 
175  if (curlen_ == block_size)
176  {
177  sha256_compress(state_, buf_);
178  length_ += 8 * block_size;
179  curlen_ = 0;
180  }
181  }
182  }
183 }
184 
185 void SHA256::process(const std::string& str) {
186  return process(str.data(), str.size());
187 }
188 
190  // Increase the length of the message
191  length_ += curlen_ * 8;
192 
193  // Append the '1' bit
194  buf_[curlen_++] = static_cast<uint8_t>(0x80);
195 
196  // If the length_ is currently above 56 bytes we append zeros then
197  // sha256_compress(). Then we can fall back to padding zeros and length
198  // encoding like normal.
199  if (curlen_ > 56)
200  {
201  while (curlen_ < 64)
202  buf_[curlen_++] = 0;
203  sha256_compress(state_, buf_);
204  curlen_ = 0;
205  }
206 
207  // Pad up to 56 bytes of zeroes
208  while (curlen_ < 56)
209  buf_[curlen_++] = 0;
210 
211  // Store length
212  store64(length_, buf_ + 56);
213  sha256_compress(state_, buf_);
214 
215  // Copy output
216  for (size_t i = 0; i < 8; i++)
217  store32(state_[i], static_cast<uint8_t*>(digest) + (4 * i));
218 }
219 
220 std::string SHA256::digest() {
221  std::string out(kDigestLength, '0');
222  finalize(const_cast<char*>(out.data()));
223  return out;
224 }
225 
226 std::string SHA256::digest_hex() {
227  uint8_t digest[kDigestLength];
228  finalize(digest);
229  return hexdump_lc(digest, kDigestLength);
230 }
231 
232 std::string SHA256::digest_hex_uc() {
233  uint8_t digest[kDigestLength];
234  finalize(digest);
235  return hexdump(digest, kDigestLength);
236 }
237 
238 std::string sha256_hex(const void* data, uint32_t size) {
239  return SHA256(data, size).digest_hex();
240 }
241 
242 std::string sha256_hex(const std::string& str) {
243  return SHA256(str).digest_hex();
244 }
245 
246 std::string sha256_hex_uc(const void* data, uint32_t size) {
247  return SHA256(data, size).digest_hex_uc();
248 }
249 
250 std::string sha256_hex_uc(const std::string& str) {
251  return SHA256(str).digest_hex_uc();
252 }
253 
254 } // namespace tlx
255 
256 /******************************************************************************/
uint64_t length_
Definition: sha256.hpp:57
static uint64_t Gamma0(uint64_t x)
Definition: sha512.cpp:94
std::string digest_hex_uc()
finalize computation and return 32 byte (256 bit) digest upper-case hex
Definition: sha256.cpp:232
static uint64_t Gamma1(uint64_t x)
Definition: sha512.cpp:97
uint32_t curlen_
Definition: sha256.hpp:59
static uint64_t Sigma0(uint64_t x)
Definition: sha512.cpp:88
std::string sha256_hex(const void *data, uint32_t size)
process data and return 32 byte (256 bit) digest hex encoded
Definition: sha256.cpp:238
SHA256()
construct empty object.
Definition: sha256.cpp:131
uint64_t u64
Definition: sha256.cpp:33
std::string hexdump_lc(const void *const data, size_t size)
Dump a (binary) string as a sequence of lowercase hexadecimal pairs.
Definition: hexdump.cpp:95
static uint64_t Sh(uint64_t x, uint64_t n)
Definition: sha512.cpp:85
static uint32_t min(uint32_t x, uint32_t y)
Definition: md5.cpp:32
void finalize(void *digest)
finalize computation and output 32 byte (256 bit) digest
Definition: sha256.cpp:189
void process(const void *data, uint32_t size)
process more data
Definition: sha256.cpp:154
static uint64_t Ch(const uint64_t &x, const uint64_t &y, const uint64_t &z)
Definition: sha512.cpp:78
std::string digest_hex()
finalize computation and return 32 byte (256 bit) digest hex encoded
Definition: sha256.cpp:226
SHA-256 processor without external dependencies.
Definition: sha256.hpp:28
uint32_t state_[8]
Definition: sha256.hpp:58
static constexpr size_t kDigestLength
digest length in bytes
Definition: sha256.hpp:44
static const uint64_t K[80]
Definition: sha512.cpp:32
static uint64_t Sigma1(uint64_t x)
Definition: sha512.cpp:91
std::string sha256_hex_uc(const void *data, uint32_t size)
process data and return 32 byte (256 bit) digest upper-case hex encoded
Definition: sha256.cpp:246
std::string digest()
finalize computation and return 32 byte (256 bit) digest
Definition: sha256.cpp:220
uint32_t u32
Definition: sha256.cpp:32
static void store64(uint64_t x, unsigned char *y)
Definition: sha512.cpp:66
static uint64_t Maj(const uint64_t &x, const uint64_t &y, const uint64_t &z)
Definition: sha512.cpp:82
std::string hexdump(const void *const data, size_t size)
Dump a (binary) string as a sequence of uppercase hexadecimal pairs.
Definition: hexdump.cpp:21
static uint32_t ror32(const uint32_t &x, int i)
ror32 - generic
Definition: ror.hpp:55
uint8_t buf_[64]
Definition: sha256.hpp:60