AnCH Framework  0.1
Another C++ Hack Framework
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
sha2.hpp
1 /*
2  ANCH Framework: ANother C++ Hack is a C++ framework based on C++11 standard
3  Copyright (C) 2012 Vincent Lachenal
4 
5  This file is part of ANCH Framework.
6 
7  ANCH Framework is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  ANCH Framework is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with ANCH Framework. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #ifndef _ANCH_CRYPTO_SHA2_H_
21 #define _ANCH_CRYPTO_SHA2_H_
22 
23 #include "crypto/hash/hash.hpp"
24 #include "endianness.hpp"
25 
26 #include <cstring>
27 
28 namespace anch {
29  namespace crypto {
30 
50  template<std::size_t O, std::size_t B, typename W, uint32_t R, const std::array<W,8>& I>
51  class SHA2: public Hash<O,B> {
52 
53  private:
59  typedef union {
61  uint8_t bytes[B * sizeof(W)];
62 
64  W words[B];
65  } Chunk;
66 
72  template<const std::array<W,8>& Init>
73  struct Context {
75  std::array<W,8> state;
76 
78  uint64_t size;
79 
81  uint8_t buffer[B];
82 
84  std::array<uint8_t,O> digest;
85 
89  Context() {
90  reset();
91  }
92 
96  void reset() {
97  state = Init;
98  size = 0;
99  }
100  };
101 
102  // Attributes +
104  Context<I> _context;
105  // Attributes -
106 
107 
108  // Constructors +
109  public:
113  SHA2(): Hash<O,B>(), _context() {
114  // Nothing to do
115  }
116  // Constructors -
117 
118  public:
119  // Destructor +
123  virtual ~SHA2() {
124  // Nothing to do
125  }
126  // Destructor -
127 
128 
129  // Methods +
130  public:
136  virtual const std::array<uint8_t,O>& digest() const override {
137  return _context.digest;
138  }
139 
140  protected:
147  static constexpr inline W shiftRight(uint8_t bits, W word) {
148  return (word >> bits);
149  }
150 
157  static constexpr inline W rotateLeft(uint8_t bits, W word) {
158  return ((word << bits) | (word >> (sizeof(W) * 8 - bits)));
159  }
160 
167  static constexpr inline W rotateRight(uint8_t bits, W word) {
168  return ((word >> bits) | (word << (sizeof(W) * 8 - bits)));
169  }
170 
171  private:
175  virtual void reset() override {
176  _context.reset();
177  }
178 
185  virtual void addData(const uint8_t* data, std::size_t len) override {
186  uint32_t rest = static_cast<uint32_t>(_context.size & static_cast<uint64_t>(B - 1));
187 
188  uint64_t availableData = static_cast<uint64_t>(len) + static_cast<uint64_t>(rest);
189  _context.size += len;
190 
191  if(availableData < static_cast<uint64_t>(B)) {
192  std::memcpy(&_context.buffer[rest], &data[0], len);
193 
194  } else {
195  uint64_t i = static_cast<uint64_t>(B - rest);
196  std::memcpy(&_context.buffer[rest], &data[0], static_cast<uint32_t>(i));
197  transform(_context.buffer);
198 
199  uint64_t lastI = len - ((len + rest) & static_cast<uint64_t>(B - 1));
200  for( ; i < lastI ; i += B) {
201  transform(&data[i]);
202  }
203 
204  std::memcpy(&_context.buffer[0], &data[i], len - i);
205  }
206  }
207 
211  virtual void finalize() override {
212  uint64_t messageSize = _context.size;
213  uint8_t sizeInBits[sizeof(W) * 2];
214  if(anch::isLittleEndian()) {
215  anch::byteSwap(messageSize << 3, sizeInBits);
216  } else {
217  uint64_t tmp = messageSize << 3;
218  std::memcpy(sizeInBits, &tmp, sizeof(W) * 2);
219  }
220 
221  addData((const uint8_t*)"\200", 1);
222 
223  uint8_t zero[B];
224  std::memset(zero, 0, B);
225  if(static_cast<int>(messageSize & (B - 1)) > (B - sizeof(W) * 2 - 1)) {
226  addData(zero, B - 1 - static_cast<size_t>(messageSize & (B - 1)));
227  addData(zero, B - 8);
228  } else {
229  addData(zero, B - 1 - 8 - static_cast<size_t>(messageSize & (B - 1)));
230  }
231 
232  addData(sizeInBits, 8);
233 
234  if(anch::isLittleEndian()) {
235  for(std::size_t i = 0 ; i < 8 ; i++) {
236  anch::byteSwap(_context.state[i], _context.digest.data() + (i * sizeof(W)));
237  }
238  } else {
239  std::memcpy(_context.digest.data(),
240  _context.state.data(),
241  sizeof(W) * O);
242  }
243  }
244 
250  virtual const std::array<W,R>& getTranslationArray() const = 0;
251 
257  void transform(const uint8_t* buffer) {
258  uint8_t chunkBuffer[B * sizeof(W)];
259  std::memcpy(chunkBuffer, buffer, B * sizeof(W));
260 
261  Chunk* chunk = reinterpret_cast<Chunk*>(&chunkBuffer);
262  bytesSwap(chunk->words, B);
263  for(std::size_t i = 16 ; i < B ; i++) {
264  chunk->words[i] = sigma1(chunk->words[i-2]) + chunk->words[i-7]
265  + sigma0(chunk->words[i-15]) + chunk->words[i-16];
266  }
267 
268  // Copy state[] to working vars
269  W a = _context.state[0];
270  W b = _context.state[1];
271  W c = _context.state[2];
272  W d = _context.state[3];
273  W e = _context.state[4];
274  W f = _context.state[5];
275  W g = _context.state[6];
276  W h = _context.state[7];
277 
278  const std::array<W,R>& trArray = getTranslationArray();
279  for(uint32_t i = 0 ; i < R ; i++) {
280  W temp1 = h + SIGMA1(e) + ch(e, f, g) + trArray[i] + chunk->words[i];
281  W temp2 = SIGMA0(a) + maj(a, b, c);
282  h = g;
283  g = f;
284  f = e;
285  e = d + temp1;
286  d = c;
287  c = b;
288  b = a;
289  a = temp1 + temp2;
290  }
291 
292  // Add the working vars back into state
293  _context.state[0] += a;
294  _context.state[1] += b;
295  _context.state[2] += c;
296  _context.state[3] += d;
297  _context.state[4] += e;
298  _context.state[5] += f;
299  _context.state[6] += g;
300  _context.state[7] += h;
301  }
302 
309  static inline void bytesSwap(W* buf, uint8_t count) {
310  if(anch::isLittleEndian()) {
311  uint8_t* words = reinterpret_cast<uint8_t*>(buf);
312  do {
313  anch::byteSwap(*buf,words);
314  buf++;
315  words += sizeof(W);
316  } while(--count);
317  }
318  }
319 
327  static inline W ch(W x, W y, W z) {
328  return ((x & (y ^ z)) ^ z);
329  }
330 
338  static inline W maj(W x, W y, W z) {
339  return ((x & (y | z)) | (y & z));
340  }
341 
347  virtual W SIGMA0(W word) const = 0;
348 
354  virtual W SIGMA1(W word) const = 0;
355 
361  virtual W sigma0(W word) const = 0;
362 
368  virtual W sigma1(W word) const = 0;
369  // Methods -
370 
371  };
372 
373  }
374 }
375 
376 #endif // _ANCH_CRYPTO_SHA2_H_
virtual const std::array< uint8_t, O > & digest() const override
Definition: sha2.hpp:136
SHA2 abstract class.
Definition: sha2.hpp:51
AnCH framework base namespace.
Definition: base64.hpp:28
SHA2()
Definition: sha2.hpp:113
static constexpr W rotateLeft(uint8_t bits, W word)
Definition: sha2.hpp:157
void byteSwap(T src, uint8_t *dest)
Definition: endianness.hpp:39
Hash algorithm abstract class.
Definition: hash.hpp:41
virtual ~SHA2()
Definition: sha2.hpp:123
static constexpr W shiftRight(uint8_t bits, W word)
Definition: sha2.hpp:147
bool isLittleEndian()
Definition: endianness.hpp:70
static constexpr W rotateRight(uint8_t bits, W word)
Definition: sha2.hpp:167