Crypto++  5.6.3
Free C++ class library of cryptographic schemes
pwdbased.h
1 // pwdbased.h - written and placed in the public domain by Wei Dai
2 
3 #ifndef CRYPTOPP_PWDBASED_H
4 #define CRYPTOPP_PWDBASED_H
5 
6 #include "cryptlib.h"
7 #include "hrtimer.h"
8 #include "integer.h"
9 #include "hmac.h"
10 
11 NAMESPACE_BEGIN(CryptoPP)
12 
13 //! abstract base class for password based key derivation function
15 {
16 public:
17  virtual size_t MaxDerivedKeyLength() const =0;
18  virtual bool UsesPurposeByte() const =0;
19  //! derive key from password
20  /*! If timeInSeconds != 0, will iterate until time elapsed, as measured by ThreadUserTimer
21  Returns actual iteration count, which is equal to iterations if timeInSeconds == 0, and not less than iterations otherwise. */
22  virtual unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const =0;
23 };
24 
25 //! PBKDF1 from PKCS #5, T should be a HashTransformation class
26 template <class T>
28 {
29 public:
30  size_t MaxDerivedKeyLength() const {return T::DIGESTSIZE;}
31  bool UsesPurposeByte() const {return false;}
32  // PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation allows salts of any length.
33  unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
34 };
35 
36 //! PBKDF2 from PKCS #5, T should be a HashTransformation class
37 template <class T>
39 {
40 public:
41  size_t MaxDerivedKeyLength() const {return 0xffffffffU;} // should multiply by T::DIGESTSIZE, but gets overflow that way
42  bool UsesPurposeByte() const {return false;}
43  unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
44 };
45 
46 /*
47 class PBKDF2Params
48 {
49 public:
50  SecByteBlock m_salt;
51  unsigned int m_interationCount;
52  ASNOptional<ASNUnsignedWrapper<word32> > m_keyLength;
53 };
54 */
55 
56 template <class T>
57 unsigned int PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
58 {
59  CRYPTOPP_UNUSED(purpose);
60  assert(derivedLen <= MaxDerivedKeyLength());
61  assert(iterations > 0 || timeInSeconds > 0);
62 
63  if (!iterations)
64  iterations = 1;
65 
66  T hash;
67  hash.Update(password, passwordLen);
68  hash.Update(salt, saltLen);
69 
70  SecByteBlock buffer(hash.DigestSize());
71  hash.Final(buffer);
72 
73  unsigned int i;
74  ThreadUserTimer timer;
75 
76  if (timeInSeconds)
77  timer.StartTimer();
78 
79  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
80  hash.CalculateDigest(buffer, buffer, buffer.size());
81 
82  memcpy(derived, buffer, derivedLen);
83  return i;
84 }
85 
86 template <class T>
87 unsigned int PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
88 {
89  CRYPTOPP_UNUSED(purpose);
90  assert(derivedLen <= MaxDerivedKeyLength());
91  assert(iterations > 0 || timeInSeconds > 0);
92 
93  if (!iterations)
94  iterations = 1;
95 
96  HMAC<T> hmac(password, passwordLen);
97  SecByteBlock buffer(hmac.DigestSize());
98  ThreadUserTimer timer;
99 
100  unsigned int i=1;
101  while (derivedLen > 0)
102  {
103  hmac.Update(salt, saltLen);
104  unsigned int j;
105  for (j=0; j<4; j++)
106  {
107  byte b = byte(i >> ((3-j)*8));
108  hmac.Update(&b, 1);
109  }
110  hmac.Final(buffer);
111 
112 #if CRYPTOPP_MSC_VERSION
113  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
114  memcpy_s(derived, segmentLen, buffer, segmentLen);
115 #else
116  const size_t segmentLen = STDMIN(derivedLen, buffer.size());
117  memcpy(derived, buffer, segmentLen);
118 #endif
119 
120  if (timeInSeconds)
121  {
122  timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
123  timer.StartTimer();
124  }
125 
126  for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
127  {
128  hmac.CalculateDigest(buffer, buffer, buffer.size());
129  xorbuf(derived, buffer, segmentLen);
130  }
131 
132  if (timeInSeconds)
133  {
134  iterations = j;
135  timeInSeconds = 0;
136  }
137 
138  derived += segmentLen;
139  derivedLen -= segmentLen;
140  i++;
141  }
142 
143  return iterations;
144 }
145 
146 //! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class
147 template <class T>
149 {
150 public:
151  size_t MaxDerivedKeyLength() const {return size_t(0)-1;}
152  bool UsesPurposeByte() const {return true;}
153  unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const;
154 };
155 
156 template <class T>
157 unsigned int PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
158 {
159  assert(derivedLen <= MaxDerivedKeyLength());
160  assert(iterations > 0 || timeInSeconds > 0);
161 
162  if (!iterations)
163  iterations = 1;
164 
165  const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
166  const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
167  const size_t PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen;
168  SecByteBlock buffer(DLen + SLen + PLen);
169  byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
170 
171  memset(D, purpose, DLen);
172  size_t i;
173  for (i=0; i<SLen; i++)
174  S[i] = salt[i % saltLen];
175  for (i=0; i<PLen; i++)
176  P[i] = password[i % passwordLen];
177 
178 
179  T hash;
180  SecByteBlock Ai(T::DIGESTSIZE), B(v);
181  ThreadUserTimer timer;
182 
183  while (derivedLen > 0)
184  {
185  hash.CalculateDigest(Ai, buffer, buffer.size());
186 
187  if (timeInSeconds)
188  {
189  timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
190  timer.StartTimer();
191  }
192 
193  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
194  hash.CalculateDigest(Ai, Ai, Ai.size());
195 
196  if (timeInSeconds)
197  {
198  iterations = (unsigned int)i;
199  timeInSeconds = 0;
200  }
201 
202  for (i=0; i<B.size(); i++)
203  B[i] = Ai[i % Ai.size()];
204 
205  Integer B1(B, B.size());
206  ++B1;
207  for (i=0; i<ILen; i+=v)
208  (Integer(I+i, v) + B1).Encode(I+i, v);
209 
210 #if CRYPTOPP_MSC_VERSION
211  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
212  memcpy_s(derived, segmentLen, Ai, segmentLen);
213 #else
214  const size_t segmentLen = STDMIN(derivedLen, Ai.size());
215  std::memcpy(derived, Ai, segmentLen);
216 #endif
217 
218  derived += segmentLen;
219  derivedLen -= segmentLen;
220  }
221 
222  return iterations;
223 }
224 
225 NAMESPACE_END
226 
227 #endif
unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const
derive key from password
Definition: pwdbased.h:57
unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
derive key from password
Definition: pwdbased.h:157
abstract base class for password based key derivation function
Definition: pwdbased.h:14
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:301
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:516
SecBlock typedef.
Definition: secblock.h:723
PBKDF2 from PKCS #5, T should be a HashTransformation class.
Definition: pwdbased.h:38
PBKDF1 from PKCS #5, T should be a HashTransformation class.
Definition: pwdbased.h:27
Classes for HMAC message authentication codes.
unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const
derive key from password
Definition: pwdbased.h:87
PBKDF from PKCS #12, appendix B, T should be a HashTransformation class.
Definition: pwdbased.h:148
unsigned int DigestSize() const
Provides the digest size of the hash.
Definition: hmac.h:28
Multiple precision integer with arithmetic operations.
Definition: integer.h:31
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: hmac.cpp:60
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:397
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:983
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:28
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:769
Crypto++ library namespace.
measure CPU time spent executing instructions of this thread (if supported by OS) ...
Definition: hrtimer.h:44
virtual void Final(byte *digest)
Computes the hash of the current message.
Definition: cryptlib.h:940