Botan  1.10.9
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 
15 namespace Botan {
16 
17 namespace {
18 
19 const std::string MAGIC_PREFIX = "$9$";
20 
21 const size_t WORKFACTOR_BYTES = 2;
22 const size_t ALGID_BYTES = 1;
23 const size_t SALT_BYTES = 12; // 96 bits of salt
24 const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output
25 
26 const size_t WORK_FACTOR_SCALE = 10000;
27 
28 MessageAuthenticationCode* get_pbkdf_prf(byte alg_id)
29  {
30  Algorithm_Factory& af = global_state().algorithm_factory();
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 
48 std::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 
84 bool 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 
127  SecureVector<byte> cmp = kdf.derive_key(
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 }
void start_msg()
Definition: pipe.cpp:152
virtual void randomize(byte output[], size_t length)=0
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:57
std::string read_all_as_string(message_id=DEFAULT_MESSAGE)
Definition: pipe_rw.cpp:117
void write(const byte in[], size_t length)
Definition: pipe_rw.cpp:34
bool check_passhash9(const std::string &pass, const std::string &hash)
Definition: passhash9.cpp:84
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
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
byte get_byte(size_t byte_num, T input)
Definition: get_byte.h:21
MessageAuthenticationCode * make_mac(const std::string &algo_spec, const std::string &provider="")
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
unsigned char byte
Definition: types.h:22
SecureVector< byte > bits_of() const
Definition: symkey.h:30
void end_msg()
Definition: pipe.cpp:166
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition: pipe_rw.cpp:105
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
u16bit load_be< u16bit >(const byte in[], size_t off)
Definition: loadstor.h:132
Library_State & global_state()
unsigned short u16bit
Definition: types.h:27
std::string generate_passhash9(const std::string &pass, RandomNumberGenerator &rng, u16bit work_factor, byte alg_id)
Definition: passhash9.cpp:48
size_t size() const
Definition: secmem.h:29
std::string to_string(u64bit n, size_t min_len)
Definition: parsing.cpp:42