Crypto++  7.0
Free C++ class library of cryptographic schemes
pwdbased.h
Go to the documentation of this file.
1 // pwdbased.h - originally written and placed in the public domain by Wei Dai
2 // Cutover to KeyDerivationFunction interface by Uri Blumenthal
3 // Marcel Raad and Jeffrey Walton in March 2018.
4 
5 /// \file pwdbased.h
6 /// \brief Password based key derivation functions
7 
8 #ifndef CRYPTOPP_PWDBASED_H
9 #define CRYPTOPP_PWDBASED_H
10 
11 #include "cryptlib.h"
12 #include "hrtimer.h"
13 #include "integer.h"
14 #include "argnames.h"
15 #include "hmac.h"
16 
17 NAMESPACE_BEGIN(CryptoPP)
18 
19 // ******************** PBKDF1 ********************
20 
21 /// \brief PBKDF1 from PKCS #5
22 /// \tparam T a HashTransformation class
23 template <class T>
25 {
26 public:
27  virtual ~PKCS5_PBKDF1() {}
28 
29  static std::string StaticAlgorithmName () {
30  const std::string name(std::string("PBKDF1(") +
31  std::string(T::StaticAlgorithmName()) + std::string(")"));
32  return name;
33  }
34 
35  // KeyDerivationFunction interface
36  std::string AlgorithmName() const {
37  return StaticAlgorithmName();
38  }
39 
40  // KeyDerivationFunction interface
41  size_t MaxDerivedKeyLength() const {
42  return static_cast<size_t>(T::DIGESTSIZE);
43  }
44 
45  // KeyDerivationFunction interface
46  size_t GetValidDerivedLength(size_t keylength) const;
47 
48  // KeyDerivationFunction interface
49  virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
50  const NameValuePairs& params = g_nullNameValuePairs) const;
51 
52  /// \brief Derive a key from a secret seed
53  /// \param derived the derived output buffer
54  /// \param derivedLen the size of the derived buffer, in bytes
55  /// \param purpose a purpose byte
56  /// \param secret the seed input buffer
57  /// \param secretLen the size of the secret buffer, in bytes
58  /// \param salt the salt input buffer
59  /// \param saltLen the size of the salt buffer, in bytes
60  /// \param iterations the number of iterations
61  /// \param timeInSeconds the in seconds
62  /// \returns the number of iterations performed
63  /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
64  /// \details DeriveKey() provides a standard interface to derive a key from
65  /// a seed and other parameters. Each class that derives from KeyDerivationFunction
66  /// provides an overload that accepts most parameters used by the derivation function.
67  /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
68  /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
69  /// will run for the specified number of iterations.
70  /// \details PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation
71  /// allows salts of any length.
72  size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
73 
74 protected:
75  // KeyDerivationFunction interface
76  const Algorithm & GetAlgorithm() const {
77  return *this;
78  }
79 };
80 
81 template <class T>
82 size_t PKCS5_PBKDF1<T>::GetValidDerivedLength(size_t keylength) const
83 {
84  if (keylength > MaxDerivedLength())
85  return MaxDerivedLength();
86  return keylength;
87 }
88 
89 template <class T>
90 size_t PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen,
91  const byte *secret, size_t secretLen, const NameValuePairs& params) const
92 {
93  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
94  CRYPTOPP_ASSERT(derived && derivedLen);
95  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
96 
97  byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
98  unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
99 
100  double timeInSeconds = 0.0f;
101  (void)params.GetValue("TimeInSeconds", timeInSeconds);
102 
104  (void)params.GetValue(Name::Salt(), salt);
105 
106  return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
107 }
108 
109 template <class T>
110 size_t PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
111 {
112  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
113  CRYPTOPP_ASSERT(derived && derivedLen);
114  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
115  CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
116  CRYPTOPP_UNUSED(purpose);
117 
118  ThrowIfInvalidDerivedLength(derivedLen);
119 
120  // Business logic
121  if (!iterations) { iterations = 1; }
122 
123  T hash;
124  hash.Update(secret, secretLen);
125  hash.Update(salt, saltLen);
126 
127  SecByteBlock buffer(hash.DigestSize());
128  hash.Final(buffer);
129 
130  unsigned int i;
131  ThreadUserTimer timer;
132 
133  if (timeInSeconds)
134  timer.StartTimer();
135 
136  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
137  hash.CalculateDigest(buffer, buffer, buffer.size());
138 
139  memcpy(derived, buffer, derivedLen);
140  return i;
141 }
142 
143 // ******************** PKCS5_PBKDF2_HMAC ********************
144 
145 /// \brief PBKDF2 from PKCS #5
146 /// \tparam T a HashTransformation class
147 template <class T>
149 {
150 public:
151  virtual ~PKCS5_PBKDF2_HMAC() {}
152 
153  static std::string StaticAlgorithmName () {
154  const std::string name(std::string("PBKDF2_HMAC(") +
155  std::string(T::StaticAlgorithmName()) + std::string(")"));
156  return name;
157  }
158 
159  // KeyDerivationFunction interface
160  std::string AlgorithmName() const {
161  return StaticAlgorithmName();
162  }
163 
164  // KeyDerivationFunction interface
165  // should multiply by T::DIGESTSIZE, but gets overflow that way
166  size_t MaxDerivedKeyLength() const {
167  return 0xffffffffU;
168  }
169 
170  // KeyDerivationFunction interface
171  size_t GetValidDerivedLength(size_t keylength) const;
172 
173  // KeyDerivationFunction interface
174  size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
175  const NameValuePairs& params = g_nullNameValuePairs) const;
176 
177  /// \brief Derive a key from a secret seed
178  /// \param derived the derived output buffer
179  /// \param derivedLen the size of the derived buffer, in bytes
180  /// \param purpose a purpose byte
181  /// \param secret the seed input buffer
182  /// \param secretLen the size of the secret buffer, in bytes
183  /// \param salt the salt input buffer
184  /// \param saltLen the size of the salt buffer, in bytes
185  /// \param iterations the number of iterations
186  /// \param timeInSeconds the in seconds
187  /// \returns the number of iterations performed
188  /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
189  /// \details DeriveKey() provides a standard interface to derive a key from
190  /// a seed and other parameters. Each class that derives from KeyDerivationFunction
191  /// provides an overload that accepts most parameters used by the derivation function.
192  /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
193  /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
194  /// will run for the specified number of iterations.
195  size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen,
196  const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
197 
198 protected:
199  // KeyDerivationFunction interface
200  const Algorithm & GetAlgorithm() const {
201  return *this;
202  }
203 };
204 
205 template <class T>
206 size_t PKCS5_PBKDF2_HMAC<T>::GetValidDerivedLength(size_t keylength) const
207 {
208  if (keylength > MaxDerivedLength())
209  return MaxDerivedLength();
210  return keylength;
211 }
212 
213 template <class T>
214 size_t PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen,
215  const byte *secret, size_t secretLen, const NameValuePairs& params) const
216 {
217  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
218  CRYPTOPP_ASSERT(derived && derivedLen);
219  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
220 
221  byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
222  unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
223 
224  double timeInSeconds = 0.0f;
225  (void)params.GetValue("TimeInSeconds", timeInSeconds);
226 
228  (void)params.GetValue(Name::Salt(), salt);
229 
230  return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
231 }
232 
233 template <class T>
234 size_t PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
235 {
236  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
237  CRYPTOPP_ASSERT(derived && derivedLen);
238  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
239  CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
240  CRYPTOPP_UNUSED(purpose);
241 
242  ThrowIfInvalidDerivedLength(derivedLen);
243 
244  // Business logic
245  if (!iterations) { iterations = 1; }
246 
247  HMAC<T> hmac(secret, secretLen);
248  SecByteBlock buffer(hmac.DigestSize());
249  ThreadUserTimer timer;
250 
251  unsigned int i=1;
252  while (derivedLen > 0)
253  {
254  hmac.Update(salt, saltLen);
255  unsigned int j;
256  for (j=0; j<4; j++)
257  {
258  byte b = byte(i >> ((3-j)*8));
259  hmac.Update(&b, 1);
260  }
261  hmac.Final(buffer);
262 
263 #if CRYPTOPP_MSC_VERSION
264  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
265  memcpy_s(derived, segmentLen, buffer, segmentLen);
266 #else
267  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
268  memcpy(derived, buffer, segmentLen);
269 #endif
270 
271  if (timeInSeconds)
272  {
273  timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
274  timer.StartTimer();
275  }
276 
277  for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
278  {
279  hmac.CalculateDigest(buffer, buffer, buffer.size());
280  xorbuf(derived, buffer, segmentLen);
281  }
282 
283  if (timeInSeconds)
284  {
285  iterations = j;
286  timeInSeconds = 0;
287  }
288 
289  derived += segmentLen;
290  derivedLen -= segmentLen;
291  i++;
292  }
293 
294  return iterations;
295 }
296 
297 // ******************** PKCS12_PBKDF ********************
298 
299 /// \brief PBKDF from PKCS #12, appendix B
300 /// \tparam T a HashTransformation class
301 template <class T>
303 {
304 public:
305  virtual ~PKCS12_PBKDF() {}
306 
307  static std::string StaticAlgorithmName () {
308  const std::string name(std::string("PBKDF_PKCS12(") +
309  std::string(T::StaticAlgorithmName()) + std::string(")"));
310  return name;
311  }
312 
313  // KeyDerivationFunction interface
314  std::string AlgorithmName() const {
315  return StaticAlgorithmName();
316  }
317 
318  // TODO - check this
319  size_t MaxDerivedKeyLength() const {
320  return static_cast<size_t>(-1);
321  }
322 
323  // KeyDerivationFunction interface
324  size_t GetValidDerivedLength(size_t keylength) const;
325 
326  // KeyDerivationFunction interface
327  size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
328  const NameValuePairs& params = g_nullNameValuePairs) const;
329 
330  /// \brief Derive a key from a secret seed
331  /// \param derived the derived output buffer
332  /// \param derivedLen the size of the derived buffer, in bytes
333  /// \param purpose a purpose byte
334  /// \param secret the seed input buffer
335  /// \param secretLen the size of the secret buffer, in bytes
336  /// \param salt the salt input buffer
337  /// \param saltLen the size of the salt buffer, in bytes
338  /// \param iterations the number of iterations
339  /// \param timeInSeconds the in seconds
340  /// \returns the number of iterations performed
341  /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
342  /// \details DeriveKey() provides a standard interface to derive a key from
343  /// a seed and other parameters. Each class that derives from KeyDerivationFunction
344  /// provides an overload that accepts most parameters used by the derivation function.
345  /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
346  /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
347  /// will run for the specified number of iterations.
348  size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen,
349  const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const;
350 
351 protected:
352  // KeyDerivationFunction interface
353  const Algorithm & GetAlgorithm() const {
354  return *this;
355  }
356 };
357 
358 template <class T>
359 size_t PKCS12_PBKDF<T>::GetValidDerivedLength(size_t keylength) const
360 {
361  if (keylength > MaxDerivedLength())
362  return MaxDerivedLength();
363  return keylength;
364 }
365 
366 template <class T>
367 size_t PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen,
368  const byte *secret, size_t secretLen, const NameValuePairs& params) const
369 {
370  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
371  CRYPTOPP_ASSERT(derived && derivedLen);
372  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
373 
374  byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
375  unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
376 
377  double timeInSeconds = 0.0f;
378  (void)params.GetValue("TimeInSeconds", timeInSeconds);
379 
380  // NULL or 0 length salt OK
382  (void)params.GetValue(Name::Salt(), salt);
383 
384  return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
385 }
386 
387 template <class T>
388 size_t PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
389 {
390  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
391  CRYPTOPP_ASSERT(derived && derivedLen);
392  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
393  CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
394 
395  ThrowIfInvalidDerivedLength(derivedLen);
396 
397  // Business logic
398  if (!iterations) { iterations = 1; }
399 
400  const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
401  const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
402  const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen;
403  SecByteBlock buffer(DLen + SLen + PLen);
404  byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
405 
406  memset(D, purpose, DLen);
407  size_t i;
408  for (i=0; i<SLen; i++)
409  S[i] = salt[i % saltLen];
410  for (i=0; i<PLen; i++)
411  P[i] = secret[i % secretLen];
412 
413  T hash;
414  SecByteBlock Ai(T::DIGESTSIZE), B(v);
415  ThreadUserTimer timer;
416 
417  while (derivedLen > 0)
418  {
419  hash.CalculateDigest(Ai, buffer, buffer.size());
420 
421  if (timeInSeconds)
422  {
423  timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
424  timer.StartTimer();
425  }
426 
427  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
428  hash.CalculateDigest(Ai, Ai, Ai.size());
429 
430  if (timeInSeconds)
431  {
432  iterations = (unsigned int)i;
433  timeInSeconds = 0;
434  }
435 
436  for (i=0; i<B.size(); i++)
437  B[i] = Ai[i % Ai.size()];
438 
439  Integer B1(B, B.size());
440  ++B1;
441  for (i=0; i<ILen; i+=v)
442  (Integer(I+i, v) + B1).Encode(I+i, v);
443 
444 #if CRYPTOPP_MSC_VERSION
445  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
446  memcpy_s(derived, segmentLen, Ai, segmentLen);
447 #else
448  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
449  std::memcpy(derived, Ai, segmentLen);
450 #endif
451 
452  derived += segmentLen;
453  derivedLen -= segmentLen;
454  }
455 
456  return iterations;
457 }
458 
459 NAMESPACE_END
460 
461 #endif
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:20
int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Definition: cryptlib.h:392
Standard names for retrieving values by name when working with NameValuePairs.
size_t size() const
Length of the memory block.
Definition: algparam.h:84
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:160
unsigned int DigestSize() const
Provides the digest size of the hash.
Definition: hmac.h:28
Abstract base classes that provide a uniform interface to this library.
void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
Bounds checking replacement for memcpy()
Definition: misc.h:383
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:206
SecBlock<byte> typedef.
Definition: secblock.h:822
PBKDF2 from PKCS #5.
Definition: pwdbased.h:148
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:82
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:214
PBKDF1 from PKCS #5.
Definition: pwdbased.h:24
Classes for HMAC message authentication codes.
PBKDF from PKCS #12, appendix B.
Definition: pwdbased.h:302
const byte * begin() const
Pointer to the first byte in the memory block.
Definition: algparam.h:80
const char * Salt()
ConstByteArrayParameter.
Definition: argnames.h:87
Multiple precision integer with arithmetic operations.
Definition: integer.h:49
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: hmac.cpp:60
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:367
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:314
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:507
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
Interface for all crypto algorithms.
Definition: cryptlib.h:573
virtual void CalculateDigest(byte *digest, const byte *input, size_t length)
Updates the hash with additional input and computes the hash of the current message.
Definition: cryptlib.h:1139
const NameValuePairs g_nullNameValuePairs
An empty set of name-value pairs.
Definition: cryptlib.h:494
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:36
HMAC.
Definition: hmac.h:50
void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:32
Interface for password based key derivation functions.
Definition: cryptlib.h:1480
Multiple precision integer with arithmetic operations.
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:971
Crypto++ library namespace.
bool GetValue(const char *name, T &value) const
Get a named value.
Definition: cryptlib.h:347
Measure CPU time spent executing instructions of this thread (if supported by OS)
Definition: hrtimer.h:46
virtual void Final(byte *digest)
Computes the hash of the current message.
Definition: cryptlib.h:1095
virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:90
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:359
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:561
Interface for retrieving values given their names.
Definition: cryptlib.h:290