Botan  2.1.0
Crypto and TLS for C++11
bcrypt.cpp
Go to the documentation of this file.
1 /*
2 * Bcrypt Password Hashing
3 * (C) 2010 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/bcrypt.h>
9 #include <botan/loadstor.h>
10 #include <botan/blowfish.h>
11 #include <botan/base64.h>
12 
13 namespace Botan {
14 
15 namespace {
16 
17 std::string bcrypt_base64_encode(const uint8_t input[], size_t length)
18  {
19  // Bcrypt uses a non-standard base64 alphabet
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
43  };
44 
45  std::string b64 = base64_encode(input, length);
46 
47  while(b64.size() && b64[b64.size()-1] == '=')
48  b64 = b64.substr(0, b64.size() - 1);
49 
50  for(size_t i = 0; i != b64.size(); ++i)
51  b64[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(b64[i])];
52 
53  return b64;
54  }
55 
56 std::vector<uint8_t> bcrypt_base64_decode(std::string input)
57  {
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
81  };
82 
83  for(size_t i = 0; i != input.size(); ++i)
84  input[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(input[i])];
85 
86  return unlock(base64_decode(input));
87  }
88 
89 std::string make_bcrypt(const std::string& pass,
90  const std::vector<uint8_t>& salt,
91  uint16_t work_factor)
92  {
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
97  };
98 
99  std::vector<uint8_t> ctext = magic;
100 
101  Blowfish blowfish;
102 
103  // Include the trailing NULL byte
104  blowfish.eks_key_schedule(reinterpret_cast<const uint8_t*>(pass.c_str()),
105  pass.length() + 1,
106  salt.data(),
107  work_factor);
108 
109  for(size_t i = 0; i != 64; ++i)
110  blowfish.encrypt_n(ctext.data(), ctext.data(), 3);
111 
112  std::string salt_b64 = bcrypt_base64_encode(salt.data(), salt.size());
113 
114  std::string work_factor_str = std::to_string(work_factor);
115  if(work_factor_str.length() == 1)
116  work_factor_str = "0" + work_factor_str;
117 
118  return "$2a$" + work_factor_str +
119  "$" + salt_b64.substr(0, 22) +
120  bcrypt_base64_encode(ctext.data(), ctext.size() - 1);
121  }
122 
123 }
124 
125 std::string generate_bcrypt(const std::string& pass,
127  uint16_t work_factor)
128  {
129  return make_bcrypt(pass, unlock(rng.random_vec(16)), work_factor);
130  }
131 
132 bool check_bcrypt(const std::string& pass, const std::string& hash)
133  {
134  if(hash.size() != 60 ||
135  hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' ||
136  hash[3] != '$' || hash[6] != '$')
137  {
138  return false;
139  }
140 
141  const uint16_t workfactor = to_u32bit(hash.substr(4, 2));
142 
143  const std::vector<uint8_t> salt = bcrypt_base64_decode(hash.substr(7, 22));
144  if(salt.size() != 16)
145  return false;
146 
147  const std::string compare = make_bcrypt(pass, salt, workfactor);
148 
149  return same_mem(hash.data(), compare.data(), compare.size());
150  }
151 
152 }
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:18
secure_vector< uint8_t > random_vec(size_t bytes)
Definition: rng.h:133
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
std::string generate_bcrypt(const std::string &pass, RandomNumberGenerator &rng, uint16_t work_factor)
Definition: bcrypt.cpp:125
size_t base64_decode(uint8_t output[], const char input[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition: base64.cpp:100
bool check_bcrypt(const std::string &pass, const std::string &hash)
Definition: bcrypt.cpp:132
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Definition: alg_id.cpp:13
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:125
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:35
MechanismType hash