Botan  2.6.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 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/pbkdf2.h>
9 #include <botan/internal/rounding.h>
10 
11 namespace Botan {
12 
13 size_t
15  uint8_t out[],
16  size_t out_len,
17  const std::string& passphrase,
18  const uint8_t salt[], size_t salt_len,
19  size_t iterations,
20  std::chrono::milliseconds msec)
21  {
22  clear_mem(out, out_len);
23 
24  if(out_len == 0)
25  return 0;
26 
27  try
28  {
29  prf.set_key(cast_char_ptr_to_uint8(passphrase.data()), passphrase.size());
30  }
31  catch(Invalid_Key_Length&)
32  {
33  throw Exception("PBKDF2 with " + prf.name() +
34  " cannot accept passphrases of length " +
35  std::to_string(passphrase.size()));
36  }
37 
38  const size_t prf_sz = prf.output_length();
39  secure_vector<uint8_t> U(prf_sz);
40 
41  const size_t blocks_needed = round_up(out_len, prf_sz) / prf_sz;
42 
43  std::chrono::microseconds usec_per_block =
44  std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed;
45 
46  uint32_t counter = 1;
47  while(out_len)
48  {
49  const size_t prf_output = std::min<size_t>(prf_sz, out_len);
50 
51  prf.update(salt, salt_len);
52  prf.update_be(counter++);
53  prf.final(U.data());
54 
55  xor_buf(out, U.data(), prf_output);
56 
57  if(iterations == 0)
58  {
59  /*
60  If no iterations set, run the first block to calibrate based
61  on how long hashing takes on whatever machine we're running on.
62  */
63 
64  const auto start = std::chrono::high_resolution_clock::now();
65 
66  iterations = 1; // the first iteration we did above
67 
68  while(true)
69  {
70  prf.update(U);
71  prf.final(U.data());
72  xor_buf(out, U.data(), prf_output);
73  iterations++;
74 
75  /*
76  Only break on relatively 'even' iterations. For one it
77  avoids confusion, and likely some broken implementations
78  break on getting completely randomly distributed values
79  */
80  if(iterations % 10000 == 0)
81  {
82  auto time_taken = std::chrono::high_resolution_clock::now() - start;
83  auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken);
84  if(usec_taken > usec_per_block)
85  break;
86  }
87  }
88  }
89  else
90  {
91  for(size_t i = 1; i != iterations; ++i)
92  {
93  prf.update(U);
94  prf.final(U.data());
95  xor_buf(out, U.data(), prf_output);
96  }
97  }
98 
99  out_len -= prf_output;
100  out += prf_output;
101  }
102 
103  return iterations;
104  }
105 
106 size_t
107 PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len,
108  const std::string& passphrase,
109  const uint8_t salt[], size_t salt_len,
110  size_t iterations,
111  std::chrono::milliseconds msec) const
112  {
113  return pbkdf2(*m_mac.get(), key, key_len, passphrase, salt, salt_len, iterations, msec);
114  }
115 
116 
117 }
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
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:145
void final(uint8_t out[])
Definition: buf_comp.h:89
size_t pbkdf2(MessageAuthenticationCode &prf, uint8_t out[], size_t out_len, const std::string &passphrase, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec)
Definition: pbkdf2.cpp:14
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:66
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:174
virtual std::string name() const =0
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:107
void update(const uint8_t in[], size_t length)
Definition: buf_comp.h:34
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
void update_be(const T in)
Definition: buf_comp.h:58
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:21
virtual size_t output_length() const =0