Lightweight 0.20251202.0
Loading...
Searching...
No Matches
Sha256.hpp
1// SPDX-License-Identifier: Apache-2.0
2// Simple SHA-256 implementation for checksum verification
3#pragma once
4
5#include <array>
6#include <cstdint>
7#include <cstring>
8#include <iomanip>
9#include <span>
10#include <sstream>
11#include <string>
12
13namespace Lightweight::SqlBackup
14{
15
16/// Simple SHA-256 implementation for backup integrity verification.
17class Sha256
18{
19 public:
20 static constexpr size_t DigestSize = 32;
21 static constexpr size_t BlockSize = 64;
22
23 Sha256()
24 {
25 Reset();
26 }
27
28 void Reset()
29 {
30 _state[0] = 0x6a09e667;
31 _state[1] = 0xbb67ae85;
32 _state[2] = 0x3c6ef372;
33 _state[3] = 0xa54ff53a;
34 _state[4] = 0x510e527f;
35 _state[5] = 0x9b05688c;
36 _state[6] = 0x1f83d9ab;
37 _state[7] = 0x5be0cd19;
38 _count = 0;
39 _bufferLen = 0;
40 }
41
42 void Update(void const* data, size_t len)
43 {
44 auto const* bytes = static_cast<uint8_t const*>(data);
45 _count += len;
46
47 if (_bufferLen > 0)
48 {
49 size_t const toCopy = std::min(BlockSize - _bufferLen, len);
50 std::memcpy(_buffer.data() + _bufferLen, bytes, toCopy);
51 _bufferLen += toCopy;
52 bytes += toCopy;
53 len -= toCopy;
54
55 if (_bufferLen == BlockSize)
56 {
57 ProcessBlock(_buffer.data());
58 _bufferLen = 0;
59 }
60 }
61
62 while (len >= BlockSize)
63 {
64 ProcessBlock(bytes);
65 bytes += BlockSize;
66 len -= BlockSize;
67 }
68
69 if (len > 0)
70 {
71 std::memcpy(_buffer.data(), bytes, len);
72 _bufferLen = len;
73 }
74 }
75
76 void Update(std::span<uint8_t const> data)
77 {
78 Update(data.data(), data.size());
79 }
80
81 void Update(std::string_view data)
82 {
83 Update(data.data(), data.size());
84 }
85
86 std::array<uint8_t, DigestSize> Finalize()
87 {
88 uint64_t const bitCount = _count * 8;
89
90 // Padding
91 uint8_t const pad = 0x80;
92 Update(&pad, 1);
93
94 while (_bufferLen != 56)
95 {
96 uint8_t const zero = 0;
97 Update(&zero, 1);
98 }
99
100 // Append bit count (big-endian)
101 std::array<uint8_t, 8> countBytes {};
102 for (size_t i = 0; i < 8; ++i)
103 countBytes[i] = static_cast<uint8_t>(bitCount >> (56 - i * 8));
104 Update(countBytes.data(), 8);
105
106 // Output hash
107 std::array<uint8_t, DigestSize> digest {};
108 for (size_t i = 0; i < 8; ++i)
109 {
110 digest[(i * 4) + 0] = static_cast<uint8_t>(_state[i] >> 24);
111 digest[(i * 4) + 1] = static_cast<uint8_t>(_state[i] >> 16);
112 digest[(i * 4) + 2] = static_cast<uint8_t>(_state[i] >> 8);
113 digest[(i * 4) + 3] = static_cast<uint8_t>(_state[i]);
114 }
115 return digest;
116 }
117
118 static std::string ToHex(std::array<uint8_t, DigestSize> const& digest)
119 {
120 std::ostringstream oss;
121 for (auto b: digest)
122 oss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(b);
123 return oss.str();
124 }
125
126 static std::string Hash(void const* data, size_t len)
127 {
128 Sha256 hasher;
129 hasher.Update(data, len);
130 return ToHex(hasher.Finalize());
131 }
132
133 static std::string Hash(std::string_view data)
134 {
135 return Hash(data.data(), data.size());
136 }
137
138 private:
139 static constexpr std::array<uint32_t, 64> K = {
140 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
141 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
142 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
143 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
144 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
145 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
146 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
147 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
148 };
149
150 static uint32_t RotateRight(uint32_t x, int n)
151 {
152 return (x >> n) | (x << (32 - n));
153 }
154
155 static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
156 {
157 return (x & y) ^ (~x & z);
158 }
159
160 static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
161 {
162 return (x & y) ^ (x & z) ^ (y & z);
163 }
164
165 static uint32_t Sigma0(uint32_t x)
166 {
167 return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22);
168 }
169
170 static uint32_t Sigma1(uint32_t x)
171 {
172 return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25);
173 }
174
175 static uint32_t LowerSigma0(uint32_t x)
176 {
177 return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
178 }
179
180 static uint32_t LowerSigma1(uint32_t x)
181 {
182 return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
183 }
184
185 void ProcessBlock(uint8_t const* block)
186 {
187 std::array<uint32_t, 64> W {};
188
189 // Prepare message schedule
190 for (size_t i = 0; i < 16; ++i)
191 {
192 W[i] = (static_cast<uint32_t>(block[i * 4]) << 24) | (static_cast<uint32_t>(block[(i * 4) + 1]) << 16)
193 | (static_cast<uint32_t>(block[(i * 4) + 2]) << 8) | static_cast<uint32_t>(block[(i * 4) + 3]);
194 }
195 for (size_t i = 16; i < 64; ++i)
196 W[i] = LowerSigma1(W[i - 2]) + W[i - 7] + LowerSigma0(W[i - 15]) + W[i - 16];
197
198 // Working variables
199 uint32_t a = _state[0];
200 uint32_t b = _state[1];
201 uint32_t c = _state[2];
202 uint32_t d = _state[3];
203 uint32_t e = _state[4];
204 uint32_t f = _state[5];
205 uint32_t g = _state[6];
206 uint32_t h = _state[7];
207
208 // Compression
209 for (size_t i = 0; i < 64; ++i)
210 {
211 uint32_t const T1 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
212 uint32_t const T2 = Sigma0(a) + Maj(a, b, c);
213 h = g;
214 g = f;
215 f = e;
216 e = d + T1;
217 d = c;
218 c = b;
219 b = a;
220 a = T1 + T2;
221 }
222
223 _state[0] += a;
224 _state[1] += b;
225 _state[2] += c;
226 _state[3] += d;
227 _state[4] += e;
228 _state[5] += f;
229 _state[6] += g;
230 _state[7] += h;
231 }
232
233 std::array<uint32_t, 8> _state {};
234 std::array<uint8_t, BlockSize> _buffer {};
235 size_t _bufferLen = 0;
236 uint64_t _count = 0;
237};
238
239} // namespace Lightweight::SqlBackup
Simple SHA-256 implementation for backup integrity verification.
Definition Sha256.hpp:18