• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13262741994

11 Feb 2025 12:19PM UTC coverage: 91.656% (-0.003%) from 91.659%
13262741994

Pull #4647

github

web-flow
Merge 0b8e56724 into f372b5a9e
Pull Request #4647: Avoid using mem_ops.h or assert.h in public headers

94864 of 103500 relevant lines covered (91.66%)

11330304.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.23
/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
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

11
#include <botan/exceptn.h>
12
#include <botan/mem_ops.h>
13
#include <botan/internal/fmt.h>
14
#include <botan/internal/time_utils.h>
15

16
namespace Botan {
17

18
namespace {
19

20
void pbkdf2_set_key(MessageAuthenticationCode& prf, const char* password, size_t password_len) {
729✔
21
   try {
729✔
22
      prf.set_key(cast_char_ptr_to_uint8(password), password_len);
729✔
23
   } catch(Invalid_Key_Length&) {
×
24
      throw Invalid_Argument("PBKDF2 cannot accept passphrase of the given size");
×
25
   }
×
26
}
729✔
27

28
size_t tune_pbkdf2(MessageAuthenticationCode& prf,
282✔
29
                   size_t output_length,
30
                   std::chrono::milliseconds msec,
31
                   std::chrono::milliseconds tune_time = std::chrono::milliseconds(10)) {
32
   if(output_length == 0) {
282✔
33
      output_length = 1;
34
   }
35

36
   const size_t prf_sz = prf.output_length();
282✔
37
   BOTAN_ASSERT_NOMSG(prf_sz > 0);
282✔
38
   secure_vector<uint8_t> U(prf_sz);
282✔
39

40
   const size_t trial_iterations = 2000;
282✔
41

42
   // Short output ensures we only need a single PBKDF2 block
43

44
   prf.set_key(nullptr, 0);
282✔
45

46
   const uint64_t duration_nsec = measure_cost(tune_time, [&]() {
282✔
47
      uint8_t out[12] = {0};
701✔
48
      uint8_t salt[12] = {0};
701✔
49
      pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations);
701✔
50
   });
701✔
51

52
   const uint64_t desired_nsec = static_cast<uint64_t>(msec.count()) * 1000000;
282✔
53

54
   if(duration_nsec > desired_nsec) {
282✔
55
      return trial_iterations;
56
   }
57

58
   const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz;
38✔
59

60
   const size_t multiplier = static_cast<size_t>(desired_nsec / duration_nsec / blocks_needed);
38✔
61

62
   if(multiplier == 0) {
38✔
63
      return trial_iterations;
64
   } else {
65
      return trial_iterations * multiplier;
38✔
66
   }
67
}
282✔
68

69
}  // namespace
70

71
size_t pbkdf2(MessageAuthenticationCode& prf,
×
72
              uint8_t out[],
73
              size_t out_len,
74
              std::string_view password,
75
              const uint8_t salt[],
76
              size_t salt_len,
77
              size_t iterations,
78
              std::chrono::milliseconds msec) {
79
   if(iterations == 0) {
×
80
      iterations = tune_pbkdf2(prf, out_len, msec);
×
81
   }
82

83
   PBKDF2 pbkdf2(prf, iterations);
×
84

85
   pbkdf2.derive_key(out, out_len, password.data(), password.size(), salt, salt_len);
×
86

87
   return iterations;
×
88
}
×
89

