Crypto++ 8.2
Free C&
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
24template <class T>
26{
27public:
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
75protected:
76 // KeyDerivationFunction interface
77 const Algorithm & GetAlgorithm() const {
78 return *this;
79 }
80};
81
82template <class T>
83size_t PKCS5_PBKDF1<T>::GetValidDerivedLength(size_t keylength) const
84{
85 if (keylength > MaxDerivedLength())
86 return MaxDerivedLength();
87 return keylength;
88}
89
90template <class T>
91size_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
110template <class T>
111size_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
148template <class T>
150{
151public:
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
199protected:
200 // KeyDerivationFunction interface
201 const Algorithm & GetAlgorithm() const {
202 return *this;
203 }
204};
205
206template <class T>
208{
209 if (keylength > MaxDerivedLength())
210 return MaxDerivedLength();
211 return keylength;
212}
213
214template <class T>
215size_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
234template <class T>
235size_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
302template <class T>
304{
305public:
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
352protected:
353 // KeyDerivationFunction interface
354 const Algorithm & GetAlgorithm() const {
355 return *this;
356 }
357};
358
359template <class T>
360size_t PKCS12_PBKDF<T>::GetValidDerivedLength(size_t keylength) const
361{
362 if (keylength > MaxDerivedLength())
363 return MaxDerivedLength();
364 return keylength;
365}
366
367template <class T>
368size_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
388template <class T>
389size_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
460NAMESPACE_END
461
462#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:571
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:21
const byte * begin() const
Pointer to the first byte in the memory block.
Definition: algparam.h:80
size_t size() const
Length of the memory block.
Definition: algparam.h:84
HMAC.
Definition: hmac.h:53
Multiple precision integer with arithmetic operations.
Definition: integer.h:50
Interface for retrieving values given their names.
Definition: cryptlib.h:294
bool GetValue(const char *name, T &value) const
Get a named value.
Definition: cryptlib.h:350
int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Definition: cryptlib.h:395
PBKDF from PKCS #12, appendix B.
Definition: pwdbased.h:304
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
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:315
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:360
PBKDF1 from PKCS #5.
Definition: pwdbased.h:26
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
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:37
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:83
PBKDF2 from PKCS #5.
Definition: pwdbased.h:150
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:161
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:207
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
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:797
SecBlock<byte> typedef.
Definition: secblock.h:1058
Measure CPU time spent executing instructions of this thread (if supported by OS)
Definition: hrtimer.h:47
Abstract base classes that provide a uniform interface to this library.
Classes for HMAC message authentication codes.
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:1085
void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
Bounds checking replacement for memcpy()
Definition: misc.h:443
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:567
Crypto++ library namespace.
const char * Salt()
ConstByteArrayParameter.
Definition: argnames.h:87
Interface for password based key derivation functions.
Definition: cryptlib.h:1534
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69