Botan 1.10.17
passhash9.cpp
Go to the documentation of this file.
1/*
2* Passhash9 Password Hashing
3* (C) 2010 Jack Lloyd
4*
5* Distributed under the terms of the Botan license
6*/
7
8#include <botan/passhash9.h>
9#include <botan/loadstor.h>
10#include <botan/libstate.h>
11#include <botan/pbkdf2.h>
12#include <botan/b64_filt.h>
13#include <botan/pipe.h>
14
15namespace Botan {
16
17namespace {
18
19const std::string MAGIC_PREFIX = "$9$";
20
21const size_t WORKFACTOR_BYTES = 2;
22const size_t ALGID_BYTES = 1;
23const size_t SALT_BYTES = 12; // 96 bits of salt
24const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output
25
26const size_t WORK_FACTOR_SCALE = 10000;
27
28MessageAuthenticationCode* get_pbkdf_prf(byte alg_id)
29 {
31
32 try
33 {
34 if(alg_id == 0)
35 return af.make_mac("HMAC(SHA-1)");
36 else if(alg_id == 1)
37 return af.make_mac("HMAC(SHA-256)");
38 else if(alg_id == 2)
39 return af.make_mac("CMAC(Blowfish)");
40 }
41 catch(Algorithm_Not_Found) {}
42
43 return 0;
44 }
45
46}
47
48std::string generate_passhash9(const std::string& pass,
50 u16bit work_factor,
51 byte alg_id)
52 {
53 MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id);
54
55 if(!prf)
56 throw Invalid_Argument("Passhash9: Algorithm id " + to_string(alg_id) +
57 " is not defined");
58
59 PKCS5_PBKDF2 kdf(prf); // takes ownership of pointer
60
61 SecureVector<byte> salt(SALT_BYTES);
62 rng.randomize(&salt[0], salt.size());
63
64 const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
65
66 SecureVector<byte> pbkdf2_output =
67 kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
68 pass,
69 &salt[0], salt.size(),
70 kdf_iterations).bits_of();
71
72 Pipe pipe(new Base64_Encoder);
73 pipe.start_msg();
74 pipe.write(alg_id);
75 pipe.write(get_byte(0, work_factor));
76 pipe.write(get_byte(1, work_factor));
77 pipe.write(salt);
78 pipe.write(pbkdf2_output);
79 pipe.end_msg();
80
81 return MAGIC_PREFIX + pipe.read_all_as_string();
82 }
83
84bool check_passhash9(const std::string& pass, const std::string& hash)
85 {
86 const size_t BINARY_LENGTH =
87 ALGID_BYTES +
88 WORKFACTOR_BYTES +
89 PASSHASH9_PBKDF_OUTPUT_LEN +
90 SALT_BYTES;
91
92 const size_t BASE64_LENGTH =
93 MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;
94
95 if(hash.size() != BASE64_LENGTH)
96 return false;
97
98 for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
99 if(hash[i] != MAGIC_PREFIX[i])
100 return false;
101
102 Pipe pipe(new Base64_Decoder);
103 pipe.start_msg();
104 pipe.write(hash.c_str() + MAGIC_PREFIX.size());
105 pipe.end_msg();
106
107 SecureVector<byte> bin = pipe.read_all();
108
109 if(bin.size() != BINARY_LENGTH)
110 return false;
111
112 byte alg_id = bin[0];
113
114 const size_t kdf_iterations =
115 WORK_FACTOR_SCALE * load_be<u16bit>(&bin[ALGID_BYTES], 0);
116
117 if(kdf_iterations == 0)
118 return false;
119
120 MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id);
121
122 if(pbkdf_prf == 0)
123 return false; // unknown algorithm, reject
124
125 PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer
126
128 PASSHASH9_PBKDF_OUTPUT_LEN,
129 pass,
130 &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
131 kdf_iterations).bits_of();
132
133 return same_mem(&cmp[0],
134 &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
135 PASSHASH9_PBKDF_OUTPUT_LEN);
136 }
137
138}
Algorithm_Factory & algorithm_factory() const
Definition libstate.cpp:173
size_t size() const
Definition secmem.h:29
SecureVector< byte > bits_of() const
Definition symkey.h:30
OctetString derive_key(size_t output_len, const std::string &passphrase, const byte salt[], size_t salt_len, size_t iterations) const
Definition pbkdf2.cpp:17
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition pipe_rw.cpp:105
void end_msg()
Definition pipe.cpp:166
void write(const byte in[], size_t length)
Definition pipe_rw.cpp:34
void start_msg()
Definition pipe.cpp:152
std::string read_all_as_string(message_id=DEFAULT_MESSAGE)
Definition pipe_rw.cpp:117
virtual void randomize(byte output[], size_t length)=0
byte get_byte(size_t byte_num, T input)
Definition get_byte.h:21
T load_be(const byte in[], size_t off)
Definition loadstor.h:100
std::string to_string(u64bit n, size_t min_len)
Definition parsing.cpp:42
std::invalid_argument Invalid_Argument
Definition exceptn.h:20
bool check_passhash9(const std::string &pass, const std::string &hash)
Definition passhash9.cpp:84
unsigned short u16bit
Definition types.h:27
Library_State & global_state()
std::string generate_passhash9(const std::string &pass, RandomNumberGenerator &rng, u16bit work_factor, byte alg_id)
Definition passhash9.cpp:48
bool same_mem(const T *p1, const T *p2, size_t n)
Definition mem_ops.h:57