1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
/*
* Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Endian.h>
#include <AK/Memory.h>
#include <AK/Types.h>
#include <LibCrypto/Hash/SHA1.h>
namespace Crypto::Hash {
static constexpr auto ROTATE_LEFT(u32 value, size_t bits)
{
return (value << bits) | (value >> (32 - bits));
}
inline void SHA1::transform(u8 const* data)
{
u32 blocks[80];
for (size_t i = 0; i < 16; ++i)
blocks[i] = AK::convert_between_host_and_network_endian(((u32 const*)data)[i]);
// w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
for (size_t i = 16; i < Rounds; ++i)
blocks[i] = ROTATE_LEFT(blocks[i - 3] ^ blocks[i - 8] ^ blocks[i - 14] ^ blocks[i - 16], 1);
auto a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], e = m_state[4];
u32 f, k;
for (size_t i = 0; i < Rounds; ++i) {
if (i <= 19) {
f = (b & c) | ((~b) & d);
k = SHA1Constants::RoundConstants[0];
} else if (i <= 39) {
f = b ^ c ^ d;
k = SHA1Constants::RoundConstants[1];
} else if (i <= 59) {
f = (b & c) | (b & d) | (c & d);
k = SHA1Constants::RoundConstants[2];
} else {
f = b ^ c ^ d;
k = SHA1Constants::RoundConstants[3];
}
auto temp = ROTATE_LEFT(a, 5) + f + e + k + blocks[i];
e = d;
d = c;
c = ROTATE_LEFT(b, 30);
b = a;
a = temp;
}
m_state[0] += a;
m_state[1] += b;
m_state[2] += c;
m_state[3] += d;
m_state[4] += e;
// "security" measures, as if SHA1 is secure
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
secure_zero(blocks, 16 * sizeof(u32));
}
void SHA1::update(u8 const* message, size_t length)
{
for (size_t i = 0; i < length; ++i) {
if (m_data_length == BlockSize) {
transform(m_data_buffer);
m_bit_length += 512;
m_data_length = 0;
}
m_data_buffer[m_data_length++] = message[i];
}
}
SHA1::DigestType SHA1::digest()
{
auto digest = peek();
reset();
return digest;
}
SHA1::DigestType SHA1::peek()
{
DigestType digest;
size_t i = m_data_length;
// make a local copy of the data as we modify it
u8 data[BlockSize];
u32 state[5];
__builtin_memcpy(data, m_data_buffer, m_data_length);
__builtin_memcpy(state, m_state, 20);
if (BlockSize == m_data_length) {
transform(m_data_buffer);
m_bit_length += BlockSize * 8;
m_data_length = 0;
i = 0;
}
if (m_data_length < FinalBlockDataSize) {
m_data_buffer[i++] = 0x80;
while (i < FinalBlockDataSize)
m_data_buffer[i++] = 0x00;
} else {
// First, complete a block with some padding.
m_data_buffer[i++] = 0x80;
while (i < BlockSize)
m_data_buffer[i++] = 0x00;
transform(m_data_buffer);
// Then start another block with BlockSize - 8 bytes of zeros
__builtin_memset(m_data_buffer, 0, FinalBlockDataSize);
}
// append total message length
m_bit_length += m_data_length * 8;
m_data_buffer[BlockSize - 1] = m_bit_length;
m_data_buffer[BlockSize - 2] = m_bit_length >> 8;
m_data_buffer[BlockSize - 3] = m_bit_length >> 16;
m_data_buffer[BlockSize - 4] = m_bit_length >> 24;
m_data_buffer[BlockSize - 5] = m_bit_length >> 32;
m_data_buffer[BlockSize - 6] = m_bit_length >> 40;
m_data_buffer[BlockSize - 7] = m_bit_length >> 48;
m_data_buffer[BlockSize - 8] = m_bit_length >> 56;
transform(m_data_buffer);
for (size_t i = 0; i < 4; ++i) {
digest.data[i + 0] = (m_state[0] >> (24 - i * 8)) & 0x000000ff;
digest.data[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff;
digest.data[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff;
digest.data[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff;
digest.data[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff;
}
// restore the data
__builtin_memcpy(m_data_buffer, data, m_data_length);
__builtin_memcpy(m_state, state, 20);
return digest;
}
}
|