Added crypto.hpp for convenient C++ wrappings for commonly used OpenSSL functions
This commit is contained in:
parent
5cdf4aa540
commit
5c5a1f78b2
4 changed files with 214 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -15,3 +15,4 @@ http_examples
|
|||
https_examples
|
||||
io_test
|
||||
parse_test
|
||||
crypto_test
|
||||
|
|
|
|||
139
crypto.hpp
Normal file
139
crypto.hpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#ifndef CRYPTO_HPP
|
||||
#define CRYPTO_HPP
|
||||
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
//Moving these to a seperate namespace for minimal global namespace cluttering does not work with clang++
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
namespace SimpleWeb {
|
||||
//TODO 2017: remove workaround for MSVS 2012
|
||||
#if _MSC_VER == 1700 //MSVS 2012 has no definition for round()
|
||||
inline double round(double x) { //custom definition of round() for positive numbers
|
||||
return floor(x + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
class Crypto {
|
||||
public:
|
||||
class Base64 {
|
||||
public:
|
||||
static std::string encode(const std::string &ascii) {
|
||||
std::string base64;
|
||||
|
||||
BIO *bio, *b64;
|
||||
BUF_MEM *bptr=BUF_MEM_new();
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
BIO_push(b64, bio);
|
||||
BIO_set_mem_buf(b64, bptr, BIO_CLOSE);
|
||||
|
||||
//Write directly to base64-buffer to avoid copy
|
||||
int base64_length=static_cast<int>(round(4*ceil((double)ascii.size()/3.0)));
|
||||
base64.resize(base64_length);
|
||||
bptr->length=0;
|
||||
bptr->max=base64_length+1;
|
||||
bptr->data=(char*)&base64[0];
|
||||
|
||||
BIO_write(b64, &ascii[0], static_cast<int>(ascii.size()));
|
||||
BIO_flush(b64);
|
||||
|
||||
//To keep &base64[0] through BIO_free_all(b64)
|
||||
bptr->length=0;
|
||||
bptr->max=0;
|
||||
bptr->data=nullptr;
|
||||
|
||||
BIO_free_all(b64);
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
static std::string decode(const std::string &base64) {
|
||||
std::string ascii;
|
||||
|
||||
//Resize ascii, however, the size is a up to two bytes too large.
|
||||
ascii.resize((6*base64.size())/8);
|
||||
BIO *b64, *bio;
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
bio = BIO_new_mem_buf((char*)&base64[0], static_cast<int>(base64.size()));
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
int decoded_length = BIO_read(bio, &ascii[0], static_cast<int>(ascii.size()));
|
||||
ascii.resize(decoded_length);
|
||||
|
||||
BIO_free_all(b64);
|
||||
|
||||
return ascii;
|
||||
}
|
||||
};
|
||||
|
||||
/// Return hex string from bytes in input string.
|
||||
static std::string to_hex_string(const std::string &input) {
|
||||
std::stringstream hex_stream;
|
||||
hex_stream << std::hex << std::internal << std::setfill('0');
|
||||
for (auto &byte : input)
|
||||
hex_stream << std::setw(2) << static_cast<int>(static_cast<unsigned char>(byte));
|
||||
return hex_stream.str();
|
||||
}
|
||||
|
||||
static std::string MD5(const std::string &input, size_t iterations=1) {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(128 / 8);
|
||||
::MD5(reinterpret_cast<const unsigned char*>(&input[0]), input.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
for (size_t c = 1; c < iterations; ++c)
|
||||
::MD5(reinterpret_cast<const unsigned char*>(&hash[0]), hash.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string SHA1(const std::string &input, size_t iterations=1) {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(160 / 8);
|
||||
::SHA1(reinterpret_cast<const unsigned char*>(&input[0]), input.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
for (size_t c = 1; c < iterations; ++c)
|
||||
::SHA1(reinterpret_cast<const unsigned char*>(&hash[0]), hash.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string SHA256(const std::string &input, size_t iterations=1) {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(256 / 8);
|
||||
::SHA256(reinterpret_cast<const unsigned char*>(&input[0]), input.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
for (size_t c = 1; c < iterations; ++c)
|
||||
::SHA256(reinterpret_cast<const unsigned char*>(&hash[0]), hash.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string SHA512(const std::string &input, size_t iterations=1) {
|
||||
std::string hash;
|
||||
|
||||
hash.resize(512 / 8);
|
||||
::SHA512(reinterpret_cast<const unsigned char*>(&input[0]), input.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
for (size_t c = 1; c < iterations; ++c)
|
||||
::SHA512(reinterpret_cast<const unsigned char*>(&hash[0]), hash.size(), reinterpret_cast<unsigned char*>(&hash[0]));
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif /* CRYPTO_HPP */
|
||||
|
||||
|
|
@ -15,3 +15,9 @@ endif()
|
|||
|
||||
add_test(io_test io_test)
|
||||
add_test(parse_test parse_test)
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
add_executable(crypto_test crypto_test.cpp)
|
||||
target_link_libraries(crypto_test ${OPENSSL_CRYPTO_LIBRARY})
|
||||
add_test(crypto_test crypto_test)
|
||||
endif()
|
||||
|
|
|
|||
68
tests/crypto_test.cpp
Normal file
68
tests/crypto_test.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
|
||||
#include "crypto.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace SimpleWeb;
|
||||
|
||||
const vector<pair<string, string> > Base64_string_tests = {
|
||||
{"", ""},
|
||||
{"f" , "Zg=="},
|
||||
{"fo", "Zm8="},
|
||||
{"foo", "Zm9v"},
|
||||
{"foob", "Zm9vYg=="},
|
||||
{"fooba", "Zm9vYmE="},
|
||||
{"foobar", "Zm9vYmFy"}
|
||||
};
|
||||
|
||||
const vector<pair<string, string> > MD5_string_tests = {
|
||||
{"", "d41d8cd98f00b204e9800998ecf8427e"},
|
||||
{"The quick brown fox jumps over the lazy dog", "9e107d9d372bb6826bd81d3542a419d6"}
|
||||
};
|
||||
|
||||
const vector<pair<string, string> > SHA1_string_tests = {
|
||||
{"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
|
||||
{"The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"}
|
||||
};
|
||||
|
||||
const vector<pair<string, string> > SHA256_string_tests = {
|
||||
{"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
|
||||
{"The quick brown fox jumps over the lazy dog", "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"}
|
||||
};
|
||||
|
||||
const vector<pair<string, string> > SHA512_string_tests = {
|
||||
{"", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"},
|
||||
{"The quick brown fox jumps over the lazy dog", "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"}
|
||||
};
|
||||
|
||||
int main() {
|
||||
//Testing SimpleWeb::Crypt::Base64
|
||||
for(auto& string_test: Base64_string_tests) {
|
||||
assert(Crypto::Base64::encode(string_test.first)==string_test.second);
|
||||
assert(Crypto::Base64::decode(string_test.second)==string_test.first);
|
||||
}
|
||||
|
||||
//Testing SimpleWeb::Crypt::MD5
|
||||
for(auto& string_test: MD5_string_tests)
|
||||
assert(Crypto::to_hex_string(Crypto::MD5(string_test.first)) == string_test.second);
|
||||
|
||||
//Testing SimpleWeb::Crypt::SHA1
|
||||
for(auto& string_test: SHA1_string_tests)
|
||||
assert(Crypto::to_hex_string(Crypto::SHA1(string_test.first)) == string_test.second);
|
||||
|
||||
//Testing SimpleWeb::Crypt::SHA256
|
||||
for(auto& string_test: SHA256_string_tests)
|
||||
assert(Crypto::to_hex_string(Crypto::SHA256(string_test.first)) == string_test.second);
|
||||
|
||||
//Testing SimpleWeb::Crypt::SHA512
|
||||
for(auto& string_test: SHA512_string_tests)
|
||||
assert(Crypto::to_hex_string(Crypto::SHA512(string_test.first)) == string_test.second);
|
||||
|
||||
//Testing iterations
|
||||
assert(Crypto::to_hex_string(Crypto::SHA1("Test", 1)) == "640ab2bae07bedc4c163f679a746f7ab7fb5d1fa");
|
||||
assert(Crypto::to_hex_string(Crypto::SHA1("Test", 2)) == "af31c6cbdecd88726d0a9b3798c71ef41f1624d5");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue