Coverage Report

Created: 2022-05-20 06:13

/src/serenity/Userland/Libraries/LibCrypto/Hash/SHA2.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Types.h>
8
#include <LibCrypto/Hash/SHA2.h>
9
10
namespace Crypto {
11
namespace Hash {
12
0
constexpr static auto ROTRIGHT(u32 a, size_t b) { return (a >> b) | (a << (32 - b)); }
13
0
constexpr static auto CH(u32 x, u32 y, u32 z) { return (x & y) ^ (z & ~x); }
14
0
constexpr static auto MAJ(u32 x, u32 y, u32 z) { return (x & y) ^ (x & z) ^ (y & z); }
15
0
constexpr static auto EP0(u32 x) { return ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22); }
16
0
constexpr static auto EP1(u32 x) { return ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25); }
17
0
constexpr static auto SIGN0(u32 x) { return ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ (x >> 3); }
18
0
constexpr static auto SIGN1(u32 x) { return ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ (x >> 10); }
19
20
0
constexpr static auto ROTRIGHT(u64 a, size_t b) { return (a >> b) | (a << (64 - b)); }
21
0
constexpr static auto CH(u64 x, u64 y, u64 z) { return (x & y) ^ (z & ~x); }
22
0
constexpr static auto MAJ(u64 x, u64 y, u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
23
0
constexpr static auto EP0(u64 x) { return ROTRIGHT(x, 28) ^ ROTRIGHT(x, 34) ^ ROTRIGHT(x, 39); }
24
0
constexpr static auto EP1(u64 x) { return ROTRIGHT(x, 14) ^ ROTRIGHT(x, 18) ^ ROTRIGHT(x, 41); }
25
0
constexpr static auto SIGN0(u64 x) { return ROTRIGHT(x, 1) ^ ROTRIGHT(x, 8) ^ (x >> 7); }
26
0
constexpr static auto SIGN1(u64 x) { return ROTRIGHT(x, 19) ^ ROTRIGHT(x, 61) ^ (x >> 6); }
27
28
inline void SHA256::transform(u8 const* data)
29
0
{
30
0
    u32 m[64];
31
32
0
    size_t i = 0;
33
0
    for (size_t j = 0; i < 16; ++i, j += 4) {
34
0
        m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | data[j + 3];
35
0
    }
36
37
0
    for (; i < BlockSize; ++i) {
38
0
        m[i] = SIGN1(m[i - 2]) + m[i - 7] + SIGN0(m[i - 15]) + m[i - 16];
39
0
    }
40
41
0
    auto a = m_state[0], b = m_state[1],
42
0
         c = m_state[2], d = m_state[3],
43
0
         e = m_state[4], f = m_state[5],
44
0
         g = m_state[6], h = m_state[7];
45
46
0
    for (size_t i = 0; i < Rounds; ++i) {
47
0
        auto temp0 = h + EP1(e) + CH(e, f, g) + SHA256Constants::RoundConstants[i] + m[i];
48
0
        auto temp1 = EP0(a) + MAJ(a, b, c);
49
0
        h = g;
50
0
        g = f;
51
0
        f = e;
52
0
        e = d + temp0;
53
0
        d = c;
54
0
        c = b;
55
0
        b = a;
56
0
        a = temp0 + temp1;
57
0
    }
58
59
0
    m_state[0] += a;
60
0
    m_state[1] += b;
61
0
    m_state[2] += c;
62
0
    m_state[3] += d;
63
0
    m_state[4] += e;
64
0
    m_state[5] += f;
65
0
    m_state[6] += g;
66
0
    m_state[7] += h;
67
0
}
68
69
void SHA256::update(u8 const* message, size_t length)
70
0
{
71
0
    for (size_t i = 0; i < length; ++i) {
72
0
        if (m_data_length == BlockSize) {
73
0
            transform(m_data_buffer);
74
0
            m_bit_length += 512;
75
0
            m_data_length = 0;
76
0
        }
77
0
        m_data_buffer[m_data_length++] = message[i];
78
0
    }
79
0
}
80
81
SHA256::DigestType SHA256::digest()
82
0
{
83
0
    auto digest = peek();
84
0
    reset();
85
0
    return digest;
86
0
}
87
88
SHA256::DigestType SHA256::peek()
89
0
{
90
0
    DigestType digest;
91
0
    size_t i = m_data_length;
92
93
0
    if (BlockSize == m_data_length) {
94
0
        transform(m_data_buffer);
95
0
        m_bit_length += BlockSize * 8;
96
0
        m_data_length = 0;
97
0
        i = 0;
98
0
    }
99
100
0
    if (m_data_length < FinalBlockDataSize) {
101
0
        m_data_buffer[i++] = 0x80;
102
0
        while (i < FinalBlockDataSize)
103
0
            m_data_buffer[i++] = 0x00;
104
105
0
    } else {
106
        // First, complete a block with some padding.
107
0
        m_data_buffer[i++] = 0x80;
108
0
        while (i < BlockSize)
109
0
            m_data_buffer[i++] = 0x00;
110
0
        transform(m_data_buffer);
111
112
        // Then start another block with BlockSize - 8 bytes of zeros
113
0
        __builtin_memset(m_data_buffer, 0, FinalBlockDataSize);
114
0
    }
115
116
    // append total message length
117
0
    m_bit_length += m_data_length * 8;
118
0
    m_data_buffer[BlockSize - 1] = m_bit_length;
119
0
    m_data_buffer[BlockSize - 2] = m_bit_length >> 8;
120
0
    m_data_buffer[BlockSize - 3] = m_bit_length >> 16;
121
0
    m_data_buffer[BlockSize - 4] = m_bit_length >> 24;
122
0
    m_data_buffer[BlockSize - 5] = m_bit_length >> 32;
123
0
    m_data_buffer[BlockSize - 6] = m_bit_length >> 40;
124
0
    m_data_buffer[BlockSize - 7] = m_bit_length >> 48;
125
0
    m_data_buffer[BlockSize - 8] = m_bit_length >> 56;
126
127
0
    transform(m_data_buffer);
128
129
    // SHA uses big-endian and we assume little-endian
130
    // FIXME: looks like a thing for AK::NetworkOrdered,
131
    //        but that doesn't support shifting operations
132
0
    for (size_t i = 0; i < 4; ++i) {
133
0
        digest.data[i + 0] = (m_state[0] >> (24 - i * 8)) & 0x000000ff;
134
0
        digest.data[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff;
135
0
        digest.data[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff;
136
0
        digest.data[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff;
137
0
        digest.data[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff;
138
0
        digest.data[i + 20] = (m_state[5] >> (24 - i * 8)) & 0x000000ff;
139
0
        digest.data[i + 24] = (m_state[6] >> (24 - i * 8)) & 0x000000ff;
140
0
        digest.data[i + 28] = (m_state[7] >> (24 - i * 8)) & 0x000000ff;
141
0
    }
142
0
    return digest;
143
0
}
144
145
inline void SHA384::transform(u8 const* data)
146
0
{
147
0
    u64 m[80];
148
149
0
    size_t i = 0;
150
0
    for (size_t j = 0; i < 16; ++i, j += 8) {
151
0
        m[i] = ((u64)data[j] << 56) | ((u64)data[j + 1] << 48) | ((u64)data[j + 2] << 40) | ((u64)data[j + 3] << 32) | ((u64)data[j + 4] << 24) | ((u64)data[j + 5] << 16) | ((u64)data[j + 6] << 8) | (u64)data[j + 7];
152
0
    }
153
154
0
    for (; i < Rounds; ++i) {
155
0
        m[i] = SIGN1(m[i - 2]) + m[i - 7] + SIGN0(m[i - 15]) + m[i - 16];
156
0
    }
157
158
0
    auto a = m_state[0], b = m_state[1],
159
0
         c = m_state[2], d = m_state[3],
160
0
         e = m_state[4], f = m_state[5],
161
0
         g = m_state[6], h = m_state[7];
162
163
0
    for (size_t i = 0; i < Rounds; ++i) {
164
        // Note : SHA384 uses the SHA512 constants.
165
0
        auto temp0 = h + EP1(e) + CH(e, f, g) + SHA512Constants::RoundConstants[i] + m[i];
166
0
        auto temp1 = EP0(a) + MAJ(a, b, c);
167
0
        h = g;
168
0
        g = f;
169
0
        f = e;
170
0
        e = d + temp0;
171
0
        d = c;
172
0
        c = b;
173
0
        b = a;
174
0
        a = temp0 + temp1;
175
0
    }
176
177
0
    m_state[0] += a;
178
0
    m_state[1] += b;
179
0
    m_state[2] += c;
180
0
    m_state[3] += d;
181
0
    m_state[4] += e;
182
0
    m_state[5] += f;
183
0
    m_state[6] += g;
184
0
    m_state[7] += h;
185
0
}
186
187
void SHA384::update(u8 const* message, size_t length)
188
0
{
189
0
    for (size_t i = 0; i < length; ++i) {
190
0
        if (m_data_length == BlockSize) {
191
0
            transform(m_data_buffer);
192
0
            m_bit_length += 1024;
193
0
            m_data_length = 0;
194
0
        }
195
0
        m_data_buffer[m_data_length++] = message[i];
196
0
    }
197
0
}
198
199
SHA384::DigestType SHA384::digest()
200
0
{
201
0
    auto digest = peek();
202
0
    reset();
203
0
    return digest;
204
0
}
205
206
SHA384::DigestType SHA384::peek()
207
0
{
208
0
    DigestType digest;
209
0
    size_t i = m_data_length;
210
211
0
    if (BlockSize == m_data_length) {
212
0
        transform(m_data_buffer);
213
0
        m_bit_length += BlockSize * 8;
214
0
        m_data_length = 0;
215
0
        i = 0;
216
0
    }
217
218
0
    if (m_data_length < FinalBlockDataSize) {
219
0
        m_data_buffer[i++] = 0x80;
220
0
        while (i < FinalBlockDataSize)
221
0
            m_data_buffer[i++] = 0x00;
222
223
0
    } else {
224
        // First, complete a block with some padding.
225
0
        m_data_buffer[i++] = 0x80;
226
0
        while (i < BlockSize)
227
0
            m_data_buffer[i++] = 0x00;
228
0
        transform(m_data_buffer);
229
230
        // Then start another block with BlockSize - 8 bytes of zeros
231
0
        __builtin_memset(m_data_buffer, 0, FinalBlockDataSize);
232
0
    }
233
234
    // append total message length
235
0
    m_bit_length += m_data_length * 8;
236
0
    m_data_buffer[BlockSize - 1] = m_bit_length;
237
0
    m_data_buffer[BlockSize - 2] = m_bit_length >> 8;
238
0
    m_data_buffer[BlockSize - 3] = m_bit_length >> 16;
239
0
    m_data_buffer[BlockSize - 4] = m_bit_length >> 24;
240
0
    m_data_buffer[BlockSize - 5] = m_bit_length >> 32;
241
0
    m_data_buffer[BlockSize - 6] = m_bit_length >> 40;
242
0
    m_data_buffer[BlockSize - 7] = m_bit_length >> 48;
243
0
    m_data_buffer[BlockSize - 8] = m_bit_length >> 56;
244
    // FIXME: Theoretically we should keep track of the number of bits as a u128, now we can only hash up to 2 EiB.
245
0
    m_data_buffer[BlockSize - 9] = 0;
246
0
    m_data_buffer[BlockSize - 10] = 0;
247
0
    m_data_buffer[BlockSize - 11] = 0;
248
0
    m_data_buffer[BlockSize - 12] = 0;
249
0
    m_data_buffer[BlockSize - 13] = 0;
250
0
    m_data_buffer[BlockSize - 14] = 0;
251
0
    m_data_buffer[BlockSize - 15] = 0;
252
0
    m_data_buffer[BlockSize - 16] = 0;
253
254
0
    transform(m_data_buffer);
255
256
    // SHA uses big-endian and we assume little-endian
257
    // FIXME: looks like a thing for AK::NetworkOrdered,
258
    //        but that doesn't support shifting operations
259
0
    for (size_t i = 0; i < 8; ++i) {
260
0
        digest.data[i + 0] = (m_state[0] >> (56 - i * 8)) & 0x000000ff;
261
0
        digest.data[i + 8] = (m_state[1] >> (56 - i * 8)) & 0x000000ff;
262
0
        digest.data[i + 16] = (m_state[2] >> (56 - i * 8)) & 0x000000ff;
263
0
        digest.data[i + 24] = (m_state[3] >> (56 - i * 8)) & 0x000000ff;
264
0
        digest.data[i + 32] = (m_state[4] >> (56 - i * 8)) & 0x000000ff;
265
0
        digest.data[i + 40] = (m_state[5] >> (56 - i * 8)) & 0x000000ff;
266
0
    }
267
0
    return digest;
268
0
}
269
270
inline void SHA512::transform(u8 const* data)
271
0
{
272
0
    u64 m[80];
273
274
0
    size_t i = 0;
275
0
    for (size_t j = 0; i < 16; ++i, j += 8) {
276
0
        m[i] = ((u64)data[j] << 56) | ((u64)data[j + 1] << 48) | ((u64)data[j + 2] << 40) | ((u64)data[j + 3] << 32) | ((u64)data[j + 4] << 24) | ((u64)data[j + 5] << 16) | ((u64)data[j + 6] << 8) | (u64)data[j + 7];
277
0
    }
278
279
0
    for (; i < Rounds; ++i) {
280
0
        m[i] = SIGN1(m[i - 2]) + m[i - 7] + SIGN0(m[i - 15]) + m[i - 16];
281
0
    }
282
283
0
    auto a = m_state[0], b = m_state[1],
284
0
         c = m_state[2], d = m_state[3],
285
0
         e = m_state[4], f = m_state[5],
286
0
         g = m_state[6], h = m_state[7];
287
288
0
    for (size_t i = 0; i < Rounds; ++i) {
289
0
        auto temp0 = h + EP1(e) + CH(e, f, g) + SHA512Constants::RoundConstants[i] + m[i];
290
0
        auto temp1 = EP0(a) + MAJ(a, b, c);
291
0
        h = g;
292
0
        g = f;
293
0
        f = e;
294
0
        e = d + temp0;
295
0
        d = c;
296
0
        c = b;
297
0
        b = a;
298
0
        a = temp0 + temp1;
299
0
    }
300
301
0
    m_state[0] += a;
302
0
    m_state[1] += b;
303
0
    m_state[2] += c;
304
0
    m_state[3] += d;
305
0
    m_state[4] += e;
306
0
    m_state[5] += f;
307
0
    m_state[6] += g;
308
0
    m_state[7] += h;
309
0
}
310
311
void SHA512::update(u8 const* message, size_t length)
312
0
{
313
0
    for (size_t i = 0; i < length; ++i) {
314
0
        if (m_data_length == BlockSize) {
315
0
            transform(m_data_buffer);
316
0
            m_bit_length += 1024;
317
0
            m_data_length = 0;
318
0
        }
319
0
        m_data_buffer[m_data_length++] = message[i];
320
0
    }
321
0
}
322
323
SHA512::DigestType SHA512::digest()
324
0
{
325
0
    auto digest = peek();
326
0
    reset();
327
0
    return digest;
328
0
}
329
330
SHA512::DigestType SHA512::peek()
331
0
{
332
0
    DigestType digest;
333
0
    size_t i = m_data_length;
334
335
0
    if (BlockSize == m_data_length) {
336
0
        transform(m_data_buffer);
337
0
        m_bit_length += BlockSize * 8;
338
0
        m_data_length = 0;
339
0
        i = 0;
340
0
    }
341
342
0
    if (m_data_length < FinalBlockDataSize) {
343
0
        m_data_buffer[i++] = 0x80;
344
0
        while (i < FinalBlockDataSize)
345
0
            m_data_buffer[i++] = 0x00;
346
347
0
    } else {
348
        // First, complete a block with some padding.
349
0
        m_data_buffer[i++] = 0x80;
350
0
        while (i < BlockSize)
351
0
            m_data_buffer[i++] = 0x00;
352
0
        transform(m_data_buffer);
353
354
        // Then start another block with BlockSize - 8 bytes of zeros
355
0
        __builtin_memset(m_data_buffer, 0, FinalBlockDataSize);
356
0
    }
357
358
    // append total message length
359
0
    m_bit_length += m_data_length * 8;
360
0
    m_data_buffer[BlockSize - 1] = m_bit_length;
361
0
    m_data_buffer[BlockSize - 2] = m_bit_length >> 8;
362
0
    m_data_buffer[BlockSize - 3] = m_bit_length >> 16;
363
0
    m_data_buffer[BlockSize - 4] = m_bit_length >> 24;
364
0
    m_data_buffer[BlockSize - 5] = m_bit_length >> 32;
365
0
    m_data_buffer[BlockSize - 6] = m_bit_length >> 40;
366
0
    m_data_buffer[BlockSize - 7] = m_bit_length >> 48;
367
0
    m_data_buffer[BlockSize - 8] = m_bit_length >> 56;
368
    // FIXME: Theoretically we should keep track of the number of bits as a u128, now we can only hash up to 2 EiB.
369
0
    m_data_buffer[BlockSize - 9] = 0;
370
0
    m_data_buffer[BlockSize - 10] = 0;
371
0
    m_data_buffer[BlockSize - 11] = 0;
372
0
    m_data_buffer[BlockSize - 12] = 0;
373
0
    m_data_buffer[BlockSize - 13] = 0;
374
0
    m_data_buffer[BlockSize - 14] = 0;
375
0
    m_data_buffer[BlockSize - 15] = 0;
376
0
    m_data_buffer[BlockSize - 16] = 0;
377
378
0
    transform(m_data_buffer);
379
380
    // SHA uses big-endian and we assume little-endian
381
    // FIXME: looks like a thing for AK::NetworkOrdered,
382
    //        but that doesn't support shifting operations
383
0
    for (size_t i = 0; i < 8; ++i) {
384
0
        digest.data[i + 0] = (m_state[0] >> (56 - i * 8)) & 0x000000ff;
385
0
        digest.data[i + 8] = (m_state[1] >> (56 - i * 8)) & 0x000000ff;
386
0
        digest.data[i + 16] = (m_state[2] >> (56 - i * 8)) & 0x000000ff;
387
0
        digest.data[i + 24] = (m_state[3] >> (56 - i * 8)) & 0x000000ff;
388
0
        digest.data[i + 32] = (m_state[4] >> (56 - i * 8)) & 0x000000ff;
389
0
        digest.data[i + 40] = (m_state[5] >> (56 - i * 8)) & 0x000000ff;
390
0
        digest.data[i + 48] = (m_state[6] >> (56 - i * 8)) & 0x000000ff;
391
0
        digest.data[i + 56] = (m_state[7] >> (56 - i * 8)) & 0x000000ff;
392
0
    }
393
0
    return digest;
394
0
}
395
}
396
}