| 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 | { | 
| 55 | #ifdef Q_CC_MSVC | 
| 56 |     return _rotl(value, shift); | 
| 57 | #else | 
| 58 |     return ((value << shift) | (value >> (32 - shift))); | 
| 59 | #endif | 
| 60 | } | 
| 61 |  | 
| 62 | static inline quint32 sha1Word(Sha1Chunk *chunk, const uint position) | 
| 63 | { | 
| 64 |     return (chunk->words[position & 0xf] = rol32(  value: chunk->words[(position+13) & 0xf] | 
| 65 |                                                  ^ chunk->words[(position+ 8) & 0xf] | 
| 66 |                                                  ^ chunk->words[(position+ 2) & 0xf] | 
| 67 |                                                  ^ chunk->words[(position)    & 0xf], shift: 1)); | 
| 68 | } | 
| 69 |  | 
| 70 | static inline void sha1Round0(Sha1Chunk *chunk, const uint position, | 
| 71 |                               quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) | 
| 72 | { | 
| 73 |     z += ((( w & (x ^ y)) ^ y) + chunk->words[position] + 0x5A827999 + rol32(value: v, shift: 5)); | 
| 74 |     w = rol32(value: w, shift: 30); | 
| 75 | } | 
| 76 |  | 
| 77 | static inline void sha1Round1(Sha1Chunk *chunk, const uint position, | 
| 78 |                               quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) | 
| 79 | { | 
| 80 |     z += ((( w & (x ^ y)) ^ y) + sha1Word(chunk,position) + 0x5A827999 + rol32(value: v, shift: 5)); | 
| 81 |     w = rol32(value: w, shift: 30); | 
| 82 | } | 
| 83 |  | 
| 84 | static inline void sha1Round2(Sha1Chunk *chunk, const uint position, | 
| 85 |                               quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) | 
| 86 | { | 
| 87 |     z += (( w ^ x ^ y) + sha1Word(chunk, position) + 0x6ED9EBA1 + rol32(value: v, shift: 5)); | 
| 88 |     w = rol32(value: w, shift: 30); | 
| 89 | } | 
| 90 |  | 
| 91 | static inline void sha1Round3(Sha1Chunk *chunk, const uint position, | 
| 92 |                               quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) | 
| 93 | { | 
| 94 |     z += (((( w | x) & y) | (w & x)) + sha1Word(chunk, position) + 0x8F1BBCDC + rol32(value: v, shift: 5)); | 
| 95 |     w = rol32(value: w, shift: 30); | 
| 96 | } | 
| 97 |  | 
| 98 | static inline void sha1Round4(Sha1Chunk *chunk, const uint position, | 
| 99 |                               quint32 &v, quint32 &w, quint32 &x, quint32 &y, quint32 &z) | 
| 100 | { | 
| 101 |     z += ((w ^ x ^ y) + sha1Word(chunk, position) + 0xCA62C1D6 + rol32(value: v, shift: 5)); | 
| 102 |     w = rol32(value: w, shift: 30); | 
| 103 | } | 
| 104 |  | 
| 105 | static inline void sha1ProcessChunk(Sha1State *state, const unsigned char *buffer) | 
| 106 | { | 
| 107 |     // Copy state[] to working vars | 
| 108 |     quint32 a = state->h0; | 
| 109 |     quint32 b = state->h1; | 
| 110 |     quint32 c = state->h2; | 
| 111 |     quint32 d = state->h3; | 
| 112 |     quint32 e = state->h4; | 
| 113 |  | 
| 114 |     quint8 chunkBuffer[64]; | 
| 115 |     memcpy(dest: chunkBuffer, src: buffer, n: 64); | 
| 116 |  | 
| 117 |     Sha1Chunk *chunk = reinterpret_cast<Sha1Chunk*>(&chunkBuffer); | 
| 118 |  | 
| 119 |     for (int i = 0; i < 16; ++i) | 
| 120 |         chunk->words[i] = qFromBigEndian(source: chunk->words[i]); | 
| 121 |  | 
| 122 |     sha1Round0(chunk,  position: 0, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round0(chunk,  position: 1, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round0(chunk,  position: 2, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round0(chunk,  position: 3, v&: c,w&: d,x&: e,y&: a,z&: b); | 
| 123 |     sha1Round0(chunk,  position: 4, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round0(chunk,  position: 5, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round0(chunk,  position: 6, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round0(chunk,  position: 7, v&: d,w&: e,x&: a,y&: b,z&: c); | 
| 124 |     sha1Round0(chunk,  position: 8, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round0(chunk,  position: 9, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round0(chunk, position: 10, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round0(chunk, position: 11, v&: e,w&: a,x&: b,y&: c,z&: d); | 
| 125 |     sha1Round0(chunk, position: 12, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round0(chunk, position: 13, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round0(chunk, position: 14, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round0(chunk, position: 15, v&: a,w&: b,x&: c,y&: d,z&: e); | 
| 126 |     sha1Round1(chunk, position: 16, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round1(chunk, position: 17, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round1(chunk, position: 18, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round1(chunk, position: 19, v&: b,w&: c,x&: d,y&: e,z&: a); | 
| 127 |     sha1Round2(chunk, position: 20, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round2(chunk, position: 21, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round2(chunk, position: 22, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round2(chunk, position: 23, v&: c,w&: d,x&: e,y&: a,z&: b); | 
| 128 |     sha1Round2(chunk, position: 24, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round2(chunk, position: 25, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round2(chunk, position: 26, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round2(chunk, position: 27, v&: d,w&: e,x&: a,y&: b,z&: c); | 
| 129 |     sha1Round2(chunk, position: 28, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round2(chunk, position: 29, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round2(chunk, position: 30, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round2(chunk, position: 31, v&: e,w&: a,x&: b,y&: c,z&: d); | 
| 130 |     sha1Round2(chunk, position: 32, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round2(chunk, position: 33, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round2(chunk, position: 34, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round2(chunk, position: 35, v&: a,w&: b,x&: c,y&: d,z&: e); | 
| 131 |     sha1Round2(chunk, position: 36, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round2(chunk, position: 37, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round2(chunk, position: 38, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round2(chunk, position: 39, v&: b,w&: c,x&: d,y&: e,z&: a); | 
| 132 |     sha1Round3(chunk, position: 40, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round3(chunk, position: 41, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round3(chunk, position: 42, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round3(chunk, position: 43, v&: c,w&: d,x&: e,y&: a,z&: b); | 
| 133 |     sha1Round3(chunk, position: 44, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round3(chunk, position: 45, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round3(chunk, position: 46, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round3(chunk, position: 47, v&: d,w&: e,x&: a,y&: b,z&: c); | 
| 134 |     sha1Round3(chunk, position: 48, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round3(chunk, position: 49, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round3(chunk, position: 50, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round3(chunk, position: 51, v&: e,w&: a,x&: b,y&: c,z&: d); | 
| 135 |     sha1Round3(chunk, position: 52, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round3(chunk, position: 53, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round3(chunk, position: 54, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round3(chunk, position: 55, v&: a,w&: b,x&: c,y&: d,z&: e); | 
| 136 |     sha1Round3(chunk, position: 56, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round3(chunk, position: 57, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round3(chunk, position: 58, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round3(chunk, position: 59, v&: b,w&: c,x&: d,y&: e,z&: a); | 
| 137 |     sha1Round4(chunk, position: 60, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round4(chunk, position: 61, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round4(chunk, position: 62, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round4(chunk, position: 63, v&: c,w&: d,x&: e,y&: a,z&: b); | 
| 138 |     sha1Round4(chunk, position: 64, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round4(chunk, position: 65, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round4(chunk, position: 66, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round4(chunk, position: 67, v&: d,w&: e,x&: a,y&: b,z&: c); | 
| 139 |     sha1Round4(chunk, position: 68, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round4(chunk, position: 69, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round4(chunk, position: 70, v&: a,w&: b,x&: c,y&: d,z&: e); sha1Round4(chunk, position: 71, v&: e,w&: a,x&: b,y&: c,z&: d); | 
| 140 |     sha1Round4(chunk, position: 72, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round4(chunk, position: 73, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round4(chunk, position: 74, v&: b,w&: c,x&: d,y&: e,z&: a); sha1Round4(chunk, position: 75, v&: a,w&: b,x&: c,y&: d,z&: e); | 
| 141 |     sha1Round4(chunk, position: 76, v&: e,w&: a,x&: b,y&: c,z&: d); sha1Round4(chunk, position: 77, v&: d,w&: e,x&: a,y&: b,z&: c); sha1Round4(chunk, position: 78, v&: c,w&: d,x&: e,y&: a,z&: b); sha1Round4(chunk, position: 79, v&: b,w&: c,x&: d,y&: e,z&: a); | 
| 142 |  | 
| 143 |     // Add the working vars back into state | 
| 144 |     state->h0 += a; | 
| 145 |     state->h1 += b; | 
| 146 |     state->h2 += c; | 
| 147 |     state->h3 += d; | 
| 148 |     state->h4 += e; | 
| 149 |  | 
| 150 |     // Wipe variables | 
| 151 | #ifdef SHA1_WIPE_VARIABLES | 
| 152 |     a = b = c = d = e = 0; | 
| 153 |     memset(s: chunkBuffer, c: 0, n: 64); | 
| 154 | #endif | 
| 155 | } | 
| 156 |  | 
| 157 | static inline void sha1InitState(Sha1State *state) | 
| 158 | { | 
| 159 |     state->h0 = 0x67452301; | 
| 160 |     state->h1 = 0xEFCDAB89; | 
| 161 |     state->h2 = 0x98BADCFE; | 
| 162 |     state->h3 = 0x10325476; | 
| 163 |     state->h4 = 0xC3D2E1F0; | 
| 164 |  | 
| 165 |     state->messageSize = 0; | 
| 166 | } | 
| 167 |  | 
| 168 | static inline void sha1Update(Sha1State *state, const unsigned char *data, qint64 len) | 
| 169 | { | 
| 170 |     quint32 rest = static_cast<quint32>(state->messageSize & Q_UINT64_C(63)); | 
| 171 |  | 
| 172 |     quint64 availableData = static_cast<quint64>(len) + static_cast<quint64>(rest); | 
| 173 |     state->messageSize += len; | 
| 174 |  | 
| 175 |     if (availableData < Q_UINT64_C(64)) { | 
| 176 |         memcpy(dest: &state->buffer[rest], src: &data[0], n: len); | 
| 177 |  | 
| 178 |     } else { | 
| 179 |         qint64 i = static_cast<qint64>(64 - rest); | 
| 180 |         memcpy(dest: &state->buffer[rest], src: &data[0], n: static_cast<qint32>(i)); | 
| 181 |         sha1ProcessChunk(state, buffer: state->buffer); | 
| 182 |  | 
| 183 |         qint64 lastI = len - ((len + rest) & Q_INT64_C(63)); | 
| 184 |         for( ; i < lastI; i += 64) | 
| 185 |             sha1ProcessChunk(state, buffer: &data[i]); | 
| 186 |  | 
| 187 |         memcpy(dest: &state->buffer[0], src: &data[i], n: len - i); | 
| 188 |     } | 
| 189 | } | 
| 190 |  | 
| 191 | static inline void sha1FinalizeState(Sha1State *state) | 
| 192 | { | 
| 193 |     quint64 messageSize = state->messageSize; | 
| 194 |     unsigned char sizeInBits[8]; | 
| 195 |     qToBigEndian(src: messageSize << 3, dest: sizeInBits); | 
| 196 |  | 
| 197 |     sha1Update(state, data: (const unsigned char *)"\200" , len: 1); | 
| 198 |  | 
| 199 |     unsigned char zero[64]; | 
| 200 |     memset(s: zero, c: 0, n: 64); | 
| 201 |     if (static_cast<int>(messageSize & 63) > 56 - 1) { | 
| 202 |         sha1Update(state, data: zero, len: 64 - 1 - static_cast<int>(messageSize & 63)); | 
| 203 |         sha1Update(state, data: zero, len: 64 - 8); | 
| 204 |     } else { | 
| 205 |         sha1Update(state, data: zero, len: 64 - 1 - 8 - static_cast<int>(messageSize & 63)); | 
| 206 |     } | 
| 207 |  | 
| 208 |     sha1Update(state, data: sizeInBits, len: 8); | 
| 209 | #ifdef SHA1_WIPE_VARIABLES | 
| 210 |     memset(s: state->buffer, c: 0, n: 64); | 
| 211 |     memset(s: zero, c: 0, n: 64); | 
| 212 |     state->messageSize = 0; | 
| 213 | #endif | 
| 214 | } | 
| 215 |  | 
| 216 | static inline void sha1ToHash(Sha1State *state, unsigned char* buffer) | 
| 217 | { | 
| 218 |     qToBigEndian(src: state->h0, dest: buffer); | 
| 219 |     qToBigEndian(src: state->h1, dest: buffer + 4); | 
| 220 |     qToBigEndian(src: state->h2, dest: buffer + 8); | 
| 221 |     qToBigEndian(src: state->h3, dest: buffer + 12); | 
| 222 |     qToBigEndian(src: state->h4, dest: buffer + 16); | 
| 223 | } | 
| 224 |  | 
| 225 | QT_END_NAMESPACE | 
| 226 |  |