Created
March 15, 2021 00:07
-
-
Save marty1885/6615102db63ba879ee51b89537e332f0 to your computer and use it in GitHub Desktop.
Cryptographic (password hashing) library for Drogon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "crypto.hpp" | |
#include <regex> | |
#include <bsd/stdlib.h> | |
#include <botan/argon2.h> | |
#include <botan/system_rng.h> | |
static Botan::System_RNG rng; | |
uint32_t secureRandom(uint32_t lower, uint32_t upper) | |
{ | |
return lower+arc4random_uniform(upper-lower); | |
} | |
std::string secureRandomString(size_t length) | |
{ | |
const std::string_view alphabet = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
std::string result; | |
result.resize(length); | |
for(auto& ch : result) | |
ch = alphabet[secureRandom(0, alphabet.size())]; | |
return result; | |
} | |
static std::tuple<std::string, std::string, std::string> parse_passwdhash(const std::string& str) | |
{ | |
auto parts = drogon::utils::splitString(str, ":", true); | |
if(parts.size() <= 3) | |
throw std::runtime_error("Bad password hash format"); | |
// Just incase there's a : in the hash | |
auto hash = parts[2]; | |
for(size_t i=3;i<parts.size();i++) | |
hash = hash + ":" + parts[i]; | |
return {parts[0], parts[1], hash}; | |
} | |
std::string passwdhash::argon2(const std::string& passwd, size_t salt_length) | |
{ | |
auto salt = secureRandomString(salt_length); | |
auto salted_passwd = salt + passwd; | |
auto hash = Botan::argon2_generate_pwhash(salted_passwd.c_str(), salted_passwd.size(), rng, 1, 1, 4096); | |
return "ARGON2:"+salt+":"+salted_passwd; | |
} | |
bool passwdhash::argon2_verify(const std::string& passwd, const std::string& passwd_hash) | |
{ | |
auto [algo, salt, hash] = parse_passwdhash(passwd_hash); | |
if(algo != "ARGON2") | |
throw std::runtime_error("Not Argon2"); | |
return Botan::argon2_check_pwhash(passwd.c_str(), passwd.size(), hash); | |
} | |
std::string passwdhash::hash(const std::string& passwd, const std::string& algo, size_t salt_length) | |
{ | |
if(algo == "ARGON2") | |
return argon2(passwd, salt_length); | |
throw std::domain_error("Unknown password hash algorithm: " + algo); | |
} | |
bool passwdhash::verify(const std::string& passwd, const std::string& passwd_hash) | |
{ | |
auto [algo, salt, hash] = parse_passwdhash(passwd_hash); | |
if(algo == "ARGON2") | |
return argon2_verify(passwd, passwd_hash); | |
throw std::domain_error("Unknown password hash algorithm: " + algo); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string> | |
#include <cstdint> | |
#include <limits> | |
uint32_t secureRandom(uint32_t lower=0, uintmax_t uint32_t=std::numeric_limits<uint32_t>::max()); | |
std::string secureRandomString(size_t length=16); | |
namespace passwdhash | |
{ | |
std::string hash(const std::string& passwd, const std::string& algo="ARGON2", size_t salt_length=16); | |
bool verify(const std::string& passwd, const std::string& passwd_hash); | |
// NOTE: Expand the selection of algorithms here in the future to comidate new standards | |
// while maintaining compatibility | |
std::string argon2(const std::string& passwd, size_t salt_length); | |
bool argon2_verify(const std::string& passwd, const std::string& passwd_hash); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment