WebSocket++  0.8.3-dev
C++ websocket client/server library
sha1.hpp
1 /*
2 *****
3 sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1
4 library (http://code.google.com/p/smallsha1/) into a single header suitable for
5 use as a header only library. This conversion was done by Peter Thorson
6 (webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
7 under the same license as the original, which is listed below.
8 *****
9 
10  Copyright (c) 2011, Micael Hildenborg
11  All rights reserved.
12 
13  Redistribution and use in source and binary forms, with or without
14  modification, are permitted provided that the following conditions are met:
15  * Redistributions of source code must retain the above copyright
16  notice, this list of conditions and the following disclaimer.
17  * Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20  * Neither the name of Micael Hildenborg nor the
21  names of its contributors may be used to endorse or promote products
22  derived from this software without specific prior written permission.
23 
24  THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
25  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
28  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #ifndef SHA1_DEFINED
37 #define SHA1_DEFINED
38 
39 namespace websocketpp {
40 namespace sha1 {
41 
42 namespace { // local
43 
44 // Rotate an integer value to left.
45 inline unsigned int rol(unsigned int value, unsigned int steps) {
46  return ((value << steps) | (value >> (32 - steps)));
47 }
48 
49 // Sets the first 16 integers in the buffert to zero.
50 // Used for clearing the W buffert.
51 inline void clearWBuffert(unsigned int * buffert)
52 {
53  for (int pos = 16; --pos >= 0;)
54  {
55  buffert[pos] = 0;
56  }
57 }
58 
59 inline void innerHash(unsigned int * result, unsigned int * w)
60 {
61  unsigned int a = result[0];
62  unsigned int b = result[1];
63  unsigned int c = result[2];
64  unsigned int d = result[3];
65  unsigned int e = result[4];
66 
67  int round = 0;
68 
69  #define sha1macro(func,val)
70  {
71  const unsigned int t = rol(a, 5) + (func) + e + val + w[round];
72  e = d;
73  d = c;
74  c = rol(b, 30);
75  b = a;
76  a = t;
77  }
78 
79  while (round < 16)
80  {
81  sha1macro((b & c) | (~b & d), 0x5a827999)
82  ++round;
83  }
84  while (round < 20)
85  {
86  w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
87  sha1macro((b & c) | (~b & d), 0x5a827999)
88  ++round;
89  }
90  while (round < 40)
91  {
92  w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
93  sha1macro(b ^ c ^ d, 0x6ed9eba1)
94  ++round;
95  }
96  while (round < 60)
97  {
98  w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
99  sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
100  ++round;
101  }
102  while (round < 80)
103  {
104  w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
105  sha1macro(b ^ c ^ d, 0xca62c1d6)
106  ++round;
107  }
108 
109  #undef sha1macro
110 
111  result[0] += a;
112  result[1] += b;
113  result[2] += c;
114  result[3] += d;
115  result[4] += e;
116 }
117 
118 } // namespace
119 
120 /// Calculate a SHA1 hash
121 /**
122  * @param src points to any kind of data to be hashed.
123  * @param bytelength the number of bytes to hash from the src pointer.
124  * @param hash should point to a buffer of at least 20 bytes of size for storing
125  * the sha1 result in.
126  */
127 inline void calc(void const * src, size_t bytelength, unsigned char * hash) {
128  // Init the result array.
129  unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe,
130  0x10325476, 0xc3d2e1f0 };
131 
132  // Cast the void src pointer to be the byte array we can work with.
133  unsigned char const * sarray = (unsigned char const *) src;
134 
135  // The reusable round buffer
136  unsigned int w[80];
137 
138  // Loop through all complete 64byte blocks.
139 
140  size_t endCurrentBlock;
141  size_t currentBlock = 0;
142 
143  if (bytelength >= 64) {
144  size_t const endOfFullBlocks = bytelength - 64;
145 
146  while (currentBlock <= endOfFullBlocks) {
147  endCurrentBlock = currentBlock + 64;
148 
149  // Init the round buffer with the 64 byte block data.
150  for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
151  {
152  // This line will swap endian on big endian and keep endian on
153  // little endian.
154  w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
155  | (((unsigned int) sarray[currentBlock + 2]) << 8)
156  | (((unsigned int) sarray[currentBlock + 1]) << 16)
157  | (((unsigned int) sarray[currentBlock]) << 24);
158  }
159  innerHash(result, w);
160  }
161  }
162 
163  // Handle the last and not full 64 byte block if existing.
164  endCurrentBlock = bytelength - currentBlock;
165  clearWBuffert(w);
166  size_t lastBlockBytes = 0;
167  for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
168  w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
169  }
170 
171  w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
172  if (endCurrentBlock >= 56) {
173  innerHash(result, w);
174  clearWBuffert(w);
175  }
176  w[15] = bytelength << 3;
177  innerHash(result, w);
178 
179  // Store hash in result pointer, and make sure we get in in the correct
180  // order on both endian models.
181  for (int hashByte = 20; --hashByte >= 0;) {
182  hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
183  }
184 }
185 
186 } // namespace sha1
187 } // namespace websocketpp
188 
189 #endif // SHA1_DEFINED
sha1macro
#define sha1macro(func, val)
websocketpp::versions_supported
static std::vector< int > const versions_supported(helper, helper+4)
Container that stores the list of protocol versions supported.