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