Crypto++  8.2
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  // DigestSize check due to https://github.com/weidai11/cryptopp/issues/855
249  HMAC<T> hmac(secret, secretLen);
250  if (hmac.DigestSize() == 0)
251  throw InvalidArgument("PKCS5_PBKDF2_HMAC: DigestSize cannot be 0");
252 
253  SecByteBlock buffer(hmac.DigestSize());
254  ThreadUserTimer timer;
255 
256  unsigned int i=1;
257  while (derivedLen > 0)
258  {
259  hmac.Update(salt, saltLen);
260  unsigned int j;
261  for (j=0; j<4; j++)
262  {
263  byte b = byte(i >> ((3-j)*8));
264  hmac.Update(&b, 1);
265  }
266  hmac.Final(buffer);
267 
268 #if CRYPTOPP_MSC_VERSION
269  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
270  memcpy_s(derived, segmentLen, buffer, segmentLen);
271 #else
272  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
273  memcpy(derived, buffer, segmentLen);
274 #endif
275 
276  if (timeInSeconds)
277  {
278  timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
279  timer.StartTimer();
280  }
281 
282  for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
283  {
284  hmac.CalculateDigest(buffer, buffer, buffer.size());
285  xorbuf(derived, buffer, segmentLen);
286  }
287 
288  if (timeInSeconds)
289  {
290  iterations = j;
291  timeInSeconds = 0;
292  }
293 
294  derived += segmentLen;
295  derivedLen -= segmentLen;
296  i++;
297  }
298 
299  return iterations;
300 }
301 
302 // ******************** PKCS12_PBKDF ********************
303 
304 /// \brief PBKDF from PKCS #12, appendix B
305 /// \tparam T a HashTransformation class
306 template <class T>
308 {
309 public:
310  virtual ~PKCS12_PBKDF() {}
311 
312  static std::string StaticAlgorithmName () {
313  const std::string name(std::string("PBKDF_PKCS12(") +
314  std::string(T::StaticAlgorithmName()) + std::string(")"));
315  return name;
316  }
317 
318  // KeyDerivationFunction interface
319  std::string AlgorithmName() const {
320  return StaticAlgorithmName();
321  }
322 
323  // TODO - check this
324  size_t MaxDerivedKeyLength() const {
325  return static_cast<size_t>(-1);
326  }
327 
328  // KeyDerivationFunction interface
329  size_t GetValidDerivedLength(size_t keylength) const;
330 
331  // KeyDerivationFunction interface
332  size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
333  const NameValuePairs& params = g_nullNameValuePairs) const;
334 
335  /// \brief Derive a key from a secret seed
336  /// \param derived the derived output buffer
337  /// \param derivedLen the size of the derived buffer, in bytes
338  /// \param purpose a purpose byte
339  /// \param secret the seed input buffer
340  /// \param secretLen the size of the secret buffer, in bytes
341  /// \param salt the salt input buffer
342  /// \param saltLen the size of the salt buffer, in bytes
343  /// \param iterations the number of iterations
344  /// \param timeInSeconds the in seconds
345  /// \returns the number of iterations performed
346  /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
347  /// \details DeriveKey() provides a standard interface to derive a key from
348  /// a seed and other parameters. Each class that derives from KeyDerivationFunction
349  /// provides an overload that accepts most parameters used by the derivation function.
350  /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
351  /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
352  /// will run for the specified number of iterations.
353  size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen,
354  const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const;
355 
356 protected:
357  // KeyDerivationFunction interface
358  const Algorithm & GetAlgorithm() const {
359  return *this;
360  }
361 };
362 
363 template <class T>
364 size_t PKCS12_PBKDF<T>::GetValidDerivedLength(size_t keylength) const
365 {
366  if (keylength > MaxDerivedLength())
367  return MaxDerivedLength();
368  return keylength;
369 }
370 
371 template <class T>
372 size_t PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen,
373  const byte *secret, size_t secretLen, const NameValuePairs& params) const
374 {
375  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
376  CRYPTOPP_ASSERT(derived && derivedLen);
377  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
378 
379  byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
380  unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
381 
382  double timeInSeconds = 0.0f;
383  (void)params.GetValue("TimeInSeconds", timeInSeconds);
384 
385  // NULL or 0 length salt OK
387  (void)params.GetValue(Name::Salt(), salt);
388 
389  return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
390 }
391 
392 template <class T>
393 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
394 {
395  CRYPTOPP_ASSERT(secret /*&& secretLen*/);
396  CRYPTOPP_ASSERT(derived && derivedLen);
397  CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
398  CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
399 
400  ThrowIfInvalidDerivedLength(derivedLen);
401 
402  // Business logic
403  if (!iterations) { iterations = 1; }
404 
405  const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
406  const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
407  const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen;
408  SecByteBlock buffer(DLen + SLen + PLen);
409  byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
410 
411  memset(D, purpose, DLen);
412  size_t i;
413  for (i=0; i<SLen; i++)
414  S[i] = salt[i % saltLen];
415  for (i=0; i<PLen; i++)
416  P[i] = secret[i % secretLen];
417 
418  T hash;
419  SecByteBlock Ai(T::DIGESTSIZE), B(v);
420  ThreadUserTimer timer;
421 
422  while (derivedLen > 0)
423  {
424  hash.CalculateDigest(Ai, buffer, buffer.size());
425 
426  if (timeInSeconds)
427  {
428  timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
429  timer.StartTimer();
430  }
431 
432  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
433  hash.CalculateDigest(Ai, Ai, Ai.size());
434 
435  if (timeInSeconds)
436  {
437  iterations = (unsigned int)i;
438  timeInSeconds = 0;
439  }
440 
441  for (i=0; i<B.size(); i++)
442  B[i] = Ai[i % Ai.size()];
443 
444  Integer B1(B, B.size());
445  ++B1;
446  for (i=0; i<ILen; i+=v)
447  (Integer(I+i, v) + B1).Encode(I+i, v);
448 
449 #if CRYPTOPP_MSC_VERSION
450  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
451  memcpy_s(derived, segmentLen, Ai, segmentLen);
452 #else
453  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
454  std::memcpy(derived, Ai, segmentLen);
455 #endif
456 
457  derived += segmentLen;
458  derivedLen -= segmentLen;
459  }
460 
461  return iterations;
462 }
463 
464 NAMESPACE_END
465 
466 #endif
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:20
Standard names for retrieving values by name when working with NameValuePairs.
An invalid argument was detected.
Definition: cryptlib.h:202
Classes for working with NameValuePairs.
CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Definition: cryptlib.h:395
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:478
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:307
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:372
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:319
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:602
#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
Interface for password based key derivation functions.
Definition: cryptlib.h:1533
CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:32
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:1121
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:364
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