/src/resiprocate/rutil/Sha1.cxx
Line | Count | Source |
1 | | /* |
2 | | Original Source code contained this header: |
3 | | |
4 | | sha1.cpp - source code of |
5 | | |
6 | | ============ |
7 | | SHA-1 in C++ |
8 | | ============ |
9 | | |
10 | | 100% Public Domain. |
11 | | |
12 | | Original C Code |
13 | | -- Steve Reid <steve@edmweb.com> |
14 | | Small changes to fit into bglibs |
15 | | -- Bruce Guenter <bruce@untroubled.org> |
16 | | Translation to simpler C++ Code |
17 | | -- Volker Grabsch <vog@notjusthosting.com> |
18 | | */ |
19 | | |
20 | | #include "Sha1.hxx" |
21 | | #include <sstream> |
22 | | #include <iomanip> |
23 | | #include <fstream> |
24 | | |
25 | | using namespace resip; |
26 | | |
27 | | Sha1::Sha1() |
28 | 0 | { |
29 | 0 | reset(); |
30 | 0 | } |
31 | | |
32 | | |
33 | | void Sha1::update(const std::string &s) |
34 | 0 | { |
35 | 0 | std::istringstream is(s); |
36 | 0 | update(is); |
37 | 0 | } |
38 | | |
39 | | |
40 | | void Sha1::update(std::istream &is) |
41 | 0 | { |
42 | 0 | std::string rest_of_buffer; |
43 | 0 | read(is, rest_of_buffer, BLOCK_BYTES - (int)buffer.size()); |
44 | 0 | buffer += rest_of_buffer; |
45 | |
|
46 | 0 | while (is) |
47 | 0 | { |
48 | 0 | uint32_t block[BLOCK_INTS]; |
49 | 0 | buffer_to_block(buffer, block); |
50 | 0 | transform(block); |
51 | 0 | read(is, buffer, BLOCK_BYTES); |
52 | 0 | } |
53 | 0 | } |
54 | | |
55 | | |
56 | | /* |
57 | | * Add padding and return the message digest. |
58 | | */ |
59 | | |
60 | | std::string Sha1::final() |
61 | 0 | { |
62 | | /* Use input and create digest */ |
63 | 0 | createDigest(); |
64 | | |
65 | | /* Hex std::string */ |
66 | 0 | std::ostringstream result; |
67 | 0 | for (unsigned int i = 0; i < DIGEST_INTS; i++) |
68 | 0 | { |
69 | 0 | result << std::hex << std::setfill('0') << std::setw(8); |
70 | 0 | result << (digest[i] & 0xffffffff); |
71 | 0 | } |
72 | | |
73 | | /* Reset for next run */ |
74 | 0 | reset(); |
75 | |
|
76 | 0 | return result.str(); |
77 | 0 | } |
78 | | |
79 | | resip::Data Sha1::finalBin() |
80 | 0 | { |
81 | | /* Use input and create digest */ |
82 | 0 | createDigest(); |
83 | |
|
84 | 0 | resip::Data result(21, Data::Preallocate); // Data likes a NULL at the end use 21 instead of 20 |
85 | 0 | for (unsigned int i = 0; i < DIGEST_INTS; i++) |
86 | 0 | { |
87 | 0 | uint32_t digesttemp = htonl(digest[i]); |
88 | 0 | result.append((const char*)&digesttemp, sizeof(digest[0])); |
89 | 0 | } |
90 | | |
91 | | /* Reset for next run */ |
92 | 0 | reset(); |
93 | |
|
94 | 0 | return result; |
95 | 0 | } |
96 | | |
97 | | void Sha1::createDigest() |
98 | 0 | { |
99 | | /* Total number of hashed bits */ |
100 | 0 | uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; |
101 | | |
102 | | /* Padding */ |
103 | 0 | buffer += (char)0x80; |
104 | 0 | unsigned int orig_size = (unsigned int)buffer.size(); |
105 | 0 | while (buffer.size() < BLOCK_BYTES) |
106 | 0 | { |
107 | 0 | buffer += (char)0x00; |
108 | 0 | } |
109 | |
|
110 | 0 | uint32_t block[BLOCK_INTS]; |
111 | 0 | buffer_to_block(buffer, block); |
112 | |
|
113 | 0 | if (orig_size > BLOCK_BYTES - 8) |
114 | 0 | { |
115 | 0 | transform(block); |
116 | 0 | for (unsigned int i = 0; i < BLOCK_INTS - 2; i++) |
117 | 0 | { |
118 | 0 | block[i] = 0; |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | /* Append total_bits, split this uint64_t into two uint32_t */ |
123 | 0 | block[BLOCK_INTS - 1] = (uint32_t)total_bits; |
124 | 0 | block[BLOCK_INTS - 2] = (total_bits >> 32); |
125 | 0 | transform(block); |
126 | 0 | } |
127 | | |
128 | | std::string Sha1::from_file(const std::string &filename) |
129 | 0 | { |
130 | 0 | std::ifstream stream(filename.c_str(), std::ios::binary); |
131 | 0 | Sha1 checksum; |
132 | 0 | checksum.update(stream); |
133 | 0 | return checksum.final(); |
134 | 0 | } |
135 | | |
136 | | |
137 | | void Sha1::reset() |
138 | 0 | { |
139 | | /* SHA1 initialization constants */ |
140 | 0 | digest[0] = 0x67452301; |
141 | 0 | digest[1] = 0xefcdab89; |
142 | 0 | digest[2] = 0x98badcfe; |
143 | 0 | digest[3] = 0x10325476; |
144 | 0 | digest[4] = 0xc3d2e1f0; |
145 | | |
146 | | /* Reset counters */ |
147 | 0 | transforms = 0; |
148 | 0 | buffer = ""; |
149 | 0 | } |
150 | | |
151 | | |
152 | | /* |
153 | | * Hash a single 512-bit block. This is the core of the algorithm. |
154 | | */ |
155 | | |
156 | | void Sha1::transform(uint32_t block[BLOCK_BYTES]) |
157 | 0 | { |
158 | | /* Copy digest[] to working vars */ |
159 | 0 | uint32_t a = digest[0]; |
160 | 0 | uint32_t b = digest[1]; |
161 | 0 | uint32_t c = digest[2]; |
162 | 0 | uint32_t d = digest[3]; |
163 | 0 | uint32_t e = digest[4]; |
164 | | |
165 | | /* Help macros */ |
166 | 0 | #define rol(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits)))) |
167 | 0 | #define blk(i) (block[i&15] = rol(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1)) |
168 | | |
169 | | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ |
170 | 0 | #define R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v,5); w=rol(w,30); |
171 | 0 | #define R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk(i) + 0x5a827999 + rol(v,5); w=rol(w,30); |
172 | 0 | #define R2(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0x6ed9eba1 + rol(v,5); w=rol(w,30); |
173 | 0 | #define R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + blk(i) + 0x8f1bbcdc + rol(v,5); w=rol(w,30); |
174 | 0 | #define R4(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0xca62c1d6 + rol(v,5); w=rol(w,30); |
175 | | |
176 | | /* 4 rounds of 20 operations each. Loop unrolled. */ |
177 | 0 | R0(a,b,c,d,e, 0); |
178 | 0 | R0(e,a,b,c,d, 1); |
179 | 0 | R0(d,e,a,b,c, 2); |
180 | 0 | R0(c,d,e,a,b, 3); |
181 | 0 | R0(b,c,d,e,a, 4); |
182 | 0 | R0(a,b,c,d,e, 5); |
183 | 0 | R0(e,a,b,c,d, 6); |
184 | 0 | R0(d,e,a,b,c, 7); |
185 | 0 | R0(c,d,e,a,b, 8); |
186 | 0 | R0(b,c,d,e,a, 9); |
187 | 0 | R0(a,b,c,d,e,10); |
188 | 0 | R0(e,a,b,c,d,11); |
189 | 0 | R0(d,e,a,b,c,12); |
190 | 0 | R0(c,d,e,a,b,13); |
191 | 0 | R0(b,c,d,e,a,14); |
192 | 0 | R0(a,b,c,d,e,15); |
193 | 0 | R1(e,a,b,c,d,16); |
194 | 0 | R1(d,e,a,b,c,17); |
195 | 0 | R1(c,d,e,a,b,18); |
196 | 0 | R1(b,c,d,e,a,19); |
197 | 0 | R2(a,b,c,d,e,20); |
198 | 0 | R2(e,a,b,c,d,21); |
199 | 0 | R2(d,e,a,b,c,22); |
200 | 0 | R2(c,d,e,a,b,23); |
201 | 0 | R2(b,c,d,e,a,24); |
202 | 0 | R2(a,b,c,d,e,25); |
203 | 0 | R2(e,a,b,c,d,26); |
204 | 0 | R2(d,e,a,b,c,27); |
205 | 0 | R2(c,d,e,a,b,28); |
206 | 0 | R2(b,c,d,e,a,29); |
207 | 0 | R2(a,b,c,d,e,30); |
208 | 0 | R2(e,a,b,c,d,31); |
209 | 0 | R2(d,e,a,b,c,32); |
210 | 0 | R2(c,d,e,a,b,33); |
211 | 0 | R2(b,c,d,e,a,34); |
212 | 0 | R2(a,b,c,d,e,35); |
213 | 0 | R2(e,a,b,c,d,36); |
214 | 0 | R2(d,e,a,b,c,37); |
215 | 0 | R2(c,d,e,a,b,38); |
216 | 0 | R2(b,c,d,e,a,39); |
217 | 0 | R3(a,b,c,d,e,40); |
218 | 0 | R3(e,a,b,c,d,41); |
219 | 0 | R3(d,e,a,b,c,42); |
220 | 0 | R3(c,d,e,a,b,43); |
221 | 0 | R3(b,c,d,e,a,44); |
222 | 0 | R3(a,b,c,d,e,45); |
223 | 0 | R3(e,a,b,c,d,46); |
224 | 0 | R3(d,e,a,b,c,47); |
225 | 0 | R3(c,d,e,a,b,48); |
226 | 0 | R3(b,c,d,e,a,49); |
227 | 0 | R3(a,b,c,d,e,50); |
228 | 0 | R3(e,a,b,c,d,51); |
229 | 0 | R3(d,e,a,b,c,52); |
230 | 0 | R3(c,d,e,a,b,53); |
231 | 0 | R3(b,c,d,e,a,54); |
232 | 0 | R3(a,b,c,d,e,55); |
233 | 0 | R3(e,a,b,c,d,56); |
234 | 0 | R3(d,e,a,b,c,57); |
235 | 0 | R3(c,d,e,a,b,58); |
236 | 0 | R3(b,c,d,e,a,59); |
237 | 0 | R4(a,b,c,d,e,60); |
238 | 0 | R4(e,a,b,c,d,61); |
239 | 0 | R4(d,e,a,b,c,62); |
240 | 0 | R4(c,d,e,a,b,63); |
241 | 0 | R4(b,c,d,e,a,64); |
242 | 0 | R4(a,b,c,d,e,65); |
243 | 0 | R4(e,a,b,c,d,66); |
244 | 0 | R4(d,e,a,b,c,67); |
245 | 0 | R4(c,d,e,a,b,68); |
246 | 0 | R4(b,c,d,e,a,69); |
247 | 0 | R4(a,b,c,d,e,70); |
248 | 0 | R4(e,a,b,c,d,71); |
249 | 0 | R4(d,e,a,b,c,72); |
250 | 0 | R4(c,d,e,a,b,73); |
251 | 0 | R4(b,c,d,e,a,74); |
252 | 0 | R4(a,b,c,d,e,75); |
253 | 0 | R4(e,a,b,c,d,76); |
254 | 0 | R4(d,e,a,b,c,77); |
255 | 0 | R4(c,d,e,a,b,78); |
256 | 0 | R4(b,c,d,e,a,79); |
257 | | |
258 | | /* Add the working vars back into digest[] */ |
259 | 0 | digest[0] += a; |
260 | 0 | digest[1] += b; |
261 | 0 | digest[2] += c; |
262 | 0 | digest[3] += d; |
263 | 0 | digest[4] += e; |
264 | | |
265 | | /* Count the number of transformations */ |
266 | 0 | transforms++; |
267 | 0 | } |
268 | | |
269 | | |
270 | | void Sha1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_BYTES]) |
271 | 0 | { |
272 | | /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ |
273 | 0 | for (unsigned int i = 0; i < BLOCK_INTS; i++) |
274 | 0 | { |
275 | 0 | block[i] = (buffer[4*i+3] & 0xff) |
276 | 0 | | (buffer[4*i+2] & 0xff)<<8 |
277 | 0 | | (buffer[4*i+1] & 0xff)<<16 |
278 | 0 | | (buffer[4*i+0] & 0xff)<<24; |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | |
283 | | void Sha1::read(std::istream &is, std::string &s, int maxBuffer) |
284 | 0 | { |
285 | 0 | char* sbuf = new char[maxBuffer]; |
286 | 0 | is.read(sbuf, maxBuffer); |
287 | 0 | s.assign(sbuf, (unsigned int)is.gcount()); |
288 | 0 | delete [] sbuf; |
289 | 0 | } |
290 | | |
291 | | /* ==================================================================== |
292 | | * The Vovida Software License, Version 1.0 |
293 | | * |
294 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
295 | | * |
296 | | * Redistribution and use in source and binary forms, with or without |
297 | | * modification, are permitted provided that the following conditions |
298 | | * are met: |
299 | | * |
300 | | * 1. Redistributions of source code must retain the above copyright |
301 | | * notice, this list of conditions and the following disclaimer. |
302 | | * |
303 | | * 2. Redistributions in binary form must reproduce the above copyright |
304 | | * notice, this list of conditions and the following disclaimer in |
305 | | * the documentation and/or other materials provided with the |
306 | | * distribution. |
307 | | * |
308 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
309 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
310 | | * not be used to endorse or promote products derived from this |
311 | | * software without prior written permission. For written |
312 | | * permission, please contact vocal@vovida.org. |
313 | | * |
314 | | * 4. Products derived from this software may not be called "VOCAL", nor |
315 | | * may "VOCAL" appear in their name, without prior written |
316 | | * permission of Vovida Networks, Inc. |
317 | | * |
318 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
319 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
320 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
321 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
322 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
323 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
324 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
325 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
326 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
327 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
328 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
329 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
330 | | * DAMAGE. |
331 | | * |
332 | | * ==================================================================== |
333 | | * |
334 | | * This software consists of voluntary contributions made by Vovida |
335 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
336 | | * Inc. For more information on Vovida Networks, Inc., please see |
337 | | * <http://www.vovida.org/>. |
338 | | * |
339 | | */ |