identt
Crypto.hpp
Go to the documentation of this file.
1 
33 #ifndef _IDENTT_HTTP_CRYPTO_HPP_
34 #define _IDENTT_HTTP_CRYPTO_HPP_
35 
36 #include <cmath>
37 #include <iomanip>
38 #include <istream>
39 #include <sstream>
40 #include <string>
41 #include <vector>
42 
43 #include <openssl/buffer.h>
44 #include <openssl/evp.h>
45 #include <openssl/md5.h>
46 #include <openssl/sha.h>
47 
48 namespace identt {
49 namespace http {
50 
51 // TODO 2017: remove workaround for MSVS 2012
52 #if _MSC_VER == 1700 // MSVS 2012 has no definition for round()
53 inline double round(double x) noexcept // Custom definition of round() for positive numbers
54 {
55  return floor(x + 0.5);
56 }
57 #endif
58 
59 class Crypto {
60  const static std::size_t buffer_size = 131072;
61 
62 public:
63  class Base64 {
64  public:
66  static std::string encode(const std::string &input) noexcept
67  {
68  std::string base64;
69 
70  BIO *bio, *b64;
71  BUF_MEM *bptr = BUF_MEM_new();
72 
73  b64 = BIO_new(BIO_f_base64());
74  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
75  bio = BIO_new(BIO_s_mem());
76  BIO_push(b64, bio);
77  BIO_set_mem_buf(b64, bptr, BIO_CLOSE);
78 
79  // Write directly to base64-buffer to avoid copy
80  auto base64_length = static_cast<std::size_t>(round(4 * ceil(static_cast<double>(input.size()) / 3.0)));
81  base64.resize(base64_length);
82  bptr->length = 0;
83  bptr->max = base64_length + 1;
84  bptr->data = &base64[0];
85 
86  if(BIO_write(b64, &input[0], static_cast<int>(input.size())) <= 0 || BIO_flush(b64) <= 0)
87  base64.clear();
88 
89  // To keep &base64[0] through BIO_free_all(b64)
90  bptr->length = 0;
91  bptr->max = 0;
92  bptr->data = nullptr;
93 
94  BIO_free_all(b64);
95 
96  return base64;
97  }
98 
100  static std::string decode(const std::string &base64) noexcept
101  {
102  std::string ascii;
103 
104  // Resize ascii, however, the size is a up to two bytes too large.
105  ascii.resize((6 * base64.size()) / 8);
106  BIO *b64, *bio;
107 
108  b64 = BIO_new(BIO_f_base64());
109  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
110  // TODO: Remove in 2020
111 #if(defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER <= 0x1000115fL) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2080000fL)
112  bio = BIO_new_mem_buf((char *)&base64[0], static_cast<int>(base64.size()));
113 #else
114  bio = BIO_new_mem_buf(&base64[0], static_cast<int>(base64.size()));
115 #endif
116  bio = BIO_push(b64, bio);
117 
118  auto decoded_length = BIO_read(bio, &ascii[0], static_cast<int>(ascii.size()));
119  if(decoded_length > 0)
120  ascii.resize(static_cast<std::size_t>(decoded_length));
121  else
122  ascii.clear();
123 
124  BIO_free_all(b64);
125 
126  return ascii;
127  }
128  };
129 
131  static std::string to_hex_string(const std::string &input) noexcept
132  {
133  std::stringstream hex_stream;
134  hex_stream << std::hex << std::internal << std::setfill('0');
135  for(auto &byte : input)
136  hex_stream << std::setw(2) << static_cast<int>(static_cast<unsigned char>(byte));
137  return hex_stream.str();
138  }
139 
141  static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept
142  {
143  std::string hash;
144 
145  hash.resize(128 / 8);
146  MD5(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
147 
148  for(std::size_t c = 1; c < iterations; ++c)
149  MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
150 
151  return hash;
152  }
153 
155  static std::string md5(std::istream &stream, std::size_t iterations = 1) noexcept
156  {
157  MD5_CTX context;
158  MD5_Init(&context);
159  std::streamsize read_length;
160  std::vector<char> buffer(buffer_size);
161  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
162  MD5_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
163  std::string hash;
164  hash.resize(128 / 8);
165  MD5_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
166 
167  for(std::size_t c = 1; c < iterations; ++c)
168  MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
169 
170  return hash;
171  }
172 
174  static std::string sha1(const std::string &input, std::size_t iterations = 1) noexcept
175  {
176  std::string hash;
177 
178  hash.resize(160 / 8);
179  SHA1(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
180 
181  for(std::size_t c = 1; c < iterations; ++c)
182  SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
183 
184  return hash;
185  }
186 
188  static std::string sha1(std::istream &stream, std::size_t iterations = 1) noexcept
189  {
190  SHA_CTX context;
191  SHA1_Init(&context);
192  std::streamsize read_length;
193  std::vector<char> buffer(buffer_size);
194  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
195  SHA1_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
196  std::string hash;
197  hash.resize(160 / 8);
198  SHA1_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
199 
200  for(std::size_t c = 1; c < iterations; ++c)
201  SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
202 
203  return hash;
204  }
205 
207  static std::string sha256(const std::string &input, std::size_t iterations = 1) noexcept
208  {
209  std::string hash;
210 
211  hash.resize(256 / 8);
212  SHA256(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
213 
214  for(std::size_t c = 1; c < iterations; ++c)
215  SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
216 
217  return hash;
218  }
219 
221  static std::string sha256(std::istream &stream, std::size_t iterations = 1) noexcept
222  {
223  SHA256_CTX context;
224  SHA256_Init(&context);
225  std::streamsize read_length;
226  std::vector<char> buffer(buffer_size);
227  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
228  SHA256_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
229  std::string hash;
230  hash.resize(256 / 8);
231  SHA256_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
232 
233  for(std::size_t c = 1; c < iterations; ++c)
234  SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
235 
236  return hash;
237  }
238 
240  static std::string sha512(const std::string &input, std::size_t iterations = 1) noexcept
241  {
242  std::string hash;
243 
244  hash.resize(512 / 8);
245  SHA512(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
246 
247  for(std::size_t c = 1; c < iterations; ++c)
248  SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
249 
250  return hash;
251  }
252 
254  static std::string sha512(std::istream &stream, std::size_t iterations = 1) noexcept
255  {
256  SHA512_CTX context;
257  SHA512_Init(&context);
258  std::streamsize read_length;
259  std::vector<char> buffer(buffer_size);
260  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
261  SHA512_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
262  std::string hash;
263  hash.resize(512 / 8);
264  SHA512_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
265 
266  for(std::size_t c = 1; c < iterations; ++c)
267  SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
268 
269  return hash;
270  }
271 
274 
285  static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept
286  {
287  std::string key;
288  key.resize(static_cast<std::size_t>(key_size));
289  PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
290  reinterpret_cast<const unsigned char *>(salt.c_str()), salt.size(), iterations,
291  key_size, reinterpret_cast<unsigned char *>(&key[0]));
292  return key;
293  }
294 };
295 
296 } // namespace http
297 } // namespace identt
298 #endif /* _IDENTT_HTTP_CRYPTO_HPP_ */
static std::string to_hex_string(const std::string &input) noexcept
Returns hex string from bytes in input string.
Definition: Crypto.hpp:131
static std::string decode(const std::string &base64) noexcept
Returns Base64 decoded string from base64 input.
Definition: Crypto.hpp:100
Definition: Crypto.hpp:59
static std::string sha1(std::istream &stream, std::size_t iterations=1) noexcept
Returns sha1 hash value from input stream.
Definition: Crypto.hpp:188
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept
Returns PBKDF2 hash value from the given password Input parameter key_size number of bytes of the ret...
Definition: Crypto.hpp:285
Definition: Crypto.hpp:63
static std::string md5(std::istream &stream, std::size_t iterations=1) noexcept
Returns md5 hash value from input stream.
Definition: Crypto.hpp:155
static std::string sha256(std::istream &stream, std::size_t iterations=1) noexcept
Returns sha256 hash value from input stream.
Definition: Crypto.hpp:221
static std::string encode(const std::string &input) noexcept
Returns Base64 encoded string from input string.
Definition: Crypto.hpp:66
Definition: CryptoBase.hpp:49
static std::string sha1(const std::string &input, std::size_t iterations=1) noexcept
Returns sha1 hash value from input string.
Definition: Crypto.hpp:174
static std::string sha256(const std::string &input, std::size_t iterations=1) noexcept
Returns sha256 hash value from input string.
Definition: Crypto.hpp:207
static std::string sha512(const std::string &input, std::size_t iterations=1) noexcept
Returns sha512 hash value from input string.
Definition: Crypto.hpp:240
static std::string sha512(std::istream &stream, std::size_t iterations=1) noexcept
Returns sha512 hash value from input stream.
Definition: Crypto.hpp:254
static std::string md5(const std::string &input, std::size_t iterations=1) noexcept
Returns md5 hash value from input string.
Definition: Crypto.hpp:141