M5Utility 0.2.0 git rev:301a6b5
Loading...
Searching...
No Matches
sha1.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UTILITY_SHA1_HPP
11#define M5_UTILITY_SHA1_HPP
12
13#include <cstdint>
14#include <cstring>
15#include "../stl/byteswap.hpp"
16
17namespace m5 {
18namespace utility {
19
25class SHA1 {
26public:
27 SHA1()
28 {
29 }
30
31 void init()
32 {
33 _state[0] = 0x67452301;
34 _state[1] = 0xEFCDAB89;
35 _state[2] = 0x98BADCFE;
36 _state[3] = 0x10325476;
37 _state[4] = 0xC3D2E1F0;
38 _count = 0;
39 _bufferLen = 0;
40 memset(_buffer, 0, sizeof(_buffer));
41 }
42
43 void update(const uint8_t* data, size_t len)
44 {
45 // Also makes update(nullptr, 0) legal: memcpy with a null source is UB even when len is 0
46 if (len == 0) {
47 return;
48 }
49 _count += static_cast<uint64_t>(len) << 3;
50 size_t fill{64 - _bufferLen};
51
52 if (len >= fill) {
53 memcpy(_buffer + _bufferLen, data, fill);
54 transform(_state, _buffer);
55 data += fill;
56 len -= fill;
57 _bufferLen = 0;
58
59 while (len >= 64) {
60 transform(_state, data);
61 data += 64;
62 len -= 64;
63 }
64 }
65
66 memcpy(_buffer + _bufferLen, data, len);
67 _bufferLen += len;
68 }
69
70 void finalize(uint8_t digest[20])
71 {
72 uint8_t padding[64]{0x80};
73 uint8_t length[8]{};
74 uint64_t count_be = m5::stl::byteswap(_count);
75 memcpy(length, &count_be, 8);
76
77 size_t padLen = (_bufferLen < 56) ? (56 - _bufferLen) : (120 - _bufferLen);
78 update(padding, padLen);
79 update(length, 8);
80
81 for (size_t i = 0; i < 5; ++i) {
82 uint32_t be = m5::stl::byteswap(_state[i]);
83 memcpy(digest + i * 4, &be, 4);
84 }
85 }
86
87 static void sha1(uint8_t digest[20], const uint8_t* data, size_t len)
88 {
89 SHA1 ctx;
90 ctx.update(data, len);
91 ctx.finalize(digest);
92 }
93
94private:
95 void transform(uint32_t state[5], const uint8_t buffer[64])
96 {
97 uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
98 uint32_t block[80];
99
100 for (int i = 0; i < 16; ++i) {
101 block[i] = (uint32_t(buffer[i * 4 + 0]) << 24) | (uint32_t(buffer[i * 4 + 1]) << 16) |
102 (uint32_t(buffer[i * 4 + 2]) << 8) | (uint32_t(buffer[i * 4 + 3]));
103 }
104 for (int i = 16; i < 80; ++i) {
105 block[i] = rol(block[i - 3] ^ block[i - 8] ^ block[i - 14] ^ block[i - 16], 1);
106 }
107
108 for (int i = 0; i < 80; ++i) {
109 uint32_t f, k;
110 if (i < 20) {
111 f = (b & c) | ((~b) & d);
112 k = 0x5A827999;
113 } else if (i < 40) {
114 f = b ^ c ^ d;
115 k = 0x6ED9EBA1;
116 } else if (i < 60) {
117 f = (b & c) | (b & d) | (c & d);
118 k = 0x8F1BBCDC;
119 } else {
120 f = b ^ c ^ d;
121 k = 0xCA62C1D6;
122 }
123
124 uint32_t temp = rol(a, 5) + f + e + k + block[i];
125 e = d;
126 d = c;
127 c = rol(b, 30);
128 b = a;
129 a = temp;
130 }
131
132 state[0] += a;
133 state[1] += b;
134 state[2] += c;
135 state[3] += d;
136 state[4] += e;
137 }
138
139 inline uint32_t rol(uint32_t value, uint32_t bits)
140 {
141 return (value << bits) | (value >> (32 - bits));
142 }
143
144 uint32_t _state[5]{0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
145 uint64_t _count{};
146 uint8_t _buffer[64]{};
147 size_t _bufferLen{};
148};
149
150} // namespace utility
151} // namespace m5
152#endif
std::byteswap for less than C++23
constexpr T byteswap(T v) noexcept
byteswap for integral type
Definition byteswap.hpp:193
Top level namespace of M5.
Definition base64.cpp:39
For utilities.