8 #include <botan/bcrypt.h>
9 #include <botan/loadstor.h>
10 #include <botan/blowfish.h>
11 #include <botan/base64.h>
17 std::string bcrypt_base64_encode(
const uint8_t input[],
size_t length)
20 const uint8_t OPENBSD_BASE64_SUB[256] = {
21 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
22 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
23 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
24 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39,
25 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80,
26 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45,
27 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
28 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80,
29 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
30 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
31 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
32 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
33 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
34 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
35 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
36 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
37 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
38 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
39 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
40 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
41 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
42 0x80, 0x80, 0x80, 0x80
47 while(b64.size() && b64[b64.size()-1] ==
'=')
48 b64 = b64.substr(0, b64.size() - 1);
50 for(
size_t i = 0; i != b64.size(); ++i)
51 b64[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(b64[i])];
56 std::vector<uint8_t> bcrypt_base64_decode(std::string input)
58 const uint8_t OPENBSD_BASE64_SUB[256] = {
59 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
60 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
61 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
62 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42,
63 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80,
64 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
65 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
66 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80,
67 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
68 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
69 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
70 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
71 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
72 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
73 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
74 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
75 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
76 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
77 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
78 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
79 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
80 0x80, 0x80, 0x80, 0x80
83 for(
size_t i = 0; i != input.size(); ++i)
84 input[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(input[i])];
89 std::string make_bcrypt(
const std::string& pass,
90 const std::vector<uint8_t>& salt,
93 auto magic = std::vector<uint8_t>{
94 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42,
95 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53,
96 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74
99 std::vector<uint8_t> ctext = magic;
104 blowfish.eks_key_schedule(reinterpret_cast<const uint8_t*>(pass.c_str()),
109 for(
size_t i = 0; i != 64; ++i)
110 blowfish.encrypt_n(ctext.data(), ctext.data(), 3);
112 std::string salt_b64 = bcrypt_base64_encode(salt.data(), salt.size());
115 if(work_factor_str.length() == 1)
116 work_factor_str =
"0" + work_factor_str;
118 return "$2a$" + work_factor_str +
119 "$" + salt_b64.substr(0, 22) +
120 bcrypt_base64_encode(ctext.data(), ctext.size() - 1);
127 uint16_t work_factor)
134 if(hash.size() != 60 ||
135 hash[0] !=
'$' || hash[1] !=
'2' || hash[2] !=
'a' ||
136 hash[3] !=
'$' || hash[6] !=
'$')
141 const uint16_t workfactor =
to_u32bit(hash.substr(4, 2));
143 const std::vector<uint8_t> salt = bcrypt_base64_decode(hash.substr(7, 22));
144 if(salt.size() != 16)
147 const std::string compare = make_bcrypt(pass, salt, workfactor);
149 return same_mem(hash.data(), compare.data(), compare.size());
uint32_t to_u32bit(const std::string &str)
secure_vector< uint8_t > random_vec(size_t bytes)
bool same_mem(const T *p1, const T *p2, size_t n)
std::string generate_bcrypt(const std::string &pass, RandomNumberGenerator &rng, uint16_t work_factor)
size_t base64_decode(uint8_t output[], const char input[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
bool check_bcrypt(const std::string &pass, const std::string &hash)
std::string to_string(const BER_Object &obj)
std::vector< T > unlock(const secure_vector< T > &in)
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)