1 | /* |
2 | * Copyright (C) 2011 Google Inc. All rights reserved. |
3 | * Copyright (C) 2015 Apple Inc. All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are |
7 | * met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above |
12 | * copyright notice, this list of conditions and the following disclaimer |
13 | * in the documentation and/or other materials provided with the |
14 | * distribution. |
15 | * * Neither the name of Google Inc. nor the names of its |
16 | * contributors may be used to endorse or promote products derived from |
17 | * this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include "config.h" |
33 | #include <wtf/SHA1.h> |
34 | |
35 | #include <wtf/Assertions.h> |
36 | #include <wtf/text/CString.h> |
37 | |
38 | namespace WTF { |
39 | |
40 | #if PLATFORM(COCOA) |
41 | |
42 | SHA1::SHA1() |
43 | { |
44 | ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
45 | CC_SHA1_Init(&m_context); |
46 | ALLOW_DEPRECATED_DECLARATIONS_END |
47 | } |
48 | |
49 | void SHA1::addBytes(const uint8_t* input, size_t length) |
50 | { |
51 | ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
52 | CC_SHA1_Update(&m_context, input, length); |
53 | ALLOW_DEPRECATED_DECLARATIONS_END |
54 | } |
55 | |
56 | void SHA1::computeHash(Digest& hash) |
57 | { |
58 | ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
59 | CC_SHA1_Final(hash.data(), &m_context); |
60 | ALLOW_DEPRECATED_DECLARATIONS_END |
61 | } |
62 | |
63 | #else |
64 | |
65 | // A straightforward SHA-1 implementation based on RFC 3174. |
66 | // http://www.ietf.org/rfc/rfc3174.txt |
67 | // The names of functions and variables (such as "a", "b", and "f") follow notations in RFC 3174. |
68 | |
69 | static inline uint32_t f(int t, uint32_t b, uint32_t c, uint32_t d) |
70 | { |
71 | ASSERT(t >= 0 && t < 80); |
72 | if (t < 20) |
73 | return (b & c) | ((~b) & d); |
74 | if (t < 40) |
75 | return b ^ c ^ d; |
76 | if (t < 60) |
77 | return (b & c) | (b & d) | (c & d); |
78 | return b ^ c ^ d; |
79 | } |
80 | |
81 | static inline uint32_t k(int t) |
82 | { |
83 | ASSERT(t >= 0 && t < 80); |
84 | if (t < 20) |
85 | return 0x5a827999; |
86 | if (t < 40) |
87 | return 0x6ed9eba1; |
88 | if (t < 60) |
89 | return 0x8f1bbcdc; |
90 | return 0xca62c1d6; |
91 | } |
92 | |
93 | static inline uint32_t rotateLeft(int n, uint32_t x) |
94 | { |
95 | ASSERT(n >= 0 && n < 32); |
96 | return (x << n) | (x >> (32 - n)); |
97 | } |
98 | |
99 | SHA1::SHA1() |
100 | { |
101 | reset(); |
102 | } |
103 | |
104 | void SHA1::addBytes(const uint8_t* input, size_t length) |
105 | { |
106 | while (length--) { |
107 | ASSERT(m_cursor < 64); |
108 | m_buffer[m_cursor++] = *input++; |
109 | ++m_totalBytes; |
110 | if (m_cursor == 64) |
111 | processBlock(); |
112 | } |
113 | } |
114 | |
115 | void SHA1::computeHash(Digest& digest) |
116 | { |
117 | finalize(); |
118 | |
119 | for (size_t i = 0; i < 5; ++i) { |
120 | // Treat hashValue as a big-endian value. |
121 | uint32_t hashValue = m_hash[i]; |
122 | for (int j = 0; j < 4; ++j) { |
123 | digest[4 * i + (3 - j)] = hashValue & 0xFF; |
124 | hashValue >>= 8; |
125 | } |
126 | } |
127 | |
128 | reset(); |
129 | } |
130 | |
131 | void SHA1::finalize() |
132 | { |
133 | ASSERT(m_cursor < 64); |
134 | m_buffer[m_cursor++] = 0x80; |
135 | if (m_cursor > 56) { |
136 | // Pad out to next block. |
137 | while (m_cursor < 64) |
138 | m_buffer[m_cursor++] = 0x00; |
139 | processBlock(); |
140 | } |
141 | |
142 | for (size_t i = m_cursor; i < 56; ++i) |
143 | m_buffer[i] = 0x00; |
144 | |
145 | // Write the length as a big-endian 64-bit value. |
146 | uint64_t bits = m_totalBytes * 8; |
147 | for (int i = 0; i < 8; ++i) { |
148 | m_buffer[56 + (7 - i)] = bits & 0xFF; |
149 | bits >>= 8; |
150 | } |
151 | m_cursor = 64; |
152 | processBlock(); |
153 | } |
154 | |
155 | void SHA1::processBlock() |
156 | { |
157 | ASSERT(m_cursor == 64); |
158 | |
159 | uint32_t w[80] = { 0 }; |
160 | for (int t = 0; t < 16; ++t) |
161 | w[t] = (m_buffer[t * 4] << 24) | (m_buffer[t * 4 + 1] << 16) | (m_buffer[t * 4 + 2] << 8) | m_buffer[t * 4 + 3]; |
162 | for (int t = 16; t < 80; ++t) |
163 | w[t] = rotateLeft(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]); |
164 | |
165 | uint32_t a = m_hash[0]; |
166 | uint32_t b = m_hash[1]; |
167 | uint32_t c = m_hash[2]; |
168 | uint32_t d = m_hash[3]; |
169 | uint32_t e = m_hash[4]; |
170 | |
171 | for (int t = 0; t < 80; ++t) { |
172 | uint32_t temp = rotateLeft(5, a) + f(t, b, c, d) + e + w[t] + k(t); |
173 | e = d; |
174 | d = c; |
175 | c = rotateLeft(30, b); |
176 | b = a; |
177 | a = temp; |
178 | } |
179 | |
180 | m_hash[0] += a; |
181 | m_hash[1] += b; |
182 | m_hash[2] += c; |
183 | m_hash[3] += d; |
184 | m_hash[4] += e; |
185 | |
186 | m_cursor = 0; |
187 | } |
188 | |
189 | void SHA1::reset() |
190 | { |
191 | m_cursor = 0; |
192 | m_totalBytes = 0; |
193 | m_hash[0] = 0x67452301; |
194 | m_hash[1] = 0xefcdab89; |
195 | m_hash[2] = 0x98badcfe; |
196 | m_hash[3] = 0x10325476; |
197 | m_hash[4] = 0xc3d2e1f0; |
198 | |
199 | // Clear the buffer after use in case it's sensitive. |
200 | memset(m_buffer, 0, sizeof(m_buffer)); |
201 | } |
202 | |
203 | #endif |
204 | |
205 | CString SHA1::hexDigest(const Digest& digest) |
206 | { |
207 | char* start = 0; |
208 | CString result = CString::newUninitialized(40, start); |
209 | char* buffer = start; |
210 | for (size_t i = 0; i < hashSize; ++i) { |
211 | snprintf(buffer, 3, "%02X" , digest.at(i)); |
212 | buffer += 2; |
213 | } |
214 | return result; |
215 | } |
216 | |
217 | CString SHA1::computeHexDigest() |
218 | { |
219 | Digest digest; |
220 | computeHash(digest); |
221 | return hexDigest(digest); |
222 | } |
223 | |
224 | } // namespace WTF |
225 | |