Botan  2.18.1
Crypto and TLS for C++11
pbkdf2.cpp
Go to the documentation of this file.
1 /*
2 * PBKDF2
3 * (C) 1999-2007 Jack Lloyd
4 * (C) 2018 Ribose Inc
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/pbkdf2.h>
10 #include <botan/exceptn.h>
11 #include <botan/internal/rounding.h>
12 #include <botan/internal/timer.h>
13 
14 namespace Botan {
15 
16 namespace {
17 
18 void pbkdf2_set_key(MessageAuthenticationCode& prf,
19  const char* password,
20  size_t password_len)
21  {
22  try
23  {
24  prf.set_key(cast_char_ptr_to_uint8(password), password_len);
25  }
26  catch(Invalid_Key_Length&)
27  {
28  throw Invalid_Argument("PBKDF2 cannot accept passphrase of the given size");
29  }
30  }
31 
32 }
33 
34 size_t
36  uint8_t out[],
37  size_t out_len,
38  const std::string& password,
39  const uint8_t salt[], size_t salt_len,
40  size_t iterations,
41  std::chrono::milliseconds msec)
42  {
43  if(iterations == 0)
44  {
45  iterations = PBKDF2(prf, out_len, msec).iterations();
46  }
47 
48  PBKDF2 pbkdf2(prf, iterations);
49 
50  pbkdf2.derive_key(out, out_len,
51  password.c_str(), password.size(),
52  salt, salt_len);
53 
54  return iterations;
55  }
56 
57 namespace {
58 
59 size_t tune_pbkdf2(MessageAuthenticationCode& prf,
60  size_t output_length,
61  uint32_t msec)
62  {
63  if(output_length == 0)
64  output_length = 1;
65 
66  const size_t prf_sz = prf.output_length();
67  BOTAN_ASSERT_NOMSG(prf_sz > 0);
68  secure_vector<uint8_t> U(prf_sz);
69 
70  const size_t trial_iterations = 2000;
71 
72  // Short output ensures we only need a single PBKDF2 block
73 
74  Timer timer("PBKDF2");
75 
76  const auto tune_time = BOTAN_PBKDF_TUNING_TIME;
77 
78  prf.set_key(nullptr, 0);
79 
80  timer.run_until_elapsed(tune_time, [&]() {
81  uint8_t out[12] = { 0 };
82  uint8_t salt[12] = { 0 };
83  pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations);
84  });
85 
86  if(timer.events() == 0)
87  return trial_iterations;
88 
89  const uint64_t duration_nsec = timer.value() / timer.events();
90 
91  const uint64_t desired_nsec = static_cast<uint64_t>(msec) * 1000000;
92 
93  if(duration_nsec > desired_nsec)
94  return trial_iterations;
95 
96  const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz;
97 
98  const size_t multiplier = static_cast<size_t>(desired_nsec / duration_nsec / blocks_needed);
99 
100  if(multiplier == 0)
101  return trial_iterations;
102  else
103  return trial_iterations * multiplier;
104  }
105 
106 }
107 
109  uint8_t out[],
110  size_t out_len,
111  const uint8_t salt[],
112  size_t salt_len,
113  size_t iterations)
114  {
115  if(iterations == 0)
116  throw Invalid_Argument("PBKDF2: Invalid iteration count");
117 
118  clear_mem(out, out_len);
119 
120  if(out_len == 0)
121  return;
122 
123  const size_t prf_sz = prf.output_length();
124  BOTAN_ASSERT_NOMSG(prf_sz > 0);
125 
126  secure_vector<uint8_t> U(prf_sz);
127 
128  uint32_t counter = 1;
129  while(out_len)
130  {
131  const size_t prf_output = std::min<size_t>(prf_sz, out_len);
132 
133  prf.update(salt, salt_len);
134  prf.update_be(counter++);
135  prf.final(U.data());
136 
137  xor_buf(out, U.data(), prf_output);
138 
139  for(size_t i = 1; i != iterations; ++i)
140  {
141  prf.update(U);
142  prf.final(U.data());
143  xor_buf(out, U.data(), prf_output);
144  }
145 
146  out_len -= prf_output;
147  out += prf_output;
148  }
149  }
150 
151 // PBKDF interface
152 size_t
153 PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len,
154  const std::string& password,
155  const uint8_t salt[], size_t salt_len,
156  size_t iterations,
157  std::chrono::milliseconds msec) const
158  {
159  if(iterations == 0)
160  {
161  iterations = PBKDF2(*m_mac, key_len, msec).iterations();
162  }
163 
164  PBKDF2 pbkdf2(*m_mac, iterations);
165 
166  pbkdf2.derive_key(key, key_len,
167  password.c_str(), password.size(),
168  salt, salt_len);
169 
170  return iterations;
171  }
172 
173 std::string PKCS5_PBKDF2::name() const
174  {
175  return "PBKDF2(" + m_mac->name() + ")";
176  }
177 
179  {
180  return new PKCS5_PBKDF2(m_mac->clone());
181  }
182 
183 // PasswordHash interface
184 
185 PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) :
186  m_prf(prf.clone()),
187  m_iterations(tune_pbkdf2(*m_prf, olen, static_cast<uint32_t>(msec.count())))
188  {}
189 
190 std::string PBKDF2::to_string() const
191  {
192  return "PBKDF2(" + m_prf->name() + "," + std::to_string(m_iterations) + ")";
193  }
194 
195 void PBKDF2::derive_key(uint8_t out[], size_t out_len,
196  const char* password, const size_t password_len,
197  const uint8_t salt[], size_t salt_len) const
198  {
199  pbkdf2_set_key(*m_prf, password, password_len);
200  pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations);
201  }
202 
203 std::string PBKDF2_Family::name() const
204  {
205  return "PBKDF2(" + m_prf->name() + ")";
206  }
207 
208 std::unique_ptr<PasswordHash> PBKDF2_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const
209  {
210  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, output_len, msec));
211  }
212 
213 std::unique_ptr<PasswordHash> PBKDF2_Family::default_params() const
214  {
215  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, 150000));
216  }
217 
218 std::unique_ptr<PasswordHash> PBKDF2_Family::from_params(size_t iter, size_t, size_t) const
219  {
220  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
221  }
222 
223 std::unique_ptr<PasswordHash> PBKDF2_Family::from_iterations(size_t iter) const
224  {
225  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
226  }
227 
228 }
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:190
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
PBKDF2(const MessageAuthenticationCode &prf, size_t iter)
Definition: pbkdf2.h:42
std::string name() const override
Definition: pbkdf2.cpp:173
std::string name() const override
Definition: pbkdf2.cpp:203
PBKDF * clone() const override
Definition: pbkdf2.cpp:178
void final(uint8_t out[])
Definition: buf_comp.h:83
std::unique_ptr< PasswordHash > tune(size_t output_len, std::chrono::milliseconds msec, size_t max_memory) const override
Definition: pbkdf2.cpp:208
PKCS5_PBKDF2(MessageAuthenticationCode *mac_fn)
Definition: pbkdf2.h:110
std::string to_string() const override
Definition: pbkdf2.cpp:190
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:262
void update_be(uint16_t val)
Definition: buf_comp.cpp:12
size_t iterations() const override
Definition: pbkdf2.h:49
size_t salt_len
Definition: x509_obj.cpp:25
Definition: alg_id.cpp:13
size_t pbkdf(uint8_t output_buf[], size_t output_len, const std::string &passphrase, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) const override
Definition: pbkdf2.cpp:153
void derive_key(uint8_t out[], size_t out_len, const char *password, size_t password_len, const uint8_t salt[], size_t salt_len) const override
Definition: pbkdf2.cpp:195
void update(const uint8_t in[], size_t length)
Definition: buf_comp.h:33
std::unique_ptr< PasswordHash > default_params() const override
Definition: pbkdf2.cpp:213
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
std::unique_ptr< PasswordHash > from_params(size_t iter, size_t, size_t) const override
Definition: pbkdf2.cpp:218
size_t pbkdf2(MessageAuthenticationCode &prf, uint8_t out[], size_t out_len, const std::string &password, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec)
Definition: pbkdf2.cpp:35
std::unique_ptr< PasswordHash > from_iterations(size_t iter) const override
Definition: pbkdf2.cpp:223
virtual size_t output_length() const =0