0.4.1
Loading...
Searching...
No Matches
SHA256.cpp
Go to the documentation of this file.
1/*
2MIT License
3
4Copyright (c) 2021 Jérémy LAMBERT (SystemGlitch)
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25// NOLINTBEGIN
26
27#include "SHA256.hpp"
28
29#include <cstring>
30#include <iomanip>
31#include <sstream>
32
33#if defined(__clang__)
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wsign-conversion"
36#endif
37
38#ifndef DOXYGEN_IGNORE
39
40namespace NAV
41{
42constexpr std::array<uint32_t, 64> SHA256::K;
43
44SHA256::SHA256() : m_blocklen(0), m_bitlen(0) // NOLINT
45{
46 m_state[0] = 0x6a09e667;
47 m_state[1] = 0xbb67ae85;
48 m_state[2] = 0x3c6ef372;
49 m_state[3] = 0xa54ff53a;
50 m_state[4] = 0x510e527f;
51 m_state[5] = 0x9b05688c;
52 m_state[6] = 0x1f83d9ab;
53 m_state[7] = 0x5be0cd19;
54}
55
56void SHA256::update(const uint8_t* data, size_t length)
57{
58 for (size_t i = 0; i < length; i++)
59 {
60 m_data[m_blocklen++] = data[i]; // NOLINT
61 if (m_blocklen == 64)
62 {
63 transform();
64
65 // End of the block
66 m_bitlen += 512;
67 m_blocklen = 0;
68 }
69 }
70}
71
72void SHA256::update(const std::string& data)
73{
74 update(reinterpret_cast<const uint8_t*>(data.c_str()), data.size()); // NOLINT
75}
76
77uint8_t* SHA256::digest()
78{
79 uint8_t* hash = new uint8_t[32]; // NOLINT
80
81 pad();
82 revert(hash);
83
84 return hash;
85}
86
87uint32_t SHA256::rotr(uint32_t x, uint32_t n)
88{
89 return (x >> n) | (x << (32 - n));
90}
91
92uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g)
93{
94 return (e & f) ^ (~e & g);
95}
96
97uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c)
98{
99 return (a & (b | c)) | (b & c);
100}
101
102uint32_t SHA256::sig0(uint32_t x)
103{
104 return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); // NOLINT
105}
106
107uint32_t SHA256::sig1(uint32_t x)
108{
109 return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); // NOLINT
110}
111
112void SHA256::transform()
113{
114 uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; // NOLINT
115 uint32_t state[8]; // NOLINT
116
117 for (uint8_t i = 0, j = 0; i < 16; i++, j += 4)
118 { // Split data in 32 bit blocks for the 16 first words
119 m[i] = (m_data[j] << 24) | (m_data[j + 1] << 16) | (m_data[j + 2] << 8) | (m_data[j + 3]); // NOLINT
120 }
121
122 for (uint8_t k = 16; k < 64; k++)
123 { // Remaining 48 blocks
124 m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; // NOLINT
125 }
126
127 for (uint8_t i = 0; i < 8; i++)
128 {
129 state[i] = m_state[i]; // NOLINT
130 }
131
132 for (uint8_t i = 0; i < 64; i++)
133 {
134 maj = SHA256::majority(state[0], state[1], state[2]);
135 xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22);
136
137 ch = choose(state[4], state[5], state[6]);
138
139 xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25);
140
141 sum = m[i] + K[i] + state[7] + ch + xorE; // NOLINT
142 newA = xorA + maj + sum;
143 newE = state[3] + sum;
144
145 state[7] = state[6];
146 state[6] = state[5];
147 state[5] = state[4];
148 state[4] = newE;
149 state[3] = state[2];
150 state[2] = state[1];
151 state[1] = state[0];
152 state[0] = newA;
153 }
154
155 for (uint8_t i = 0; i < 8; i++)
156 {
157 m_state[i] += state[i]; // NOLINT
158 }
159}
160
161void SHA256::pad()
162{
163 uint64_t i = m_blocklen;
164 uint8_t end = m_blocklen < 56 ? 56 : 64;
165
166 m_data[i++] = 0x80; // Append a bit 1 // NOLINT
167 while (i < end)
168 {
169 m_data[i++] = 0x00; // Pad with zeros // NOLINT
170 }
171
172 if (m_blocklen >= 56)
173 {
174 transform();
175 memset(m_data, 0, 56); // NOLINT
176 }
177
178 // Append to the padding the total message's length in bits and transform.
179 m_bitlen += m_blocklen * 8; // NOLINT
180 m_data[63] = static_cast<uint8_t>(m_bitlen);
181 m_data[62] = static_cast<uint8_t>(m_bitlen >> 8); // NOLINT
182 m_data[61] = static_cast<uint8_t>(m_bitlen >> 16); // NOLINT
183 m_data[60] = static_cast<uint8_t>(m_bitlen >> 24); // NOLINT
184 m_data[59] = static_cast<uint8_t>(m_bitlen >> 32); // NOLINT
185 m_data[58] = static_cast<uint8_t>(m_bitlen >> 40); // NOLINT
186 m_data[57] = static_cast<uint8_t>(m_bitlen >> 48); // NOLINT
187 m_data[56] = static_cast<uint8_t>(m_bitlen >> 56); // NOLINT
188 transform();
189}
190
191void SHA256::revert(uint8_t* hash)
192{
193 // SHA uses big endian byte ordering
194 // Revert all bytes
195 for (uint8_t i = 0; i < 4; i++)
196 {
197 for (uint8_t j = 0; j < 8; j++)
198 {
199 hash[i + (j * 4)] = (m_state[j] >> (24 - i * 8)) & 0x000000ff; // NOLINT
200 }
201 }
202}
203
204std::string SHA256::toString(const uint8_t* digest)
205{
206 std::stringstream s;
207 s << std::setfill('0') << std::hex;
208
209 for (uint8_t i = 0; i < 32; i++)
210 {
211 s << std::setw(2) << static_cast<unsigned int>(digest[i]); // NOLINT
212 }
213
214 return s.str();
215}
216
217} // namespace NAV
218
219#endif
220
221#if defined(__clang__)
222 #pragma GCC diagnostic pop
223#endif
224// NOLINTEND
auto transform(std::tuple< Ts... > const &inputs, Function function)
Transform algorithm for tuples.