Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

passhash9.cpp
Go to the documentation of this file.
1 /*
2 * Passhash9 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/passhash9.h>
9 #include <botan/loadstor.h>
10 #include <botan/pbkdf2.h>
11 #include <botan/base64.h>
12
13 namespace Botan {
14
15 namespace {
16
17 const std::string MAGIC_PREFIX = "$9$";
18
19 const size_t WORKFACTOR_BYTES = 2;
20 const size_t ALGID_BYTES = 1;
21 const size_t SALT_BYTES = 12; // 96 bits of salt
22 const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output
23
24 const size_t WORK_FACTOR_SCALE = 10000;
25
26 std::unique_ptr<MessageAuthenticationCode> get_pbkdf_prf(uint8_t alg_id)
27 {
28 if(alg_id == 0)
29 return MessageAuthenticationCode::create("HMAC(SHA-1)");
30 else if(alg_id == 1)
31 return MessageAuthenticationCode::create("HMAC(SHA-256)");
32 else if(alg_id == 2)
33 return MessageAuthenticationCode::create("CMAC(Blowfish)");
34 else if(alg_id == 3)
35 return MessageAuthenticationCode::create("HMAC(SHA-384)");
36 else if(alg_id == 4)
37 return MessageAuthenticationCode::create("HMAC(SHA-512)");
38 return nullptr;
39 }
40
41 }
42
43 std::string generate_passhash9(const std::string& pass,
44 RandomNumberGenerator& rng,
45 uint16_t work_factor,
46 uint8_t alg_id)
47 {
48 std::unique_ptr<MessageAuthenticationCode> prf = get_pbkdf_prf(alg_id);
49
50 if(!prf)
51 throw Invalid_Argument("Passhash9: Algorithm id " +
52 std::to_string(alg_id) +
53 " is not defined");
54
55 PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer
56
57 secure_vector<uint8_t> salt(SALT_BYTES);
58 rng.randomize(salt.data(), salt.size());
59
60 const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
61
62 secure_vector<uint8_t> blob;
63 blob.push_back(alg_id);
64 blob.push_back(get_byte(0, work_factor));
65 blob.push_back(get_byte(1, work_factor));
66 blob += salt;
67 blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
68 pass,
69 salt.data(), salt.size(),
70 kdf_iterations).bits_of();
71
72 return MAGIC_PREFIX + base64_encode(blob);
73 }
74
75 bool check_passhash9(const std::string& pass, const std::string& hash)
76 {
77 const size_t BINARY_LENGTH =
78 ALGID_BYTES +
79 WORKFACTOR_BYTES +
80 PASSHASH9_PBKDF_OUTPUT_LEN +
81 SALT_BYTES;
82
83 const size_t BASE64_LENGTH =
84 MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;
85
86 if(hash.size() != BASE64_LENGTH)
87 return false;
88
89 for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
90 if(hash[i] != MAGIC_PREFIX[i])
91 return false;
92
93 secure_vector<uint8_t> bin = base64_decode(hash.c_str() + MAGIC_PREFIX.size());
94
95 if(bin.size() != BINARY_LENGTH)
96 return false;
97
98 uint8_t alg_id = bin[0];
99
100 const size_t work_factor = load_be<uint16_t>(&bin[ALGID_BYTES], 0);
101
102 // Bug in the format, bad states shouldn't be representable, but are...
103 if(work_factor == 0)
104 return false;
105
106 if(work_factor > 512)
107 throw Invalid_Argument("Requested Bcrypt work factor " +
108 std::to_string(work_factor) + " too large");
109
110 const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
111
112 std::unique_ptr<MessageAuthenticationCode> pbkdf_prf = get_pbkdf_prf(alg_id);
113
114 if(!pbkdf_prf)
115 return false; // unknown algorithm, reject
116
117 PKCS5_PBKDF2 kdf(pbkdf_prf.release()); // takes ownership of pointer
118
119 secure_vector<uint8_t> cmp = kdf.derive_key(
120 PASSHASH9_PBKDF_OUTPUT_LEN,
121 pass,
122 &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
123 kdf_iterations).bits_of();
124
125 return same_mem(cmp.data(),
126 &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
127 PASSHASH9_PBKDF_OUTPUT_LEN);
128 }
129
130 }
Botan::OctetString::bits_of
secure_vector< uint8_t > bits_of() const
Definition: symkey.h:31
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::MessageAuthenticationCode::create
static std::unique_ptr< MessageAuthenticationCode > create(const std::string &algo_spec, const std::string &provider="")
Definition: mac.cpp:43
Botan::same_mem
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
Botan::PKCS5_PBKDF2
Definition: pbkdf2.h:28
Botan::RandomNumberGenerator
Definition: rng.h:25
Botan::RandomNumberGenerator::randomize
virtual void randomize(uint8_t output[], size_t length)=0
Botan::base64_decode
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
Botan::load_be< uint16_t >
uint16_t load_be< uint16_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:145
Botan::PBKDF::derive_key
OctetString derive_key(size_t out_len, const std::string &passphrase, const uint8_t salt[], size_t salt_len, size_t iterations) const
Definition: pbkdf.h:149
Botan::check_passhash9
bool check_passhash9(const std::string &pass, const std::string &hash)
Definition: passhash9.cpp:75
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
Botan
Definition: alg_id.cpp:13
Botan::base64_encode
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
Botan::get_byte
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
Botan::generate_passhash9
std::string generate_passhash9(const std::string &pass, RandomNumberGenerator &rng, uint16_t work_factor, uint8_t alg_id)
Definition: passhash9.cpp:43
hash
MechanismType hash
Definition: p11_mechanism.cpp:63