tlx
sha1.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * tlx/digest/sha1.cpp
3  *
4  * Public domain implementation of SHA-1 processor. Based on LibTomCrypt from
5  * https://github.com/libtom/libtomcrypt.git
6  *
7  * Part of tlx - http://panthema.net/tlx
8  *
9  * Copyright (C) 2018 Timo Bingmann <tb@panthema.net>
10  *
11  * All rights reserved. Published under the Boost Software License, Version 1.0
12  ******************************************************************************/
13 
14 #include <tlx/digest/sha1.hpp>
15 
16 #include <tlx/math/rol.hpp>
17 #include <tlx/string/hexdump.hpp>
18 
19 namespace tlx {
20 
21 /*
22  * LibTomCrypt, modular cryptographic library -- Tom St Denis
23  *
24  * LibTomCrypt is a library that provides various cryptographic algorithms in a
25  * highly modular and flexible manner.
26  *
27  * The library is free for all purposes without any express guarantee it works.
28  */
29 
30 namespace digest_detail {
31 
32 static inline uint32_t min(uint32_t x, uint32_t y) {
33  return x < y ? x : y;
34 }
35 
36 static inline void store64h(uint64_t x, unsigned char* y) {
37  for (int i = 0; i != 8; ++i)
38  y[i] = (x >> ((7 - i) * 8)) & 255;
39 }
40 static inline uint32_t load32h(const uint8_t* y) {
41  return (uint32_t(y[0]) << 24) | (uint32_t(y[1]) << 16) |
42  (uint32_t(y[2]) << 8) | (uint32_t(y[3]) << 0);
43 }
44 static inline void store32h(uint32_t x, uint8_t* y) {
45  for (int i = 0; i != 4; ++i)
46  y[i] = (x >> ((3 - i) * 8)) & 255;
47 }
48 
49 static inline
50 uint32_t F0(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
51  return (z ^ (x & (y ^ z)));
52 }
53 static inline
54 uint32_t F1(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
55  return (x ^ y ^ z);
56 }
57 static inline
58 uint32_t F2(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
59  return ((x & y) | (z & (x | y)));
60 }
61 static inline
62 uint32_t F3(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
63  return (x ^ y ^ z);
64 }
65 
66 static void sha1_compress(uint32_t state[4], const uint8_t* buf) {
67  uint32_t a, b, c, d, e, W[80], i, t;
68 
69  /* copy the state into 512-bits into W[0..15] */
70  for (i = 0; i < 16; i++) {
71  W[i] = load32h(buf + (4 * i));
72  }
73 
74  /* copy state */
75  a = state[0];
76  b = state[1];
77  c = state[2];
78  d = state[3];
79  e = state[4];
80 
81  /* expand it */
82  for (i = 16; i < 80; i++) {
83  W[i] = rol32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
84  }
85 
86  /* compress */
87  for (i = 0; i < 20; ++i) {
88  e = (rol32(a, 5) + F0(b, c, d) + e + W[i] + 0x5a827999UL);
89  b = rol32(b, 30);
90  t = e, e = d, d = c, c = b, b = a, a = t;
91  }
92  for ( ; i < 40; ++i) {
93  e = (rol32(a, 5) + F1(b, c, d) + e + W[i] + 0x6ed9eba1UL);
94  b = rol32(b, 30);
95  t = e, e = d, d = c, c = b, b = a, a = t;
96  }
97  for ( ; i < 60; ++i) {
98  e = (rol32(a, 5) + F2(b, c, d) + e + W[i] + 0x8f1bbcdcUL);
99  b = rol32(b, 30);
100  t = e, e = d, d = c, c = b, b = a, a = t;
101  }
102  for ( ; i < 80; ++i) {
103  e = (rol32(a, 5) + F3(b, c, d) + e + W[i] + 0xca62c1d6UL);
104  b = rol32(b, 30);
105  t = e, e = d, d = c, c = b, b = a, a = t;
106  }
107 
108  /* store */
109  state[0] = state[0] + a;
110  state[1] = state[1] + b;
111  state[2] = state[2] + c;
112  state[3] = state[3] + d;
113  state[4] = state[4] + e;
114 }
115 
116 } // namespace digest_detail
117 
119  curlen_ = 0;
120  length_ = 0;
121  state_[0] = 0x67452301UL;
122  state_[1] = 0xefcdab89UL;
123  state_[2] = 0x98badcfeUL;
124  state_[3] = 0x10325476UL;
125  state_[4] = 0xc3d2e1f0UL;
126 }
127 
128 SHA1::SHA1(const void* data, uint32_t size) : SHA1() {
129  process(data, size);
130 }
131 
132 SHA1::SHA1(const std::string& str) : SHA1() {
133  process(str);
134 }
135 
136 void SHA1::process(const void* data, uint32_t size) {
137  const uint32_t block_size = sizeof(SHA1::buf_);
138  auto in = static_cast<const uint8_t*>(data);
139 
140  while (size > 0)
141  {
142  if (curlen_ == 0 && size >= block_size)
143  {
145  length_ += block_size * 8;
146  in += block_size;
147  size -= block_size;
148  }
149  else
150  {
151  uint32_t n = digest_detail::min(size, (block_size - curlen_));
152  uint8_t* b = buf_ + curlen_;
153  for (const uint8_t* a = in; a != in + n; ++a, ++b) {
154  *b = *a;
155  }
156  curlen_ += n;
157  in += n;
158  size -= n;
159 
160  if (curlen_ == block_size)
161  {
163  length_ += 8 * block_size;
164  curlen_ = 0;
165  }
166  }
167  }
168 }
169 
170 void SHA1::process(const std::string& str) {
171  return process(str.data(), str.size());
172 }
173 
174 void SHA1::finalize(void* digest) {
175  // Increase the length of the message
176  length_ += curlen_ * 8;
177 
178  // Append the '1' bit
179  buf_[curlen_++] = static_cast<uint8_t>(0x80);
180 
181  // If the length_ is currently above 56 bytes we append zeros then
182  // sha1_compress(). Then we can fall back to padding zeros and length
183  // encoding like normal.
184  if (curlen_ > 56) {
185  while (curlen_ < 64)
186  buf_[curlen_++] = 0;
188  curlen_ = 0;
189  }
190 
191  // Pad up to 56 bytes of zeroes
192  while (curlen_ < 56)
193  buf_[curlen_++] = 0;
194 
195  // Store length
198 
199  // Copy output
200  for (size_t i = 0; i < 5; i++)
201  digest_detail::store32h(state_[i], static_cast<uint8_t*>(digest) + (4 * i));
202 }
203 
204 std::string SHA1::digest() {
205  std::string out(kDigestLength, '0');
206  finalize(const_cast<char*>(out.data()));
207  return out;
208 }
209 
210 std::string SHA1::digest_hex() {
211  uint8_t digest[kDigestLength];
212  finalize(digest);
213  return hexdump_lc(digest, kDigestLength);
214 }
215 
216 std::string SHA1::digest_hex_uc() {
217  uint8_t digest[kDigestLength];
218  finalize(digest);
219  return hexdump(digest, kDigestLength);
220 }
221 
222 std::string sha1_hex(const void* data, uint32_t size) {
223  return SHA1(data, size).digest_hex();
224 }
225 
226 std::string sha1_hex(const std::string& str) {
227  return SHA1(str).digest_hex();
228 }
229 
230 std::string sha1_hex_uc(const void* data, uint32_t size) {
231  return SHA1(data, size).digest_hex_uc();
232 }
233 
234 std::string sha1_hex_uc(const std::string& str) {
235  return SHA1(str).digest_hex_uc();
236 }
237 
238 } // namespace tlx
239 
240 /******************************************************************************/
static uint32_t F3(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: sha1.cpp:62
void process(const void *data, uint32_t size)
process more data
Definition: sha1.cpp:136
static void store64h(uint64_t x, unsigned char *y)
Definition: sha1.cpp:36
SHA-1 processor without external dependencies.
Definition: sha1.hpp:28
static void store32h(uint32_t x, uint8_t *y)
Definition: sha1.cpp:44
uint8_t buf_[64]
Definition: sha1.hpp:60
static uint32_t load32h(const uint8_t *y)
Definition: sha1.cpp:40
std::string digest()
finalize computation and return 20 byte (160 bit) digest
Definition: sha1.cpp:204
std::string hexdump_lc(const void *const data, size_t size)
Dump a (binary) string as a sequence of lowercase hexadecimal pairs.
Definition: hexdump.cpp:95
uint32_t state_[5]
Definition: sha1.hpp:58
void finalize(void *digest)
finalize computation and output 20 byte (160 bit) digest
Definition: sha1.cpp:174
static uint32_t min(uint32_t x, uint32_t y)
Definition: md5.cpp:32
static uint32_t F0(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: sha1.cpp:50
SHA1()
construct empty object.
Definition: sha1.cpp:118
static uint32_t F2(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: sha1.cpp:58
static uint32_t rol32(const uint32_t &x, int i)
rol32 - generic
Definition: rol.hpp:55
static void sha1_compress(uint32_t state[4], const uint8_t *buf)
Definition: sha1.cpp:66
uint32_t curlen_
Definition: sha1.hpp:59
std::string digest_hex_uc()
finalize computation and return 20 byte (160 bit) digest upper-case hex
Definition: sha1.cpp:216
std::string sha1_hex(const void *data, uint32_t size)
process data and return 20 byte (160 bit) digest hex encoded
Definition: sha1.cpp:222
std::string hexdump(const void *const data, size_t size)
Dump a (binary) string as a sequence of uppercase hexadecimal pairs.
Definition: hexdump.cpp:21
static uint32_t F1(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: sha1.cpp:54
static constexpr size_t kDigestLength
digest length in bytes
Definition: sha1.hpp:44
std::string sha1_hex_uc(const void *data, uint32_t size)
process data and return 20 byte (160 bit) digest upper-case hex encoded
Definition: sha1.cpp:230
std::string digest_hex()
finalize computation and return 20 byte (160 bit) digest hex encoded
Definition: sha1.cpp:210
uint64_t length_
Definition: sha1.hpp:57