/src/qtbase/src/3rdparty/sha1/sha1.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Based on the public domain implementation of the SHA-1 algorithm by Dominik Reichl |
2 | | // |
3 | | // Copyright (C) Dominik Reichl <dominik.reichl@t-online.de> |
4 | | // Copyright (C) 2016 The Qt Company Ltd. |
5 | | // |
6 | | // SPDX-License-Identifier: LicenseRef-SHA1-Public-Domain |
7 | | |
8 | | #include <QtCore/qendian.h> |
9 | | |
10 | | #ifdef Q_CC_MSVC |
11 | | # include <stdlib.h> |
12 | | #endif |
13 | | |
14 | | QT_BEGIN_NAMESPACE |
15 | | |
16 | | // Test Vectors (from FIPS PUB 180-1) |
17 | | // |
18 | | // SHA1("abc") = |
19 | | // A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D |
20 | | // |
21 | | // SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = |
22 | | // 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 |
23 | | // |
24 | | // SHA1(A million repetitions of "a") = |
25 | | // 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F |
26 | | // |
27 | | |
28 | | |
29 | | // #define or #undef this, if you want the to wipe all |
30 | | // temporary variables after processing |
31 | | #define SHA1_WIPE_VARIABLES |
32 | | |
33 | | |
34 | | struct Sha1State |
35 | | { |
36 | | quint32 h0; |
37 | | quint32 h1; |
38 | | quint32 h2; |
39 | | quint32 h3; |
40 | | quint32 h4; |
41 | | |
42 | | quint64 messageSize; |
43 | | unsigned char buffer[64]; |
44 | | }; |
45 | | |
46 | | |
47 | | typedef union |
48 | | { |
49 | | quint8 bytes[64]; |
50 | | quint32 words[16]; |
51 | | } Sha1Chunk; |
52 | | |
53 | | static inline quint32 rol32(quint32 value, unsigned int shift) |
54 | 0 | { |
55 | | #ifdef Q_CC_MSVC |
56 | | return _rotl(value, shift); |
57 | | #else |
58 | 0 | return ((value << shift) | (value >> (32 - shift))); |
59 | 0 | #endif |
60 | 0 | } |
61 | | |
62 | | static inline quint32 sha1Word(Sha1Chunk *chunk, const uint position) |
63 | 0 | { |
64 | 0 | return (chunk->words[position & 0xf] = rol32( chunk->words[(position+13) & 0xf] |
65 | 0 | ^ chunk->words[(position+ 8) & 0xf] |
66 | 0 | ^ chunk->words[(position+ 2) & 0xf] |
67 | 0 | ^ chunk->words[(position) & 0xf], 1)); |
68 | 0 | } |
69 | | |
70 | | static inline void sha1Round0(Sha1Chunk *chunk, const uint position, |
71 | | quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) |
72 | 0 | { |
73 | 0 | z += ((( w & (x ^ y)) ^ y) + chunk->words[position] + 0x5A827999 + rol32(v, 5)); |
74 | 0 | w = rol32(w, 30); |
75 | 0 | } |
76 | | |
77 | | static inline void sha1Round1(Sha1Chunk *chunk, const uint position, |
78 | | quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) |
79 | 0 | { |
80 | 0 | z += ((( w & (x ^ y)) ^ y) + sha1Word(chunk,position) + 0x5A827999 + rol32(v, 5)); |
81 | 0 | w = rol32(w, 30); |
82 | 0 | } |
83 | | |
84 | | static inline void sha1Round2(Sha1Chunk *chunk, const uint position, |
85 | | quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) |
86 | 0 | { |
87 | 0 | z += (( w ^ x ^ y) + sha1Word(chunk, position) + 0x6ED9EBA1 + rol32(v, 5)); |
88 | 0 | w = rol32(w, 30); |
89 | 0 | } |
90 | | |
91 | | static inline void sha1Round3(Sha1Chunk *chunk, const uint position, |
92 | | quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) |
93 | 0 | { |
94 | 0 | z += (((( w | x) & y) | (w & x)) + sha1Word(chunk, position) + 0x8F1BBCDC + rol32(v, 5)); |
95 | 0 | w = rol32(w, 30); |
96 | 0 | } |
97 | | |
98 | | static inline void sha1Round4(Sha1Chunk *chunk, const uint position, |
99 | | quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) |
100 | 0 | { |
101 | 0 | z += ((w ^ x ^ y) + sha1Word(chunk, position) + 0xCA62C1D6 + rol32(v, 5)); |
102 | 0 | w = rol32(w, 30); |
103 | 0 | } |
104 | | |
105 | | static inline void sha1ProcessChunk(Sha1State *state, const unsigned char *buffer) |
106 | 0 | { |
107 | | // Copy state[] to working vars |
108 | 0 | quint32 a = state->h0; |
109 | 0 | quint32 b = state->h1; |
110 | 0 | quint32 c = state->h2; |
111 | 0 | quint32 d = state->h3; |
112 | 0 | quint32 e = state->h4; |
113 | |
|
114 | 0 | quint8 chunkBuffer[64]; |
115 | 0 | memcpy(chunkBuffer, buffer, 64); |
116 | |
|
117 | 0 | Sha1Chunk *chunk = reinterpret_cast<Sha1Chunk*>(&chunkBuffer); |
118 | |
|
119 | 0 | for (int i = 0; i < 16; ++i) |
120 | 0 | chunk->words[i] = qFromBigEndian(chunk->words[i]); |
121 | |
|
122 | 0 | sha1Round0(chunk, 0, a,b,c,d,e); sha1Round0(chunk, 1, e,a,b,c,d); sha1Round0(chunk, 2, d,e,a,b,c); sha1Round0(chunk, 3, c,d,e,a,b); |
123 | 0 | sha1Round0(chunk, 4, b,c,d,e,a); sha1Round0(chunk, 5, a,b,c,d,e); sha1Round0(chunk, 6, e,a,b,c,d); sha1Round0(chunk, 7, d,e,a,b,c); |
124 | 0 | sha1Round0(chunk, 8, c,d,e,a,b); sha1Round0(chunk, 9, b,c,d,e,a); sha1Round0(chunk, 10, a,b,c,d,e); sha1Round0(chunk, 11, e,a,b,c,d); |
125 | 0 | sha1Round0(chunk, 12, d,e,a,b,c); sha1Round0(chunk, 13, c,d,e,a,b); sha1Round0(chunk, 14, b,c,d,e,a); sha1Round0(chunk, 15, a,b,c,d,e); |
126 | 0 | sha1Round1(chunk, 16, e,a,b,c,d); sha1Round1(chunk, 17, d,e,a,b,c); sha1Round1(chunk, 18, c,d,e,a,b); sha1Round1(chunk, 19, b,c,d,e,a); |
127 | 0 | sha1Round2(chunk, 20, a,b,c,d,e); sha1Round2(chunk, 21, e,a,b,c,d); sha1Round2(chunk, 22, d,e,a,b,c); sha1Round2(chunk, 23, c,d,e,a,b); |
128 | 0 | sha1Round2(chunk, 24, b,c,d,e,a); sha1Round2(chunk, 25, a,b,c,d,e); sha1Round2(chunk, 26, e,a,b,c,d); sha1Round2(chunk, 27, d,e,a,b,c); |
129 | 0 | sha1Round2(chunk, 28, c,d,e,a,b); sha1Round2(chunk, 29, b,c,d,e,a); sha1Round2(chunk, 30, a,b,c,d,e); sha1Round2(chunk, 31, e,a,b,c,d); |
130 | 0 | sha1Round2(chunk, 32, d,e,a,b,c); sha1Round2(chunk, 33, c,d,e,a,b); sha1Round2(chunk, 34, b,c,d,e,a); sha1Round2(chunk, 35, a,b,c,d,e); |
131 | 0 | sha1Round2(chunk, 36, e,a,b,c,d); sha1Round2(chunk, 37, d,e,a,b,c); sha1Round2(chunk, 38, c,d,e,a,b); sha1Round2(chunk, 39, b,c,d,e,a); |
132 | 0 | sha1Round3(chunk, 40, a,b,c,d,e); sha1Round3(chunk, 41, e,a,b,c,d); sha1Round3(chunk, 42, d,e,a,b,c); sha1Round3(chunk, 43, c,d,e,a,b); |
133 | 0 | sha1Round3(chunk, 44, b,c,d,e,a); sha1Round3(chunk, 45, a,b,c,d,e); sha1Round3(chunk, 46, e,a,b,c,d); sha1Round3(chunk, 47, d,e,a,b,c); |
134 | 0 | sha1Round3(chunk, 48, c,d,e,a,b); sha1Round3(chunk, 49, b,c,d,e,a); sha1Round3(chunk, 50, a,b,c,d,e); sha1Round3(chunk, 51, e,a,b,c,d); |
135 | 0 | sha1Round3(chunk, 52, d,e,a,b,c); sha1Round3(chunk, 53, c,d,e,a,b); sha1Round3(chunk, 54, b,c,d,e,a); sha1Round3(chunk, 55, a,b,c,d,e); |
136 | 0 | sha1Round3(chunk, 56, e,a,b,c,d); sha1Round3(chunk, 57, d,e,a,b,c); sha1Round3(chunk, 58, c,d,e,a,b); sha1Round3(chunk, 59, b,c,d,e,a); |
137 | 0 | sha1Round4(chunk, 60, a,b,c,d,e); sha1Round4(chunk, 61, e,a,b,c,d); sha1Round4(chunk, 62, d,e,a,b,c); sha1Round4(chunk, 63, c,d,e,a,b); |
138 | 0 | sha1Round4(chunk, 64, b,c,d,e,a); sha1Round4(chunk, 65, a,b,c,d,e); sha1Round4(chunk, 66, e,a,b,c,d); sha1Round4(chunk, 67, d,e,a,b,c); |
139 | 0 | sha1Round4(chunk, 68, c,d,e,a,b); sha1Round4(chunk, 69, b,c,d,e,a); sha1Round4(chunk, 70, a,b,c,d,e); sha1Round4(chunk, 71, e,a,b,c,d); |
140 | 0 | sha1Round4(chunk, 72, d,e,a,b,c); sha1Round4(chunk, 73, c,d,e,a,b); sha1Round4(chunk, 74, b,c,d,e,a); sha1Round4(chunk, 75, a,b,c,d,e); |
141 | 0 | sha1Round4(chunk, 76, e,a,b,c,d); sha1Round4(chunk, 77, d,e,a,b,c); sha1Round4(chunk, 78, c,d,e,a,b); sha1Round4(chunk, 79, b,c,d,e,a); |
142 | | |
143 | | // Add the working vars back into state |
144 | 0 | state->h0 += a; |
145 | 0 | state->h1 += b; |
146 | 0 | state->h2 += c; |
147 | 0 | state->h3 += d; |
148 | 0 | state->h4 += e; |
149 | | |
150 | | // Wipe variables |
151 | 0 | #ifdef SHA1_WIPE_VARIABLES |
152 | 0 | a = b = c = d = e = 0; |
153 | 0 | memset(chunkBuffer, 0, 64); |
154 | 0 | #endif |
155 | 0 | } |
156 | | |
157 | | static inline void sha1InitState(Sha1State *state) |
158 | 0 | { |
159 | 0 | state->h0 = 0x67452301; |
160 | 0 | state->h1 = 0xEFCDAB89; |
161 | 0 | state->h2 = 0x98BADCFE; |
162 | 0 | state->h3 = 0x10325476; |
163 | 0 | state->h4 = 0xC3D2E1F0; |
164 | |
|
165 | 0 | state->messageSize = 0; |
166 | 0 | } |
167 | | |
168 | | static inline void sha1Update(Sha1State *state, const unsigned char *data, qint64 len) |
169 | 0 | { |
170 | 0 | quint32 rest = static_cast<quint32>(state->messageSize & Q_UINT64_C(63)); |
171 | |
|
172 | 0 | quint64 availableData = static_cast<quint64>(len) + static_cast<quint64>(rest); |
173 | 0 | state->messageSize += len; |
174 | |
|
175 | 0 | if (availableData < Q_UINT64_C(64)) { |
176 | 0 | memcpy(&state->buffer[rest], &data[0], len); |
177 | |
|
178 | 0 | } else { |
179 | 0 | qint64 i = static_cast<qint64>(64 - rest); |
180 | 0 | memcpy(&state->buffer[rest], &data[0], static_cast<qint32>(i)); |
181 | 0 | sha1ProcessChunk(state, state->buffer); |
182 | |
|
183 | 0 | qint64 lastI = len - ((len + rest) & Q_INT64_C(63)); |
184 | 0 | for( ; i < lastI; i += 64) |
185 | 0 | sha1ProcessChunk(state, &data[i]); |
186 | |
|
187 | 0 | memcpy(&state->buffer[0], &data[i], len - i); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | static inline void sha1FinalizeState(Sha1State *state) |
192 | 0 | { |
193 | 0 | quint64 messageSize = state->messageSize; |
194 | 0 | unsigned char sizeInBits[8]; |
195 | 0 | qToBigEndian(messageSize << 3, sizeInBits); |
196 | |
|
197 | 0 | sha1Update(state, (const unsigned char *)"\200", 1); |
198 | |
|
199 | 0 | unsigned char zero[64]; |
200 | 0 | memset(zero, 0, 64); |
201 | 0 | if (static_cast<int>(messageSize & 63) > 56 - 1) { |
202 | 0 | sha1Update(state, zero, 64 - 1 - static_cast<int>(messageSize & 63)); |
203 | 0 | sha1Update(state, zero, 64 - 8); |
204 | 0 | } else { |
205 | 0 | sha1Update(state, zero, 64 - 1 - 8 - static_cast<int>(messageSize & 63)); |
206 | 0 | } |
207 | |
|
208 | 0 | sha1Update(state, sizeInBits, 8); |
209 | 0 | #ifdef SHA1_WIPE_VARIABLES |
210 | 0 | memset(state->buffer, 0, 64); |
211 | 0 | memset(zero, 0, 64); |
212 | 0 | state->messageSize = 0; |
213 | 0 | #endif |
214 | 0 | } |
215 | | |
216 | | static inline void sha1ToHash(Sha1State *state, unsigned char* buffer) |
217 | 0 | { |
218 | 0 | qToBigEndian(state->h0, buffer); |
219 | 0 | qToBigEndian(state->h1, buffer + 4); |
220 | 0 | qToBigEndian(state->h2, buffer + 8); |
221 | 0 | qToBigEndian(state->h3, buffer + 12); |
222 | 0 | qToBigEndian(state->h4, buffer + 16); |
223 | 0 | } |
224 | | |
225 | | QT_END_NAMESPACE |