Line data Source code
1 : #ifndef THINGER_UTIL_SHA1_HPP
2 : #define THINGER_UTIL_SHA1_HPP
3 :
4 : #include <string>
5 : #include <cstring>
6 : #include <cstdint>
7 :
8 : namespace thinger::util {
9 :
10 : class sha1 {
11 : private:
12 : static constexpr uint32_t K[] = {
13 : 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
14 : };
15 :
16 : uint32_t H[5];
17 : unsigned char buffer[64];
18 : uint64_t count;
19 :
20 1727488 : static uint32_t rotate_left(uint32_t value, size_t count) {
21 1727488 : return (value << count) | (value >> (32 - count));
22 : }
23 :
24 7712 : void process_block() {
25 : uint32_t W[80];
26 :
27 : // Copy block to W[0..15]
28 131104 : for (int i = 0; i < 16; i++) {
29 123392 : W[i] = (buffer[i * 4] << 24) |
30 123392 : (buffer[i * 4 + 1] << 16) |
31 123392 : (buffer[i * 4 + 2] << 8) |
32 123392 : (buffer[i * 4 + 3]);
33 : }
34 :
35 : // Extend W[16..79]
36 501280 : for (int i = 16; i < 80; i++) {
37 493568 : W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
38 : }
39 :
40 7712 : uint32_t A = H[0];
41 7712 : uint32_t B = H[1];
42 7712 : uint32_t C = H[2];
43 7712 : uint32_t D = H[3];
44 7712 : uint32_t E = H[4];
45 :
46 : // Main loop
47 624672 : for (int i = 0; i < 80; i++) {
48 : uint32_t f, k;
49 616960 : if (i < 20) {
50 154240 : f = (B & C) | ((~B) & D);
51 154240 : k = K[0];
52 462720 : } else if (i < 40) {
53 154240 : f = B ^ C ^ D;
54 154240 : k = K[1];
55 308480 : } else if (i < 60) {
56 154240 : f = (B & C) | (B & D) | (C & D);
57 154240 : k = K[2];
58 : } else {
59 154240 : f = B ^ C ^ D;
60 154240 : k = K[3];
61 : }
62 :
63 616960 : uint32_t temp = rotate_left(A, 5) + f + E + k + W[i];
64 616960 : E = D;
65 616960 : D = C;
66 616960 : C = rotate_left(B, 30);
67 616960 : B = A;
68 616960 : A = temp;
69 : }
70 :
71 7712 : H[0] += A;
72 7712 : H[1] += B;
73 7712 : H[2] += C;
74 7712 : H[3] += D;
75 7712 : H[4] += E;
76 7712 : }
77 :
78 : public:
79 3856 : sha1() {
80 3856 : reset();
81 3856 : }
82 :
83 3856 : void reset() {
84 3856 : H[0] = 0x67452301;
85 3856 : H[1] = 0xEFCDAB89;
86 3856 : H[2] = 0x98BADCFE;
87 3856 : H[3] = 0x10325476;
88 3856 : H[4] = 0xC3D2E1F0;
89 3856 : count = 0;
90 3856 : memset(buffer, 0, sizeof(buffer));
91 3856 : }
92 :
93 3856 : void update(const unsigned char* data, size_t len) {
94 7712 : while (len > 0) {
95 3856 : size_t buffer_pos = count % 64;
96 3856 : size_t to_copy = std::min(len, 64 - buffer_pos);
97 :
98 3856 : memcpy(buffer + buffer_pos, data, to_copy);
99 3856 : count += to_copy;
100 3856 : data += to_copy;
101 3856 : len -= to_copy;
102 :
103 3856 : if ((count % 64) == 0) {
104 0 : process_block();
105 : }
106 : }
107 3856 : }
108 :
109 3856 : void update(const std::string& str) {
110 3856 : update(reinterpret_cast<const unsigned char*>(str.c_str()), str.length());
111 3856 : }
112 :
113 3856 : std::string finalize() {
114 : // Padding
115 3856 : size_t buffer_pos = count % 64;
116 3856 : buffer[buffer_pos++] = 0x80;
117 :
118 3856 : if (buffer_pos > 56) {
119 3856 : memset(buffer + buffer_pos, 0, 64 - buffer_pos);
120 3856 : process_block();
121 3856 : buffer_pos = 0;
122 : }
123 :
124 3856 : memset(buffer + buffer_pos, 0, 56 - buffer_pos);
125 :
126 : // Append length in bits
127 3856 : uint64_t bit_count = count * 8;
128 34704 : for (int i = 0; i < 8; i++) {
129 30848 : buffer[56 + i] = (bit_count >> ((7 - i) * 8)) & 0xFF;
130 : }
131 :
132 3856 : process_block();
133 :
134 : // Convert hash to string
135 3856 : std::string result;
136 3856 : result.reserve(20);
137 23136 : for (int i = 0; i < 5; i++) {
138 19280 : result += static_cast<char>((H[i] >> 24) & 0xFF);
139 19280 : result += static_cast<char>((H[i] >> 16) & 0xFF);
140 19280 : result += static_cast<char>((H[i] >> 8) & 0xFF);
141 19280 : result += static_cast<char>(H[i] & 0xFF);
142 : }
143 :
144 3856 : return result;
145 0 : }
146 :
147 3856 : static std::string hash(const std::string& input) {
148 3856 : sha1 hasher;
149 3856 : hasher.update(input);
150 7712 : return hasher.finalize();
151 : }
152 : };
153 :
154 : } // namespace thinger::util
155 :
156 : #endif // THINGER_UTIL_SHA1_HPP
|