Crow  1.1
A C++ microframework for the web
TinySHA1.hpp
Go to the documentation of this file.
1 /*
2  * SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
3  *
4  * Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * \file TinySHA1.hpp
21  * \author SAURAV MOHAPATRA <mohaps@gmail.com>
22  * \date 2012-22
23  * \brief TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
24  * on the implementation in boost::uuid::details.
25  *
26  * In this file are defined:
27  * - sha1::SHA1
28  */
29 #ifndef _TINY_SHA1_HPP_
30 #define _TINY_SHA1_HPP_
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 #include <stdint.h>
35 
36 /**
37  * \namespace sha1
38  * \brief Here is defined the SHA1 class
39  */
40 namespace sha1
41 {
42  /**
43  * \class SHA1
44  * \brief A tiny SHA1 algorithm implementation used internally in the
45  * Crow server (specifically in crow/websocket.h).
46  */
47  class SHA1
48  {
49  public:
50  typedef uint32_t digest32_t[5];
51  typedef uint8_t digest8_t[20];
52  inline static uint32_t LeftRotate(uint32_t value, size_t count) {
53  return (value << count) ^ (value >> (32-count));
54  }
55  SHA1(){ reset(); }
56  virtual ~SHA1() {}
57  SHA1(const SHA1& s) { *this = s; }
58  const SHA1& operator = (const SHA1& s) {
59  memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
60  memcpy(m_block, s.m_block, 64);
61  m_blockByteIndex = s.m_blockByteIndex;
62  m_byteCount = s.m_byteCount;
63  return *this;
64  }
65  SHA1& reset() {
66  m_digest[0] = 0x67452301;
67  m_digest[1] = 0xEFCDAB89;
68  m_digest[2] = 0x98BADCFE;
69  m_digest[3] = 0x10325476;
70  m_digest[4] = 0xC3D2E1F0;
71  m_blockByteIndex = 0;
72  m_byteCount = 0;
73  return *this;
74  }
75  SHA1& processByte(uint8_t octet) {
76  this->m_block[this->m_blockByteIndex++] = octet;
77  ++this->m_byteCount;
78  if(m_blockByteIndex == 64) {
79  this->m_blockByteIndex = 0;
80  processBlock();
81  }
82  return *this;
83  }
84  SHA1& processBlock(const void* const start, const void* const end) {
85  const uint8_t* begin = static_cast<const uint8_t*>(start);
86  const uint8_t* finish = static_cast<const uint8_t*>(end);
87  while(begin != finish) {
88  processByte(*begin);
89  begin++;
90  }
91  return *this;
92  }
93  SHA1& processBytes(const void* const data, size_t len) {
94  const uint8_t* block = static_cast<const uint8_t*>(data);
95  processBlock(block, block + len);
96  return *this;
97  }
98  const uint32_t* getDigest(digest32_t digest) {
99  size_t bitCount = this->m_byteCount * 8;
100  processByte(0x80);
101  if (this->m_blockByteIndex > 56) {
102  while (m_blockByteIndex != 0) {
103  processByte(0);
104  }
105  while (m_blockByteIndex < 56) {
106  processByte(0);
107  }
108  } else {
109  while (m_blockByteIndex < 56) {
110  processByte(0);
111  }
112  }
113  processByte(0);
114  processByte(0);
115  processByte(0);
116  processByte(0);
117  processByte( static_cast<unsigned char>((bitCount>>24) & 0xFF));
118  processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
119  processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
120  processByte( static_cast<unsigned char>((bitCount) & 0xFF));
121 
122  memcpy(digest, m_digest, 5 * sizeof(uint32_t));
123  return digest;
124  }
125  const uint8_t* getDigestBytes(digest8_t digest) {
126  digest32_t d32;
127  getDigest(d32);
128  size_t di = 0;
129  digest[di++] = ((d32[0] >> 24) & 0xFF);
130  digest[di++] = ((d32[0] >> 16) & 0xFF);
131  digest[di++] = ((d32[0] >> 8) & 0xFF);
132  digest[di++] = ((d32[0]) & 0xFF);
133 
134  digest[di++] = ((d32[1] >> 24) & 0xFF);
135  digest[di++] = ((d32[1] >> 16) & 0xFF);
136  digest[di++] = ((d32[1] >> 8) & 0xFF);
137  digest[di++] = ((d32[1]) & 0xFF);
138 
139  digest[di++] = ((d32[2] >> 24) & 0xFF);
140  digest[di++] = ((d32[2] >> 16) & 0xFF);
141  digest[di++] = ((d32[2] >> 8) & 0xFF);
142  digest[di++] = ((d32[2]) & 0xFF);
143 
144  digest[di++] = ((d32[3] >> 24) & 0xFF);
145  digest[di++] = ((d32[3] >> 16) & 0xFF);
146  digest[di++] = ((d32[3] >> 8) & 0xFF);
147  digest[di++] = ((d32[3]) & 0xFF);
148 
149  digest[di++] = ((d32[4] >> 24) & 0xFF);
150  digest[di++] = ((d32[4] >> 16) & 0xFF);
151  digest[di++] = ((d32[4] >> 8) & 0xFF);
152  digest[di++] = ((d32[4]) & 0xFF);
153  return digest;
154  }
155 
156  protected:
157  void processBlock() {
158  uint32_t w[80];
159  for (size_t i = 0; i < 16; i++) {
160  w[i] = (m_block[i*4 + 0] << 24);
161  w[i] |= (m_block[i*4 + 1] << 16);
162  w[i] |= (m_block[i*4 + 2] << 8);
163  w[i] |= (m_block[i*4 + 3]);
164  }
165  for (size_t i = 16; i < 80; i++) {
166  w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
167  }
168 
169  uint32_t a = m_digest[0];
170  uint32_t b = m_digest[1];
171  uint32_t c = m_digest[2];
172  uint32_t d = m_digest[3];
173  uint32_t e = m_digest[4];
174 
175  for (std::size_t i=0; i<80; ++i) {
176  uint32_t f = 0;
177  uint32_t k = 0;
178 
179  if (i<20) {
180  f = (b & c) | (~b & d);
181  k = 0x5A827999;
182  } else if (i<40) {
183  f = b ^ c ^ d;
184  k = 0x6ED9EBA1;
185  } else if (i<60) {
186  f = (b & c) | (b & d) | (c & d);
187  k = 0x8F1BBCDC;
188  } else {
189  f = b ^ c ^ d;
190  k = 0xCA62C1D6;
191  }
192  uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
193  e = d;
194  d = c;
195  c = LeftRotate(b, 30);
196  b = a;
197  a = temp;
198  }
199 
200  m_digest[0] += a;
201  m_digest[1] += b;
202  m_digest[2] += c;
203  m_digest[3] += d;
204  m_digest[4] += e;
205  }
206  private:
207  digest32_t m_digest;
208  uint8_t m_block[64];
209  size_t m_blockByteIndex;
210  size_t m_byteCount;
211  };
212 }
213 #endif
A tiny SHA1 algorithm implementation used internally in the Crow server (specifically in crow/websock...
Definition: TinySHA1.hpp:48
Here is defined the SHA1 class.