RESTinio
sha1.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
9 #pragma once
10 
12 
13 #include <string>
14 #include <array>
15 #include <exception>
16 #include <iostream> // std::cout, debug
17 #include <algorithm>
18 
19 namespace restinio
20 {
21 
22 namespace utils
23 {
24 
25 namespace sha1
26 {
27 
28 // Block size in bytes.
29 constexpr std::uint8_t block_size = 64;
30 
31 // Number of 32bit integers in block.
32 constexpr std::uint8_t block_ints = 16;
33 
34 // Word size in digest in bytes.
35 constexpr std::uint8_t word_size = 4;
36 
37 // Digest size in bytes.
38 constexpr std::uint8_t digest_size = 20;
39 
40 // Number of words in digest.
41 constexpr std::size_t digest_array_size = digest_size / word_size ;
42 
43 using byte_block_t = std::array< std::uint8_t, block_size >;
44 using int_block_t = std::array< std::uint32_t, block_ints >;
45 using digest_t = std::array< std::uint32_t, digest_array_size >;
46 
47 template< class T >
48 inline std::uint8_t
49 as_uint8( T what )
50 {
51  return static_cast< std::uint8_t >( what );
52 }
53 
54 template< class T >
55 inline std::uint32_t
56 as_uint32( T what )
57 {
58  return static_cast< std::uint32_t >( what );
59 }
60 
61 template< class T >
62 const std::uint8_t *
63 as_uint8_ptr( const T * what )
64 {
65  return reinterpret_cast< const std::uint8_t * >( what );
66 }
67 
68 template< unsigned int Shift >
69 std::uint32_t
70 rotate_left( const std::uint32_t x )
71 {
72  return (x << Shift) | (x >> (32 - Shift));
73 }
74 
75 template< unsigned int Shift >
76 inline std::uint8_t
77 octet_from( std::uint32_t x )
78 {
79  return ::restinio::utils::impl::bitops::n_bits_from< std::uint8_t, Shift >(x);
80 }
81 
82 static uint32_t blk(const int_block_t & block, const size_t i)
83 {
84  return rotate_left<1>(
85  block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i] );
86 }
87 
88 inline void
89 R0(const int_block_t & block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
90 {
91  z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rotate_left<5>( v );
92  w = rotate_left<30>( w );
93 }
94 
95 
96 inline void
97 R1(int_block_t & block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
98 {
99  block[i] = blk(block, i);
100  z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rotate_left<5>(v);
101  w = rotate_left<30>(w);
102 }
103 
104 
105 inline void
106 R2(int_block_t & block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
107 {
108  block[i] = blk(block, i);
109  z += (w^x^y) + block[i] + 0x6ed9eba1 + rotate_left<5>(v);
110  w = rotate_left<30>(w);
111 }
112 
113 inline void
114 R3(int_block_t & block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
115 {
116  block[i] = blk(block, i);
117  z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rotate_left<5>(v);
118  w = rotate_left<30>(w);
119 }
120 
121 
122 inline void
123 R4(int_block_t & block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
124 {
125  block[i] = blk(block, i);
126  z += (w^x^y) + block[i] + 0xca62c1d6 + rotate_left<5>(v);
127  w = rotate_left<30>(w);
128 }
129 
130 inline void
131 transform( digest_t & digest, const byte_block_t & buf )
132 {
133  int_block_t block;
134 
135  for (size_t i = 0; i < block_ints; i++)
136  {
137  block[i] =
138  as_uint32(buf[4*i+3] & 0xff) |
139  as_uint32(buf[4*i+2] & 0xff)<<8 |
140  as_uint32(buf[4*i+1] & 0xff)<<16 |
141  as_uint32(buf[4*i+0] & 0xff)<<24;
142  }
143 
144  std::uint32_t a = digest[0];
145  std::uint32_t b = digest[1];
146  std::uint32_t c = digest[2];
147  std::uint32_t d = digest[3];
148  std::uint32_t e = digest[4];
149 
150  R0(block, a, b, c, d, e, 0);
151  R0(block, e, a, b, c, d, 1);
152  R0(block, d, e, a, b, c, 2);
153  R0(block, c, d, e, a, b, 3);
154  R0(block, b, c, d, e, a, 4);
155  R0(block, a, b, c, d, e, 5);
156  R0(block, e, a, b, c, d, 6);
157  R0(block, d, e, a, b, c, 7);
158  R0(block, c, d, e, a, b, 8);
159  R0(block, b, c, d, e, a, 9);
160  R0(block, a, b, c, d, e, 10);
161  R0(block, e, a, b, c, d, 11);
162  R0(block, d, e, a, b, c, 12);
163  R0(block, c, d, e, a, b, 13);
164  R0(block, b, c, d, e, a, 14);
165  R0(block, a, b, c, d, e, 15);
166  R1(block, e, a, b, c, d, 0);
167  R1(block, d, e, a, b, c, 1);
168  R1(block, c, d, e, a, b, 2);
169  R1(block, b, c, d, e, a, 3);
170  R2(block, a, b, c, d, e, 4);
171  R2(block, e, a, b, c, d, 5);
172  R2(block, d, e, a, b, c, 6);
173  R2(block, c, d, e, a, b, 7);
174  R2(block, b, c, d, e, a, 8);
175  R2(block, a, b, c, d, e, 9);
176  R2(block, e, a, b, c, d, 10);
177  R2(block, d, e, a, b, c, 11);
178  R2(block, c, d, e, a, b, 12);
179  R2(block, b, c, d, e, a, 13);
180  R2(block, a, b, c, d, e, 14);
181  R2(block, e, a, b, c, d, 15);
182  R2(block, d, e, a, b, c, 0);
183  R2(block, c, d, e, a, b, 1);
184  R2(block, b, c, d, e, a, 2);
185  R2(block, a, b, c, d, e, 3);
186  R2(block, e, a, b, c, d, 4);
187  R2(block, d, e, a, b, c, 5);
188  R2(block, c, d, e, a, b, 6);
189  R2(block, b, c, d, e, a, 7);
190  R3(block, a, b, c, d, e, 8);
191  R3(block, e, a, b, c, d, 9);
192  R3(block, d, e, a, b, c, 10);
193  R3(block, c, d, e, a, b, 11);
194  R3(block, b, c, d, e, a, 12);
195  R3(block, a, b, c, d, e, 13);
196  R3(block, e, a, b, c, d, 14);
197  R3(block, d, e, a, b, c, 15);
198  R3(block, c, d, e, a, b, 0);
199  R3(block, b, c, d, e, a, 1);
200  R3(block, a, b, c, d, e, 2);
201  R3(block, e, a, b, c, d, 3);
202  R3(block, d, e, a, b, c, 4);
203  R3(block, c, d, e, a, b, 5);
204  R3(block, b, c, d, e, a, 6);
205  R3(block, a, b, c, d, e, 7);
206  R3(block, e, a, b, c, d, 8);
207  R3(block, d, e, a, b, c, 9);
208  R3(block, c, d, e, a, b, 10);
209  R3(block, b, c, d, e, a, 11);
210  R4(block, a, b, c, d, e, 12);
211  R4(block, e, a, b, c, d, 13);
212  R4(block, d, e, a, b, c, 14);
213  R4(block, c, d, e, a, b, 15);
214  R4(block, b, c, d, e, a, 0);
215  R4(block, a, b, c, d, e, 1);
216  R4(block, e, a, b, c, d, 2);
217  R4(block, d, e, a, b, c, 3);
218  R4(block, c, d, e, a, b, 4);
219  R4(block, b, c, d, e, a, 5);
220  R4(block, a, b, c, d, e, 6);
221  R4(block, e, a, b, c, d, 7);
222  R4(block, d, e, a, b, c, 8);
223  R4(block, c, d, e, a, b, 9);
224  R4(block, b, c, d, e, a, 10);
225  R4(block, a, b, c, d, e, 11);
226  R4(block, e, a, b, c, d, 12);
227  R4(block, d, e, a, b, c, 13);
228  R4(block, c, d, e, a, b, 14);
229  R4(block, b, c, d, e, a, 15);
230 
231  digest[0] += a;
232  digest[1] += b;
233  digest[2] += c;
234  digest[3] += d;
235  digest[4] += e;
236 }
237 
238 struct builder_t
239 {
240  public:
241 
243  {
244  reset();
245  }
246 
248  {
249  /* Zeroize sensitive information. */
250  reset();
251  }
252 
253  inline builder_t &
254  update( const std::uint8_t * what, std::size_t length )
255  {
256  while( true )
257  {
258  auto part_len = std::min( length, block_size - m_buffer_len );
259 
260  std::copy( what, what + part_len, m_buffer.begin() + m_buffer_len );
261  m_buffer_len += part_len;
262 
263  if( m_buffer_len != block_size )
264  break;
265  else
266  {
267  length -= part_len;
268  what += part_len;
269 
272  m_buffer_len = 0;
273  }
274  }
275 
276  return *this;
277  }
278 
279  digest_t
281  {
282  const auto total_bits = calculate_total_bits_count();
283 
284  const auto original_buf_len = m_buffer_len;
285 
286  m_buffer[ m_buffer_len ++ ] = 0x80;
287 
288  while( m_buffer_len < block_size )
289  m_buffer[m_buffer_len++] = 0x00;
290 
291  if( original_buf_len > block_size - 8 )
292  {
294 
295  for( size_t i = 0 ; i < block_size ; ++ i )
296  m_buffer[i] = 0;
297  }
298 
299  // Fill total bits count in last 8 bytes of buffer as big-endian.
300  std::size_t i = block_size - 8u;
301  const auto push_uint_to_buffer = [&]( auto big_value ) {
302  const auto v = static_cast<std::uint32_t>(big_value);
303  m_buffer[ i++ ] = octet_from<24>(v);
304  m_buffer[ i++ ] = octet_from<16>(v);
305  m_buffer[ i++ ] = octet_from<8>(v);
306  m_buffer[ i++ ] = octet_from<0>(v);
307  };
308  push_uint_to_buffer( total_bits >> 32 );
309  push_uint_to_buffer( total_bits & 0xffffffffu );
310 
312 
313  return m_digest;
314  }
315 
316  private:
317 
318  std::uint_fast64_t
320  {
321  return (static_cast<std::uint_fast64_t>(m_transforms_count)
322  * block_size + m_buffer_len) * 8;
323  }
324 
325  void
327  {
328  }
329 
330  void
332  {
333  m_buffer_len = 0;
334  m_transforms_count = 0;
335 
336  m_digest[0] = 0x67452301;
337  m_digest[1] = 0xEFCDAB89;
338  m_digest[2] = 0x98BADCFE;
339  m_digest[3] = 0x10325476;
340  m_digest[4] = 0xC3D2E1F0;
341 
342  std::fill( std::begin(m_buffer), std::end(m_buffer), 0 );
343  }
344 
346 
347  size_t m_buffer_len;
349 
351 };
352 
353 namespace details
354 {
355 
356 template< unsigned int Shift >
357 unsigned int
358 halfbyte( digest_t::value_type v )
359 {
360  return ::restinio::utils::impl::bitops::n_bits_from< unsigned int, Shift, 4 >(v);
361 }
362 
363 template< unsigned int Shift >
364 unsigned int
365 byte( digest_t::value_type v )
366 {
367  return ::restinio::utils::impl::bitops::n_bits_from< unsigned int, Shift, 8 >(v);
368 }
369 
370 } /* namespace details */
371 
372 inline std::string
373 to_hex_string( const digest_t & what )
374 {
375  using namespace details;
376 
377  static const char digits[] = "0123456789abcdef";
378 
379  std::string result;
380  result.reserve( digest_array_size * 8);
381 
382  for( const auto c : what )
383  {
384  result += digits[halfbyte<28>(c)];
385  result += digits[halfbyte<24>(c)];
386  result += digits[halfbyte<20>(c)];
387  result += digits[halfbyte<16>(c)];
388  result += digits[halfbyte<12>(c)];
389  result += digits[halfbyte<8>(c)];
390  result += digits[halfbyte<4>(c)];
391  result += digits[halfbyte<0>(c)];
392  }
393 
394  return result;
395 }
396 
397 inline std::string
398 to_string( const digest_t & what )
399 {
400  using namespace details;
401 
402  std::string result;
403  result.reserve( digest_size );
404 
405  for( const auto c : what )
406  {
407  result.push_back( static_cast<char>(byte<24>(c)) );
408  result.push_back( static_cast<char>(byte<16>(c)) );
409  result.push_back( static_cast<char>(byte<8>(c)) );
410  result.push_back( static_cast<char>(byte<0>(c)) );
411  }
412 
413  return result;
414 }
415 
416 inline digest_t
417 make_digest( const std::uint8_t * what, std::size_t length )
418 {
419  return builder_t{}.update( what, length ).finish();
420 }
421 
422 template< class T >
423 inline digest_t
424 make_digest( const T * begin, const T * end )
425 {
426  const std::uint8_t * const start = as_uint8_ptr( begin );
427  const std::uint8_t * const finish = as_uint8_ptr( end );
428  const auto length = static_cast< std::size_t >( finish - start );
429 
430  return make_digest( start, length );
431 }
432 
433 inline digest_t
434 make_digest( const char * what, std::size_t length )
435 {
436  return builder_t{}.update(
437  as_uint8_ptr( what ), length ).finish();
438 }
439 
440 inline digest_t
442 {
443  return make_digest( sv.data(), sv.size() );
444 }
445 
446 } /* namespace sha1 */
447 
448 } /* namespace utils */
449 
450 } /* namespace restinio */
restinio::utils::sha1::details::halfbyte
unsigned int halfbyte(digest_t::value_type v)
Definition: sha1.hpp:358
restinio::utils::sha1::digest_t
std::array< std::uint32_t, digest_array_size > digest_t
Definition: sha1.hpp:45
restinio::utils::sha1::block_size
constexpr std::uint8_t block_size
Definition: sha1.hpp:29
restinio::utils::sha1::to_string
std::string to_string(const digest_t &what)
Definition: sha1.hpp:398
restinio::utils::sha1::transform
void transform(digest_t &digest, const byte_block_t &buf)
Definition: sha1.hpp:131
restinio::utils::sha1::builder_t::m_digest
digest_t m_digest
Definition: sha1.hpp:345
restinio::utils::sha1::builder_t::~builder_t
~builder_t()
Definition: sha1.hpp:247
restinio::utils::sha1::R4
void R4(int_block_t &block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
Definition: sha1.hpp:123
restinio::utils::sha1::builder_t::store_total_bits_to_buffer
void store_total_bits_to_buffer()
Definition: sha1.hpp:326
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::utils::sha1::word_size
constexpr std::uint8_t word_size
Definition: sha1.hpp:35
restinio::utils::sha1::octet_from
std::uint8_t octet_from(std::uint32_t x)
Definition: sha1.hpp:77
restinio::utils::sha1::builder_t::calculate_total_bits_count
std::uint_fast64_t calculate_total_bits_count() const
Definition: sha1.hpp:319
bitops.hpp
restinio::utils::sha1::builder_t::reset
void reset()
Definition: sha1.hpp:331
restinio::utils::sha1::make_digest
digest_t make_digest(const std::uint8_t *what, std::size_t length)
Definition: sha1.hpp:417
restinio::utils::sha1::builder_t
Definition: sha1.hpp:239
restinio::utils::sha1::as_uint8
std::uint8_t as_uint8(T what)
Definition: sha1.hpp:49
restinio::utils::sha1::byte_block_t
std::array< std::uint8_t, block_size > byte_block_t
Definition: sha1.hpp:43
restinio::utils::sha1::block_ints
constexpr std::uint8_t block_ints
Definition: sha1.hpp:32
restinio::utils::sha1::builder_t::m_buffer
byte_block_t m_buffer
Definition: sha1.hpp:350
restinio::utils::sha1::digest_size
constexpr std::uint8_t digest_size
Definition: sha1.hpp:38
restinio::utils::sha1::builder_t::m_buffer_len
size_t m_buffer_len
Definition: sha1.hpp:347
restinio::utils::sha1::R2
void R2(int_block_t &block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
Definition: sha1.hpp:106
restinio::utils::sha1::R0
void R0(const int_block_t &block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
Definition: sha1.hpp:89
restinio::utils::sha1::rotate_left
std::uint32_t rotate_left(const std::uint32_t x)
Definition: sha1.hpp:70
restinio::utils::sha1::builder_t::update
builder_t & update(const std::uint8_t *what, std::size_t length)
Definition: sha1.hpp:254
restinio::utils::sha1::to_hex_string
std::string to_hex_string(const digest_t &what)
Definition: sha1.hpp:373
restinio::utils::sha1::details::byte
unsigned int byte(digest_t::value_type v)
Definition: sha1.hpp:365
restinio::utils::sha1::int_block_t
std::array< std::uint32_t, block_ints > int_block_t
Definition: sha1.hpp:44
restinio
Definition: asio_include.hpp:21
restinio::utils::sha1::digest_array_size
constexpr std::size_t digest_array_size
Definition: sha1.hpp:41
restinio::utils::sha1::as_uint8_ptr
const std::uint8_t * as_uint8_ptr(const T *what)
Definition: sha1.hpp:63
restinio::utils::sha1::builder_t::finish
digest_t finish()
Definition: sha1.hpp:280
restinio::utils::sha1::builder_t::builder_t
builder_t()
Definition: sha1.hpp:242
restinio::utils::sha1::R3
void R3(int_block_t &block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
Definition: sha1.hpp:114
restinio::utils::sha1::as_uint32
std::uint32_t as_uint32(T what)
Definition: sha1.hpp:56
restinio::utils::sha1::R1
void R1(int_block_t &block, const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
Definition: sha1.hpp:97
restinio::utils::sha1::builder_t::m_transforms_count
size_t m_transforms_count
Definition: sha1.hpp:348