90
void pbkdf2(MessageAuthenticationCode& prf,
2,934✔
91
            uint8_t out[],
92
            size_t out_len,
93
            const uint8_t salt[],
94
            size_t salt_len,
95
            size_t iterations) {
96
   if(iterations == 0) {
2,934✔
97
      throw Invalid_Argument("PBKDF2: Invalid iteration count");
×
98
   }
99

100
   clear_mem(out, out_len);
2,934✔
101

102
   if(out_len == 0) {
2,934✔
103
      return;
×
104
   }
105

106
   const size_t prf_sz = prf.output_length();
2,934✔
107
   BOTAN_ASSERT_NOMSG(prf_sz > 0);
2,934✔
108

109
   secure_vector<uint8_t> U(prf_sz);
2,934✔
110

111
   uint32_t counter = 1;
2,934✔
112
   while(out_len) {
93,037✔
113
      const size_t prf_output = std::min<size_t>(prf_sz, out_len);
90,103✔
114

115
      prf.update(salt, salt_len);
90,103✔
116
      prf.update_be(counter++);
90,103✔
117
      prf.final(U.data());
90,103✔
118

119
      xor_buf(out, U.data(), prf_output);
90,103✔
120

121
      for(size_t i = 1; i != iterations; ++i) {
11,518,600✔
122
         prf.update(U);
11,428,497✔
123
         prf.final(U.data());
11,428,497✔
124
         xor_buf(out, U.data(), prf_output);
11,428,497✔
125
      }
126

127
      out_len -= prf_output;
90,103✔
128
      out += prf_output;
90,103✔
129
   }
130
}
2,934✔
131

132
// PBKDF interface
133
size_t PKCS5_PBKDF2::pbkdf(uint8_t key[],
66✔
134
                           size_t key_len,
135
                           std::string_view password,
136
                           const uint8_t salt[],
137
                           size_t salt_len,
138
                           size_t iterations,
139
                           std::chrono::milliseconds msec) const {
140
   if(iterations == 0) {
66✔
141
      iterations = tune_pbkdf2(*m_mac, key_len, msec);
×
142
   }
143

144
   PBKDF2 pbkdf2(*m_mac, iterations);
66✔
145

146
   pbkdf2.derive_key(key, key_len, password.data(), password.size(), salt, salt_len);
66✔
147

148
   return iterations;
66✔
149
}
66✔
150

151
std::string PKCS5_PBKDF2::name() const {
15✔
152
   return fmt("PBKDF2({})", m_mac->name());
15✔
153
}
154

155
std::unique_ptr<PBKDF> PKCS5_PBKDF2::new_object() const {
×
156
   return std::make_unique<PKCS5_PBKDF2>(m_mac->new_object());
×
157
}
158

159
// PasswordHash interface
160

161
PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) :
×
162
      m_prf(prf.new_object()), m_iterations(tune_pbkdf2(*m_prf, olen, msec)) {}
×
163

164
std::string PBKDF2::to_string() const {
4✔
165
   return fmt("PBKDF2({},{})", m_prf->name(), m_iterations);
4✔
166
}
167

168
void PBKDF2::derive_key(uint8_t out[],
729✔
169
                        size_t out_len,
170
                        const char* password,
171
                        const size_t password_len,
172
                        const uint8_t salt[],
173
                        size_t salt_len) const {
174
   pbkdf2_set_key(*m_prf, password, password_len);
729✔
175
   pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations);
729✔
176
}
729✔
177

178
std::string PBKDF2_Family::name() const {
2✔
179
   return fmt("PBKDF2({})", m_prf->name());
2✔
180
}
181

182
std::unique_ptr<PasswordHash> PBKDF2_Family::tune(size_t output_len,
282✔
183
                                                  std::chrono::milliseconds msec,
184
                                                  size_t /*max_memory_usage_mb*/,
185
                                                  std::chrono::milliseconds tune_time) const {
186
   auto iterations = tune_pbkdf2(*m_prf, output_len, msec, tune_time);
282✔
187
   return std::make_unique<PBKDF2>(*m_prf, iterations);
282✔
188
}
189

190
std::unique_ptr<PasswordHash> PBKDF2_Family::default_params() const {
2✔
191
   return std::make_unique<PBKDF2>(*m_prf, 150000);
2✔
192
}
193

194
std::unique_ptr<PasswordHash> PBKDF2_Family::from_params(size_t iter, size_t /*i2*/, size_t /*i3*/) const {
335✔
195
   return std::make_unique<PBKDF2>(*m_prf, iter);
335✔
196
}
197

198
std::unique_ptr<PasswordHash> PBKDF2_Family::from_iterations(size_t iter) const {
44✔
199
   return std::make_unique<PBKDF2>(*m_prf, iter);
44✔
200
}
201

202
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc