pbkdf2.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_PBKDF_PBKDF2_HPP
26 #define CRYPTO3_PBKDF_PBKDF2_HPP
27 
29 
30 #include <chrono>
31 
32 namespace nil {
33  namespace crypto3 {
34  namespace pbkdf {
40  template<typename MessageAuthenticationCode>
41  class pbkdf2 {
43 
44  public:
45  typedef typename policy_type::mac_type mac_type;
46 
47  constexpr static const std::size_t digest_bits = policy_type::digest_bits;
49 
50  constexpr static const std::size_t salt_bits = policy_type::salt_bits;
52 
53  size_t derive(digest_type &digest, const std::string &passphrase, const salt_type &salt,
54  size_t iterations, std::chrono::milliseconds msec) {
55  clear_mem(out, out_len);
56 
57  if (out_len == 0) {
58  return 0;
59  }
60 
61  try {
62  prf.set_key(cast_char_ptr_to_uint8(passphrase.data()), passphrase.size());
63  } catch (Invalid_Key_Length &) {
64  throw Exception("PBKDF2 with " + prf.name() + " cannot accept passphrases of length " +
65  std::to_string(passphrase.size()));
66  }
67 
68  const size_t prf_sz = prf.output_length();
69  secure_vector<uint8_t> U(prf_sz);
70 
71  const std::size_t blocks_needed = policy_type::round_up(out_len, prf_sz) / prf_sz;
72 
73  std::chrono::microseconds usec_per_block =
74  std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed;
75 
76  uint32_t counter = 1;
77  while (out_len) {
78  const size_t prf_output = std::min<size_t>(prf_sz, out_len);
79 
80  prf.update(salt, salt_len);
81  prf.update_be(counter++);
82  prf.final(U.data());
83 
84  xor_buf(out, U.data(), prf_output);
85 
86  if (iterations == 0) {
87  /*
88  If no iterations set, run the first block to calibrate based
89  on how long hashing takes on whatever machine we're running on.
90  */
91 
92  const auto start = std::chrono::high_resolution_clock::now();
93 
94  iterations = 1; // the first iteration we did above
95 
96  while (true) {
97  prf.update(U);
98  prf.final(U.data());
99  xor_buf(out, U.data(), prf_output);
100  iterations++;
101 
102  /*
103  Only break on relatively 'even' iterations. For one it
104  avoids confusion, and likely some broken implementations
105  break on getting completely randomly distributed values
106  */
107  if (iterations % 10000 == 0) {
108  auto time_taken = std::chrono::high_resolution_clock::now() - start;
109  auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken);
110  if (usec_taken > usec_per_block) {
111  break;
112  }
113  }
114  }
115  } else {
116  for (size_t i = 1; i != iterations; ++i) {
117  prf.update(U);
118  prf.final(U.data());
119  xor_buf(out, U.data(), prf_output);
120  }
121  }
122 
123  out_len -= prf_output;
124  out += prf_output;
125  }
126 
127  return iterations;
128  }
129  };
130  } // namespace pbkdf
131  } // namespace crypto3
132 } // namespace nil
133 
134 #endif
Definition: pbkdf2.hpp:41
policy_type::mac_type mac_type
Definition: pbkdf2.hpp:45
constexpr static const std::size_t digest_bits
Definition: pbkdf2.hpp:47
policy_type::digest_type digest_type
Definition: pbkdf2.hpp:48
size_t derive(digest_type &digest, const std::string &passphrase, const salt_type &salt, size_t iterations, std::chrono::milliseconds msec)
Definition: pbkdf2.hpp:53
policy_type::salt_type salt_type
Definition: pbkdf2.hpp:51
constexpr static const std::size_t salt_bits
Definition: pbkdf2.hpp:50
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: memory_operations.hpp:205
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: memory_operations.hpp:245
void clear_mem(T *ptr, size_t n)
Definition: memory_operations.hpp:175
Definition: pair.hpp:31
Definition: block/include/nil/crypto3/detail/digest.hpp:72
Definition: pbkdf2_functions.hpp:35
constexpr static const std::size_t salt_bits
Definition: pbkdf2_functions.hpp:43
constexpr static const std::size_t digest_bits
Definition: pbkdf2_functions.hpp:40
policy_type::mac_type mac_type
Definition: pbkdf2_functions.hpp:38
policy_type::digest_type digest_type
Definition: pbkdf2_functions.hpp:41
policy_type::salt_type salt_type
Definition: pbkdf2_functions.hpp:44
static std::size_t round_up(std::size_t n, std::size_t align_to)
Definition: pbkdf2_functions.hpp:52