Botan  2.8.0
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 Exception("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  const size_t prf_sz = prf.output_length();
64  BOTAN_ASSERT_NOMSG(prf_sz > 0);
65  secure_vector<uint8_t> U(prf_sz);
66 
67  const size_t trial_iterations = 10000;
68 
69  // Short output ensures we only need a single PBKDF2 block
70 
71  Timer timer("PBKDF2");
72 
73  const std::chrono::milliseconds tune_msec(30);
74 
75  prf.set_key(nullptr, 0);
76 
77  timer.run_until_elapsed(tune_msec, [&]() {
78  uint8_t out[16] = { 0 };
79  uint8_t salt[16] = { 0 };
80  pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations);
81  });
82 
83  if(timer.events() == 0)
84  return trial_iterations;
85 
86  const uint64_t duration_nsec = timer.value() / timer.events();
87 
88  const uint64_t desired_nsec = static_cast<uint64_t>(msec) * 1000000;
89 
90  if(duration_nsec > desired_nsec)
91  return trial_iterations;
92 
93  const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz;
94 
95  const size_t multiplier = (desired_nsec / duration_nsec / blocks_needed);
96 
97  if(multiplier == 0)
98  return trial_iterations;
99  else
100  return trial_iterations * multiplier;
101  }
102 
103 }
104 
106  uint8_t out[],
107  size_t out_len,
108  const uint8_t salt[],
109  size_t salt_len,
110  size_t iterations)
111  {
112  clear_mem(out, out_len);
113 
114  if(out_len == 0)
115  return;
116 
117  const size_t prf_sz = prf.output_length();
118  BOTAN_ASSERT_NOMSG(prf_sz > 0);
119 
120  secure_vector<uint8_t> U(prf_sz);
121 
122  uint32_t counter = 1;
123  while(out_len)
124  {
125  const size_t prf_output = std::min<size_t>(prf_sz, out_len);
126 
127  prf.update(salt, salt_len);
128  prf.update_be(counter++);
129  prf.final(U.data());
130 
131  xor_buf(out, U.data(), prf_output);
132 
133  for(size_t i = 1; i != iterations; ++i)
134  {
135  prf.update(U);
136  prf.final(U.data());
137  xor_buf(out, U.data(), prf_output);
138  }
139 
140  out_len -= prf_output;
141  out += prf_output;
142  }
143  }
144 
145 // PBKDF interface
146 size_t
147 PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len,
148  const std::string& password,
149  const uint8_t salt[], size_t salt_len,
150  size_t iterations,
151  std::chrono::milliseconds msec) const
152  {
153  if(iterations == 0)
154  {
155  iterations = PBKDF2(*m_mac, key_len, msec).iterations();
156  }
157 
158  PBKDF2 pbkdf2(*m_mac, iterations);
159 
160  pbkdf2.derive_key(key, key_len,
161  password.c_str(), password.size(),
162  salt, salt_len);
163 
164  return iterations;
165  }
166 
167 std::string PKCS5_PBKDF2::name() const
168  {
169  return "PBKDF2(" + m_mac->name() + ")";
170  }
171 
173  {
174  return new PKCS5_PBKDF2(m_mac->clone());
175  }
176 
177 // PasswordHash interface
178 
179 PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) :
180  m_prf(prf.clone()),
181  m_iterations(tune_pbkdf2(*m_prf, olen, static_cast<uint32_t>(msec.count())))
182  {}
183 
184 std::string PBKDF2::to_string() const
185  {
186  return "PBKDF2(" + m_prf->name() + "," + std::to_string(m_iterations) + ")";
187  }
188 
189 void PBKDF2::derive_key(uint8_t out[], size_t out_len,
190  const char* password, const size_t password_len,
191  const uint8_t salt[], size_t salt_len) const
192  {
193  pbkdf2_set_key(*m_prf, password, password_len);
194  pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations);
195  }
196 
197 std::string PBKDF2_Family::name() const
198  {
199  return "PBKDF2(" + m_prf->name() + ")";
200  }
201 
202 std::unique_ptr<PasswordHash> PBKDF2_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const
203  {
204  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, output_len, msec));
205  }
206 
207 std::unique_ptr<PasswordHash> PBKDF2_Family::default_params() const
208  {
209  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, 150000));
210  }
211 
212 std::unique_ptr<PasswordHash> PBKDF2_Family::from_params(size_t iter, size_t, size_t) const
213  {
214  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
215  }
216 
217 std::unique_ptr<PasswordHash> PBKDF2_Family::from_iterations(size_t iter) const
218  {
219  return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
220  }
221 
222 }
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:97
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:131
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:210
PBKDF2(const MessageAuthenticationCode &prf, size_t iter)
Definition: pbkdf2.h:40
std::string name() const override
Definition: pbkdf2.cpp:167
std::string name() const override
Definition: pbkdf2.cpp:197
PBKDF * clone() const override
Definition: pbkdf2.cpp:172
void final(uint8_t out[])
Definition: buf_comp.h:89
std::unique_ptr< PasswordHash > tune(size_t output_len, std::chrono::milliseconds msec, size_t max_memory) const override
Definition: pbkdf2.cpp:202
PKCS5_PBKDF2(MessageAuthenticationCode *mac_fn)
Definition: pbkdf2.h:108
std::string to_string() const override
Definition: pbkdf2.cpp:184
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:174
size_t iterations() const override
Definition: pbkdf2.h:47
size_t salt_len
Definition: x509_obj.cpp:26
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:147
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:189
void update(const uint8_t in[], size_t length)
Definition: buf_comp.h:34
std::unique_ptr< PasswordHash > default_params() const override
Definition: pbkdf2.cpp:207
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
std::unique_ptr< PasswordHash > from_params(size_t iter, size_t, size_t) const override
Definition: pbkdf2.cpp:212
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
void update_be(const T in)
Definition: buf_comp.h:58
std::unique_ptr< PasswordHash > from_iterations(size_t iter) const override
Definition: pbkdf2.cpp:217
virtual size_t output_length() const =0