[core] allow scilab to use more secure hash functions
[scilab.git] / scilab / modules / core / src / cpp / hash / sha1.cpp
1 // //////////////////////////////////////////////////////////
2 // sha1.cpp
3 // Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
4 // see http://create.stephan-brumme.com/disclaimer.html
5 //
6
7 #include "sha1.hxx"
8
9 /// same as reset()
10 SHA1::SHA1()
11 {
12   reset();
13 }
14
15
16 /// restart
17 void SHA1::reset()
18 {
19   m_numBytes   = 0;
20   m_bufferSize = 0;
21
22   // according to RFC 1321
23   m_hash[0] = 0x67452301;
24   m_hash[1] = 0xefcdab89;
25   m_hash[2] = 0x98badcfe;
26   m_hash[3] = 0x10325476;
27   m_hash[4] = 0xc3d2e1f0;
28 }
29
30
31 namespace
32 {
33   // mix functions for processBlock()
34   inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
35   {
36     return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
37   }
38
39   inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
40   {
41     return b ^ c ^ d;
42   }
43
44   inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
45   {
46     return (b & c) | (b & d) | (c & d);
47   }
48
49   inline uint32_t rotate(uint32_t a, uint32_t c)
50   {
51     return (a << c) | (a >> (32 - c));
52   }
53
54   inline uint32_t swap(uint32_t x)
55   {
56 #if defined(__GNUC__) || defined(__clang__)
57     return __builtin_bswap32(x);
58 #endif
59 #ifdef MSC_VER
60     return _byteswap_ulong(x);
61 #endif
62
63     return (x >> 24) |
64           ((x >>  8) & 0x0000FF00) |
65           ((x <<  8) & 0x00FF0000) |
66            (x << 24);
67   }
68 }
69
70
71 /// process 64 bytes
72 void SHA1::processBlock(const void* data)
73 {
74   // get last hash
75   uint32_t a = m_hash[0];
76   uint32_t b = m_hash[1];
77   uint32_t c = m_hash[2];
78   uint32_t d = m_hash[3];
79   uint32_t e = m_hash[4];
80
81   // data represented as 16x 32-bit words
82   const uint32_t* input = (uint32_t*) data;
83   // convert to big endian
84   uint32_t words[80];
85   for (int i = 0; i < 16; i++)
86 #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
87     words[i] = input[i];
88 #else
89     words[i] = swap(input[i]);
90 #endif
91
92   // extend to 80 words
93   for (int i = 16; i < 80; i++)
94     words[i] = rotate(words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16], 1);
95
96   // first round
97   for (int i = 0; i < 4; i++)
98   {
99     int offset = 5*i;
100     e += rotate(a,5) + f1(b,c,d) + words[offset  ] + 0x5a827999; b = rotate(b,30);
101     d += rotate(e,5) + f1(a,b,c) + words[offset+1] + 0x5a827999; a = rotate(a,30);
102     c += rotate(d,5) + f1(e,a,b) + words[offset+2] + 0x5a827999; e = rotate(e,30);
103     b += rotate(c,5) + f1(d,e,a) + words[offset+3] + 0x5a827999; d = rotate(d,30);
104     a += rotate(b,5) + f1(c,d,e) + words[offset+4] + 0x5a827999; c = rotate(c,30);
105   }
106
107   // second round
108   for (int i = 4; i < 8; i++)
109   {
110     int offset = 5*i;
111     e += rotate(a,5) + f2(b,c,d) + words[offset  ] + 0x6ed9eba1; b = rotate(b,30);
112     d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0x6ed9eba1; a = rotate(a,30);
113     c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0x6ed9eba1; e = rotate(e,30);
114     b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0x6ed9eba1; d = rotate(d,30);
115     a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0x6ed9eba1; c = rotate(c,30);
116   }
117
118   // third round
119   for (int i = 8; i < 12; i++)
120   {
121     int offset = 5*i;
122     e += rotate(a,5) + f3(b,c,d) + words[offset  ] + 0x8f1bbcdc; b = rotate(b,30);
123     d += rotate(e,5) + f3(a,b,c) + words[offset+1] + 0x8f1bbcdc; a = rotate(a,30);
124     c += rotate(d,5) + f3(e,a,b) + words[offset+2] + 0x8f1bbcdc; e = rotate(e,30);
125     b += rotate(c,5) + f3(d,e,a) + words[offset+3] + 0x8f1bbcdc; d = rotate(d,30);
126     a += rotate(b,5) + f3(c,d,e) + words[offset+4] + 0x8f1bbcdc; c = rotate(c,30);
127   }
128
129   // fourth round
130   for (int i = 12; i < 16; i++)
131   {
132     int offset = 5*i;
133     e += rotate(a,5) + f2(b,c,d) + words[offset  ] + 0xca62c1d6; b = rotate(b,30);
134     d += rotate(e,5) + f2(a,b,c) + words[offset+1] + 0xca62c1d6; a = rotate(a,30);
135     c += rotate(d,5) + f2(e,a,b) + words[offset+2] + 0xca62c1d6; e = rotate(e,30);
136     b += rotate(c,5) + f2(d,e,a) + words[offset+3] + 0xca62c1d6; d = rotate(d,30);
137     a += rotate(b,5) + f2(c,d,e) + words[offset+4] + 0xca62c1d6; c = rotate(c,30);
138   }
139
140   // update hash
141   m_hash[0] += a;
142   m_hash[1] += b;
143   m_hash[2] += c;
144   m_hash[3] += d;
145   m_hash[4] += e;
146 }
147
148
149 /// add arbitrary number of bytes
150 void SHA1::add(const void* data, size_t numBytes)
151 {
152   const uint8_t* current = (const uint8_t*) data;
153
154   if (m_bufferSize > 0)
155   {
156     while (numBytes > 0 && m_bufferSize < BlockSize)
157     {
158       m_buffer[m_bufferSize++] = *current++;
159       numBytes--;
160     }
161   }
162
163   // full buffer
164   if (m_bufferSize == BlockSize)
165   {
166     processBlock((void*)m_buffer);
167     m_numBytes  += BlockSize;
168     m_bufferSize = 0;
169   }
170
171   // no more data ?
172   if (numBytes == 0)
173     return;
174
175   // process full blocks
176   while (numBytes >= BlockSize)
177   {
178     processBlock(current);
179     current    += BlockSize;
180     m_numBytes += BlockSize;
181     numBytes   -= BlockSize;
182   }
183
184   // keep remaining bytes in buffer
185   while (numBytes > 0)
186   {
187     m_buffer[m_bufferSize++] = *current++;
188     numBytes--;
189   }
190 }
191
192
193 /// process final block, less than 64 bytes
194 void SHA1::processBuffer()
195 {
196   // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
197
198   // - append "1" bit to message
199   // - append "0" bits until message length in bit mod 512 is 448
200   // - append length as 64 bit integer
201
202   // number of bits
203   size_t paddedLength = m_bufferSize * 8;
204
205   // plus one bit set to 1 (always appended)
206   paddedLength++;
207
208   // number of bits must be (numBits % 512) = 448
209   size_t lower11Bits = paddedLength & 511;
210   if (lower11Bits <= 448)
211     paddedLength +=       448 - lower11Bits;
212   else
213     paddedLength += 512 + 448 - lower11Bits;
214   // convert from bits to bytes
215   paddedLength /= 8;
216
217   // only needed if additional data flows over into a second block
218   unsigned char extra[BlockSize];
219
220   // append a "1" bit, 128 => binary 10000000
221   if (m_bufferSize < BlockSize)
222     m_buffer[m_bufferSize] = 128;
223   else
224     extra[0] = 128;
225
226   size_t i;
227   for (i = m_bufferSize + 1; i < BlockSize; i++)
228     m_buffer[i] = 0;
229   for (; i < paddedLength; i++)
230     extra[i - BlockSize] = 0;
231
232   // add message length in bits as 64 bit number
233   uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
234   // find right position
235   unsigned char* addLength;
236   if (paddedLength < BlockSize)
237     addLength = m_buffer + paddedLength;
238   else
239     addLength = extra + paddedLength - BlockSize;
240
241   // must be big endian
242   *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF);
243   *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF);
244   *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF);
245   *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF);
246   *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF);
247   *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF);
248   *addLength++ = (unsigned char)((msgBits >>  8) & 0xFF);
249   *addLength   = (unsigned char)( msgBits        & 0xFF);
250
251   // process blocks
252   processBlock(m_buffer);
253   // flowed over into a second block ?
254   if (paddedLength > BlockSize)
255     processBlock(extra);
256 }
257
258
259 /// return latest hash as 40 hex characters
260 std::string SHA1::getHash()
261 {
262   // compute hash (as raw bytes)
263   unsigned char rawHash[HashBytes];
264   getHash(rawHash);
265
266   // convert to hex string
267   std::string result;
268   result.reserve(2 * HashBytes);
269   for (int i = 0; i < HashBytes; i++)
270   {
271     static const char dec2hex[16+1] = "0123456789abcdef";
272     result += dec2hex[(rawHash[i] >> 4) & 15];
273     result += dec2hex[ rawHash[i]       & 15];
274   }
275
276   return result;
277 }
278
279
280 /// return latest hash as bytes
281 void SHA1::getHash(unsigned char buffer[SHA1::HashBytes])
282 {
283   // save old hash if buffer is partially filled
284   uint32_t oldHash[HashValues];
285   for (int i = 0; i < HashValues; i++)
286     oldHash[i] = m_hash[i];
287
288   // process remaining bytes
289   processBuffer();
290
291   unsigned char* current = buffer;
292   for (int i = 0; i < HashValues; i++)
293   {
294     *current++ = (m_hash[i] >> 24) & 0xFF;
295     *current++ = (m_hash[i] >> 16) & 0xFF;
296     *current++ = (m_hash[i] >>  8) & 0xFF;
297     *current++ =  m_hash[i]        & 0xFF;
298
299     // restore old hash
300     m_hash[i] = oldHash[i];
301   }
302 }
303
304
305 /// compute SHA1 of a memory block
306 std::string SHA1::operator()(const void* data, size_t numBytes)
307 {
308   reset();
309   add(data, numBytes);
310   return getHash();
311 }
312
313
314 /// compute SHA1 of a string, excluding final zero
315 std::string SHA1::operator()(const std::string& text)
316 {
317   reset();
318   add(text.c_str(), text.size());
319   return getHash();
320 }