1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "anglebase/sha1.h"
6
7#include <stddef.h>
8#include <stdint.h>
9#include <string.h>
10
11#include "anglebase/sys_byteorder.h"
12
13namespace angle
14{
15
16namespace base
17{
18
19// Implementation of SHA-1. Only handles data in byte-sized blocks,
20// which simplifies the code a fair bit.
21
22// Identifier names follow notation in FIPS PUB 180-3, where you'll
23// also find a description of the algorithm:
24// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
25
26// Usage example:
27//
28// SecureHashAlgorithm sha;
29// while(there is data to hash)
30// sha.Update(moredata, size of data);
31// sha.Final();
32// memcpy(somewhere, sha.Digest(), 20);
33//
34// to reuse the instance of sha, call sha.Init();
35
36// TODO(jhawkins): Replace this implementation with a per-platform
37// implementation using each platform's crypto library. See
38// http://crbug.com/47218
39
40class SecureHashAlgorithm
41{
42 public:
43 SecureHashAlgorithm() { Init(); }
44
45 static const int kDigestSizeBytes;
46
47 void Init();
48 void Update(const void *data, size_t nbytes);
49 void Final();
50
51 // 20 bytes of message digest.
52 const unsigned char *Digest() const { return reinterpret_cast<const unsigned char *>(H); }
53
54 private:
55 void Pad();
56 void Process();
57
58 uint32_t A, B, C, D, E;
59
60 uint32_t H[5];
61
62 union {
63 uint32_t W[80];
64 uint8_t M[64];
65 };
66
67 uint32_t cursor;
68 uint64_t l;
69};
70
71static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D)
72{
73 if (t < 20)
74 {
75 return (B & C) | ((~B) & D);
76 }
77 else if (t < 40)
78 {
79 return B ^ C ^ D;
80 }
81 else if (t < 60)
82 {
83 return (B & C) | (B & D) | (C & D);
84 }
85 else
86 {
87 return B ^ C ^ D;
88 }
89}
90
91static inline uint32_t S(uint32_t n, uint32_t X)
92{
93 return (X << n) | (X >> (32 - n));
94}
95
96static inline uint32_t K(uint32_t t)
97{
98 if (t < 20)
99 {
100 return 0x5a827999;
101 }
102 else if (t < 40)
103 {
104 return 0x6ed9eba1;
105 }
106 else if (t < 60)
107 {
108 return 0x8f1bbcdc;
109 }
110 else
111 {
112 return 0xca62c1d6;
113 }
114}
115
116const int SecureHashAlgorithm::kDigestSizeBytes = 20;
117
118void SecureHashAlgorithm::Init()
119{
120 A = 0;
121 B = 0;
122 C = 0;
123 D = 0;
124 E = 0;
125 cursor = 0;
126 l = 0;
127 H[0] = 0x67452301;
128 H[1] = 0xefcdab89;
129 H[2] = 0x98badcfe;
130 H[3] = 0x10325476;
131 H[4] = 0xc3d2e1f0;
132}
133
134void SecureHashAlgorithm::Final()
135{
136 Pad();
137 Process();
138
139 for (int t = 0; t < 5; ++t)
140 H[t] = ByteSwap(H[t]);
141}
142
143void SecureHashAlgorithm::Update(const void *data, size_t nbytes)
144{
145 const uint8_t *d = reinterpret_cast<const uint8_t *>(data);
146 while (nbytes--)
147 {
148 M[cursor++] = *d++;
149 if (cursor >= 64)
150 Process();
151 l += 8;
152 }
153}
154
155void SecureHashAlgorithm::Pad()
156{
157 M[cursor++] = 0x80;
158
159 if (cursor > 64 - 8)
160 {
161 // pad out to next block
162 while (cursor < 64)
163 M[cursor++] = 0;
164
165 Process();
166 }
167
168 while (cursor < 64 - 8)
169 M[cursor++] = 0;
170
171 M[cursor++] = (l >> 56) & 0xff;
172 M[cursor++] = (l >> 48) & 0xff;
173 M[cursor++] = (l >> 40) & 0xff;
174 M[cursor++] = (l >> 32) & 0xff;
175 M[cursor++] = (l >> 24) & 0xff;
176 M[cursor++] = (l >> 16) & 0xff;
177 M[cursor++] = (l >> 8) & 0xff;
178 M[cursor++] = l & 0xff;
179}
180
181void SecureHashAlgorithm::Process()
182{
183 uint32_t t;
184
185 // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
186
187 // a.
188 //
189 // W and M are in a union, so no need to memcpy.
190 // memcpy(W, M, sizeof(M));
191 for (t = 0; t < 16; ++t)
192 W[t] = ByteSwap(W[t]);
193
194 // b.
195 for (t = 16; t < 80; ++t)
196 W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
197
198 // c.
199 A = H[0];
200 B = H[1];
201 C = H[2];
202 D = H[3];
203 E = H[4];
204
205 // d.
206 for (t = 0; t < 80; ++t)
207 {
208 uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
209 E = D;
210 D = C;
211 C = S(30, B);
212 B = A;
213 A = TEMP;
214 }
215
216 // e.
217 H[0] += A;
218 H[1] += B;
219 H[2] += C;
220 H[3] += D;
221 H[4] += E;
222
223 cursor = 0;
224}
225
226std::string SHA1HashString(const std::string &str)
227{
228 char hash[SecureHashAlgorithm::kDigestSizeBytes];
229 SHA1HashBytes(reinterpret_cast<const unsigned char *>(str.c_str()), str.length(),
230 reinterpret_cast<unsigned char *>(hash));
231 return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes);
232}
233
234void SHA1HashBytes(const unsigned char *data, size_t len, unsigned char *hash)
235{
236 SecureHashAlgorithm sha;
237 sha.Update(data, len);
238 sha.Final();
239
240 memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes);
241}
242
243} // namespace base
244
245} // namespace angle
246