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