RDFS
The Rice Comp413 2017 class' continuation on the work of the 2016 RDFS.
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
crypto.h
1 #ifndef SIMPLE_WEB_CRYPTO_HPP
2 #define SIMPLE_WEB_CRYPTO_HPP
3 
4 #include <cmath>
5 #include <iomanip>
6 #include <istream>
7 #include <sstream>
8 #include <string>
9 #include <vector>
10 
11 #include <openssl/buffer.h>
12 #include <openssl/evp.h>
13 #include <openssl/md5.h>
14 #include <openssl/sha.h>
15 
16 namespace SimpleWeb {
17 // TODO 2017: remove workaround for MSVS 2012
18 #if _MSC_VER == 1700 // MSVS 2012 has no definition for round()
19  inline double round(double x) noexcept { // Custom definition of round() for positive numbers
20  return floor(x + 0.5);
21  }
22 #endif
23 
24  class Crypto {
25  const static std::size_t buffer_size = 131072;
26 
27  public:
28  class Base64 {
29  public:
30  static std::string encode(const std::string &ascii) noexcept {
31  std::string base64;
32 
33  BIO *bio, *b64;
34  BUF_MEM *bptr = BUF_MEM_new();
35 
36  b64 = BIO_new(BIO_f_base64());
37  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
38  bio = BIO_new(BIO_s_mem());
39  BIO_push(b64, bio);
40  BIO_set_mem_buf(b64, bptr, BIO_CLOSE);
41 
42  // Write directly to base64-buffer to avoid copy
43  auto base64_length = static_cast<std::size_t>(round(4 * ceil(static_cast<double>(ascii.size()) / 3.0)));
44  base64.resize(base64_length);
45  bptr->length = 0;
46  bptr->max = base64_length + 1;
47  bptr->data = &base64[0];
48 
49  if(BIO_write(b64, &ascii[0], static_cast<int>(ascii.size())) <= 0 || BIO_flush(b64) <= 0)
50  base64.clear();
51 
52  // To keep &base64[0] through BIO_free_all(b64)
53  bptr->length = 0;
54  bptr->max = 0;
55  bptr->data = nullptr;
56 
57  BIO_free_all(b64);
58 
59  return base64;
60  }
61 
62  static std::string decode(const std::string &base64) noexcept {
63  std::string ascii;
64 
65  // Resize ascii, however, the size is a up to two bytes too large.
66  ascii.resize((6 * base64.size()) / 8);
67  BIO *b64, *bio;
68 
69  b64 = BIO_new(BIO_f_base64());
70  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
71  bio = BIO_new_mem_buf(&base64[0], static_cast<int>(base64.size()));
72  bio = BIO_push(b64, bio);
73 
74  auto decoded_length = BIO_read(bio, &ascii[0], static_cast<int>(ascii.size()));
75  if(decoded_length > 0)
76  ascii.resize(static_cast<std::size_t>(decoded_length));
77  else
78  ascii.clear();
79 
80  BIO_free_all(b64);
81 
82  return ascii;
83  }
84  };
85 
87  static std::string to_hex_string(const std::string &input) noexcept {
88  std::stringstream hex_stream;
89  hex_stream << std::hex << std::internal << std::setfill('0');
90  for(auto &byte : input)
91  hex_stream << std::setw(2) << static_cast<int>(static_cast<unsigned char>(byte));
92  return hex_stream.str();
93  }
94 
95  static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept {
96  std::string hash;
97 
98  hash.resize(128 / 8);
99  MD5(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
100 
101  for(std::size_t c = 1; c < iterations; ++c)
102  MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
103 
104  return hash;
105  }
106 
107  static std::string md5(std::istream &stream, std::size_t iterations = 1) noexcept {
108  MD5_CTX context;
109  MD5_Init(&context);
110  std::streamsize read_length;
111  std::vector<char> buffer(buffer_size);
112  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
113  MD5_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
114  std::string hash;
115  hash.resize(128 / 8);
116  MD5_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
117 
118  for(std::size_t c = 1; c < iterations; ++c)
119  MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
120 
121  return hash;
122  }
123 
124  static std::string sha1(const std::string &input, std::size_t iterations = 1) noexcept {
125  std::string hash;
126 
127  hash.resize(160 / 8);
128  SHA1(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
129 
130  for(std::size_t c = 1; c < iterations; ++c)
131  SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
132 
133  return hash;
134  }
135 
136  static std::string sha1(std::istream &stream, std::size_t iterations = 1) noexcept {
137  SHA_CTX context;
138  SHA1_Init(&context);
139  std::streamsize read_length;
140  std::vector<char> buffer(buffer_size);
141  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
142  SHA1_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
143  std::string hash;
144  hash.resize(160 / 8);
145  SHA1_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
146 
147  for(std::size_t c = 1; c < iterations; ++c)
148  SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
149 
150  return hash;
151  }
152 
153  static std::string sha256(const std::string &input, std::size_t iterations = 1) noexcept {
154  std::string hash;
155 
156  hash.resize(256 / 8);
157  SHA256(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
158 
159  for(std::size_t c = 1; c < iterations; ++c)
160  SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
161 
162  return hash;
163  }
164 
165  static std::string sha256(std::istream &stream, std::size_t iterations = 1) noexcept {
166  SHA256_CTX context;
167  SHA256_Init(&context);
168  std::streamsize read_length;
169  std::vector<char> buffer(buffer_size);
170  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
171  SHA256_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
172  std::string hash;
173  hash.resize(256 / 8);
174  SHA256_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
175 
176  for(std::size_t c = 1; c < iterations; ++c)
177  SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
178 
179  return hash;
180  }
181 
182  static std::string sha512(const std::string &input, std::size_t iterations = 1) noexcept {
183  std::string hash;
184 
185  hash.resize(512 / 8);
186  SHA512(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0]));
187 
188  for(std::size_t c = 1; c < iterations; ++c)
189  SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
190 
191  return hash;
192  }
193 
194  static std::string sha512(std::istream &stream, std::size_t iterations = 1) noexcept {
195  SHA512_CTX context;
196  SHA512_Init(&context);
197  std::streamsize read_length;
198  std::vector<char> buffer(buffer_size);
199  while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0)
200  SHA512_Update(&context, buffer.data(), static_cast<std::size_t>(read_length));
201  std::string hash;
202  hash.resize(512 / 8);
203  SHA512_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context);
204 
205  for(std::size_t c = 1; c < iterations; ++c)
206  SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0]));
207 
208  return hash;
209  }
210 
212  static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept {
213  std::string key;
214  key.resize(static_cast<std::size_t>(key_size));
215  PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
216  reinterpret_cast<const unsigned char *>(salt.c_str()), salt.size(), iterations,
217  key_size, reinterpret_cast<unsigned char *>(&key[0]));
218  return key;
219  }
220  };
221 }
222 #endif /* SIMPLE_WEB_CRYPTO_HPP */
static std::string to_hex_string(const std::string &input) noexcept
Return hex string from bytes in input string.
Definition: crypto.h:87
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept
key_size is number of bytes of the returned key.
Definition: crypto.h:212
Definition: crypto.h:24
Definition: crypto.h:28