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