Added stream versions of the Crypto:: hash functions for calculating hashes from for instance large files
This commit is contained in:
parent
9e29d2d572
commit
92ddf86e15
2 changed files with 94 additions and 11 deletions
83
crypto.hpp
83
crypto.hpp
|
|
@ -5,6 +5,8 @@
|
|||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <istream>
|
||||
#include <vector>
|
||||
|
||||
//Moving these to a seperate namespace for minimal global namespace cluttering does not work with clang++
|
||||
#include <openssl/evp.h>
|
||||
|
|
@ -21,6 +23,7 @@ namespace SimpleWeb {
|
|||
#endif
|
||||
|
||||
class Crypto {
|
||||
const static size_t buffer_size=131072;
|
||||
public:
|
||||
class Base64 {
|
||||
public:
|
||||
|
|
@ -97,6 +100,23 @@ namespace SimpleWeb {
|
|||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string md5(std::istream &stream, size_t iterations=1) {
|
||||
MD5_CTX context;
|
||||
MD5_Init(&context);
|
||||
std::streamsize read_length;
|
||||
std::vector<char> buffer(buffer_size);
|
||||
while((read_length=stream.read(&buffer[0], buffer_size).gcount())>0)
|
||||
MD5_Update(&context, buffer.data(), read_length);
|
||||
std::string hash;
|
||||
hash.resize(128 / 8);
|
||||
MD5_Final(reinterpret_cast<unsigned char*>(&hash[0]), &context);
|
||||
|
||||
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;
|
||||
|
|
@ -109,6 +129,23 @@ namespace SimpleWeb {
|
|||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha1(std::istream &stream, size_t iterations=1) {
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
std::streamsize read_length;
|
||||
std::vector<char> buffer(buffer_size);
|
||||
while((read_length=stream.read(&buffer[0], buffer_size).gcount())>0)
|
||||
SHA1_Update(&context, buffer.data(), read_length);
|
||||
std::string hash;
|
||||
hash.resize(160 / 8);
|
||||
SHA1_Final(reinterpret_cast<unsigned char*>(&hash[0]), &context);
|
||||
|
||||
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;
|
||||
|
|
@ -121,6 +158,23 @@ namespace SimpleWeb {
|
|||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static std::string sha256(std::istream &stream, size_t iterations=1) {
|
||||
SHA256_CTX context;
|
||||
SHA256_Init(&context);
|
||||
std::streamsize read_length;
|
||||
std::vector<char> buffer(buffer_size);
|
||||
while((read_length=stream.read(&buffer[0], buffer_size).gcount())>0)
|
||||
SHA256_Update(&context, buffer.data(), read_length);
|
||||
std::string hash;
|
||||
hash.resize(256 / 8);
|
||||
SHA256_Final(reinterpret_cast<unsigned char*>(&hash[0]), &context);
|
||||
|
||||
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;
|
||||
|
|
@ -134,15 +188,30 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns empty string on error. key_size is in bytes.
|
||||
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations = 4096, int key_size = 256 / 8) {
|
||||
static std::string sha512(std::istream &stream, size_t iterations=1) {
|
||||
SHA512_CTX context;
|
||||
SHA512_Init(&context);
|
||||
std::streamsize read_length;
|
||||
std::vector<char> buffer(buffer_size);
|
||||
while((read_length=stream.read(&buffer[0], buffer_size).gcount())>0)
|
||||
SHA512_Update(&context, buffer.data(), read_length);
|
||||
std::string hash;
|
||||
hash.resize(512 / 8);
|
||||
SHA512_Final(reinterpret_cast<unsigned char*>(&hash[0]), &context);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// key_size is number of bytes of the returned key.
|
||||
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) {
|
||||
std::string key;
|
||||
key.resize(key_size);
|
||||
auto success = PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
|
||||
reinterpret_cast<const unsigned char*>(salt.c_str()), salt.size(), iterations,
|
||||
key_size, reinterpret_cast<unsigned char*>(&key[0]));
|
||||
if (!success)
|
||||
return std::string();
|
||||
PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
|
||||
reinterpret_cast<const unsigned char*>(salt.c_str()), salt.size(), iterations,
|
||||
key_size, reinterpret_cast<unsigned char*>(&key[0]));
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,21 +42,35 @@ int main() {
|
|||
assert(Crypto::Base64::decode(string_test.second)==string_test.first);
|
||||
}
|
||||
|
||||
for(auto& string_test: md5_string_tests)
|
||||
for(auto& string_test: md5_string_tests) {
|
||||
assert(Crypto::to_hex_string(Crypto::md5(string_test.first)) == string_test.second);
|
||||
stringstream ss(string_test.first);
|
||||
assert(Crypto::to_hex_string(Crypto::md5(ss)) == string_test.second);
|
||||
}
|
||||
|
||||
for(auto& string_test: sha1_string_tests)
|
||||
for(auto& string_test: sha1_string_tests) {
|
||||
assert(Crypto::to_hex_string(Crypto::sha1(string_test.first)) == string_test.second);
|
||||
stringstream ss(string_test.first);
|
||||
assert(Crypto::to_hex_string(Crypto::sha1(ss)) == string_test.second);
|
||||
}
|
||||
|
||||
for(auto& string_test: sha256_string_tests)
|
||||
for(auto& string_test: sha256_string_tests) {
|
||||
assert(Crypto::to_hex_string(Crypto::sha256(string_test.first)) == string_test.second);
|
||||
stringstream ss(string_test.first);
|
||||
assert(Crypto::to_hex_string(Crypto::sha256(ss)) == string_test.second);
|
||||
}
|
||||
|
||||
for(auto& string_test: sha512_string_tests)
|
||||
for(auto& string_test: sha512_string_tests) {
|
||||
assert(Crypto::to_hex_string(Crypto::sha512(string_test.first)) == string_test.second);
|
||||
stringstream ss(string_test.first);
|
||||
assert(Crypto::to_hex_string(Crypto::sha512(ss)) == 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");
|
||||
stringstream ss("Test");
|
||||
assert(Crypto::to_hex_string(Crypto::sha1(ss, 2)) == "af31c6cbdecd88726d0a9b3798c71ef41f1624d5");
|
||||
|
||||
assert(Crypto::to_hex_string(Crypto::pbkdf2("Password", "Salt", 4096, 128 / 8)) == "f66df50f8aaa11e4d9721e1312ff2e66");
|
||||
assert(Crypto::to_hex_string(Crypto::pbkdf2("Password", "Salt", 8192, 512 / 8)) == "a941ccbc34d1ee8ebbd1d34824a419c3dc4eac9cbc7c36ae6c7ca8725e2b618a6ad22241e787af937b0960cf85aa8ea3a258f243e05d3cc9b08af5dd93be046c");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue