OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
SHA1.h
Go to the documentation of this file.
1 /*
2 
3 Copyright 2007 Andy Tompkins.
4 
5 Boost Software License - Version 1.0 - August 17th, 2003
6 
7 Permission is hereby granted, free of charge, to any person or organization
8 obtaining a copy of the software and accompanying documentation covered by
9 this license (the "Software") to use, reproduce, display, distribute,
10 execute, and transmit the Software, and to prepare derivative works of the
11 Software, and to permit third-parties to whom the Software is furnished to
12 do so, all subject to the following:
13 
14 The copyright notices in the Software and this entire statement, including
15 the above license grant, this restriction and the following disclaimer,
16 must be included in all copies of the Software, in whole or in part, and
17 all derivative works of the Software, unless such copies or derivative
18 works are solely in the form of machine-executable object code generated by
19 a source language processor.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28 */
29 
30 // This is a byte oriented implementation
31 // Note: this implementation does not handle message longer than
32 // 2^32 bytes.
33 
34 #ifndef LIB_SHA1_H
35 #define LIB_SHA1_H
36 
37 #include <cstddef>
38 
39 static_assert(sizeof(unsigned char)*8 == 8, "Please reboot the C universe.");
40 static_assert(sizeof(unsigned int)*8 == 32, "sizeof(unsigned int) == 4");
41 
42 #define SHA_DIGEST_LENGTH 20
43 
44 class sha1
45 {
46 public:
47  typedef unsigned int(&digest_type)[5];
48 public:
49  sha1();
50 
51  void reset();
52 
53  void process_byte(unsigned char byte);
54  void process_block(void const* bytes_begin, void const* bytes_end);
55  void process_bytes(void const* buffer, std::size_t byte_count);
56 
57  void get_digest(digest_type digest);
58 
59 private:
60  void process_block();
61  static unsigned int left_rotate(unsigned int x, std::size_t n)
62  {
63  return (x<<n) ^ (x>> (32-n));
64  }
65 
66 private:
67  unsigned int h_[5];
68 
69  unsigned char block_[64];
70 
71  std::size_t block_byte_index_;
72  std::size_t byte_count_;
73 };
74 
75 inline sha1::sha1()
76 {
77  reset();
78 }
79 
80 inline void sha1::reset()
81 {
82  h_[0] = 0x67452301;
83  h_[1] = 0xEFCDAB89;
84  h_[2] = 0x98BADCFE;
85  h_[3] = 0x10325476;
86  h_[4] = 0xC3D2E1F0;
87 
88  block_byte_index_ = 0;
89  byte_count_ = 0;
90 }
91 
92 inline void sha1::process_byte(unsigned char byte)
93 {
94  block_[block_byte_index_++] = byte;
95  ++byte_count_;
96  if (block_byte_index_ == 64) {
97  block_byte_index_ = 0;
98  process_block();
99  }
100 }
101 
102 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
103 {
104  unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
105  unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
106  for(; begin != end; ++begin) {
107  process_byte(*begin);
108  }
109 }
110 
111 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
112 {
113  unsigned char const* b = static_cast<unsigned char const*>(buffer);
114  process_block(b, b+byte_count);
115 }
116 
117 inline void sha1::process_block()
118 {
119  unsigned int w[80];
120  for (std::size_t i=0; i<16; ++i) {
121  w[i] = (block_[i*4 + 0] << 24);
122  w[i] |= (block_[i*4 + 1] << 16);
123  w[i] |= (block_[i*4 + 2] << 8);
124  w[i] |= (block_[i*4 + 3]);
125  }
126  for (std::size_t i=16; i<80; ++i) {
127  w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
128  }
129 
130  unsigned int a = h_[0];
131  unsigned int b = h_[1];
132  unsigned int c = h_[2];
133  unsigned int d = h_[3];
134  unsigned int e = h_[4];
135 
136  for (std::size_t i=0; i<80; ++i) {
137  unsigned int f;
138  unsigned int k;
139 
140  if (i<20) {
141  f = (b & c) | (~b & d);
142  k = 0x5A827999;
143  } else if (i<40) {
144  f = b ^ c ^ d;
145  k = 0x6ED9EBA1;
146  } else if (i<60) {
147  f = (b & c) | (b & d) | (c & d);
148  k = 0x8F1BBCDC;
149  } else {
150  f = b ^ c ^ d;
151  k = 0xCA62C1D6;
152  }
153 
154  unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
155  e = d;
156  d = c;
157  c = left_rotate(b, 30);
158  b = a;
159  a = temp;
160  }
161 
162  h_[0] += a;
163  h_[1] += b;
164  h_[2] += c;
165  h_[3] += d;
166  h_[4] += e;
167 }
168 
169 inline void sha1::get_digest(digest_type digest)
170 {
171  std::size_t bit_count = byte_count_*8;
172 
173  // append the bit '1' to the message
174  process_byte(0x80);
175 
176  // append k bits '0', where k is the minimum number >= 0
177  // such that the resulting message length is congruent to 56 (mod 64)
178  // check if there is enough space for padding and bit_count
179  if (block_byte_index_ > 56) {
180  // finish this block
181  while (block_byte_index_ != 0) {
182  process_byte(0);
183  }
184 
185  // one more block
186  while (block_byte_index_ < 56) {
187  process_byte(0);
188  }
189  } else {
190  while (block_byte_index_ < 56) {
191  process_byte(0);
192  }
193  }
194 
195  // append length of message (before pre-processing)
196  // as a 64-bit big-endian integer
197  process_byte(0);
198  process_byte(0);
199  process_byte(0);
200  process_byte(0);
201  process_byte( static_cast<unsigned char>((bit_count>>24) & 0xFF));
202  process_byte( static_cast<unsigned char>((bit_count>>16) & 0xFF));
203  process_byte( static_cast<unsigned char>((bit_count>>8 ) & 0xFF));
204  process_byte( static_cast<unsigned char>((bit_count) & 0xFF));
205 
206  // get final digest
207  digest[0] = h_[0];
208  digest[1] = h_[1];
209  digest[2] = h_[2];
210  digest[3] = h_[3];
211  digest[4] = h_[4];
212 }
213 
214 #endif
#define b
#define a