Crypto++
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 "hmac.h"
8 #include "hrtimer.h"
9 #include "integer.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  assert(derivedLen <= MaxDerivedKeyLength());
60  assert(iterations > 0 || timeInSeconds > 0);
61 
62  if (!iterations)
63  iterations = 1;
64 
65  T hash;
66  hash.Update(password, passwordLen);
67  hash.Update(salt, saltLen);
68 
69  SecByteBlock buffer(hash.DigestSize());
70  hash.Final(buffer);
71 
72  unsigned int i;
73  ThreadUserTimer timer;
74 
75  if (timeInSeconds)
76  timer.StartTimer();
77 
78  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
79  hash.CalculateDigest(buffer, buffer, buffer.size());
80 
81  memcpy(derived, buffer, derivedLen);
82  return i;
83 }
84 
85 template <class T>
86 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
87 {
88  assert(derivedLen <= MaxDerivedKeyLength());
89  assert(iterations > 0 || timeInSeconds > 0);
90 
91  if (!iterations)
92  iterations = 1;
93 
94  HMAC<T> hmac(password, passwordLen);
95  SecByteBlock buffer(hmac.DigestSize());
96  ThreadUserTimer timer;
97 
98  unsigned int i=1;
99  while (derivedLen > 0)
100  {
101  hmac.Update(salt, saltLen);
102  unsigned int j;
103  for (j=0; j<4; j++)
104  {
105  byte b = byte(i >> ((3-j)*8));
106  hmac.Update(&b, 1);
107  }
108  hmac.Final(buffer);
109 
110  size_t segmentLen = STDMIN(derivedLen, buffer.size());
111  memcpy(derived, buffer, segmentLen);
112 
113  if (timeInSeconds)
114  {
115  timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
116  timer.StartTimer();
117  }
118 
119  for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
120  {
121  hmac.CalculateDigest(buffer, buffer, buffer.size());
122  xorbuf(derived, buffer, segmentLen);
123  }
124 
125  if (timeInSeconds)
126  {
127  iterations = j;
128  timeInSeconds = 0;
129  }
130 
131  derived += segmentLen;
132  derivedLen -= segmentLen;
133  i++;
134  }
135 
136  return iterations;
137 }
138 
139 //! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class
140 template <class T>
142 {
143 public:
144  size_t MaxDerivedKeyLength() const {return size_t(0)-1;}
145  bool UsesPurposeByte() const {return true;}
146  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;
147 };
148 
149 template <class T>
150 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
151 {
152  assert(derivedLen <= MaxDerivedKeyLength());
153  assert(iterations > 0 || timeInSeconds > 0);
154 
155  if (!iterations)
156  iterations = 1;
157 
158  const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
159  const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
160  const size_t PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen;
161  SecByteBlock buffer(DLen + SLen + PLen);
162  byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
163 
164  memset(D, purpose, DLen);
165  size_t i;
166  for (i=0; i<SLen; i++)
167  S[i] = salt[i % saltLen];
168  for (i=0; i<PLen; i++)
169  P[i] = password[i % passwordLen];
170 
171 
172  T hash;
173  SecByteBlock Ai(T::DIGESTSIZE), B(v);
174  ThreadUserTimer timer;
175 
176  while (derivedLen > 0)
177  {
178  hash.CalculateDigest(Ai, buffer, buffer.size());
179 
180  if (timeInSeconds)
181  {
182  timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
183  timer.StartTimer();
184  }
185 
186  for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
187  hash.CalculateDigest(Ai, Ai, Ai.size());
188 
189  if (timeInSeconds)
190  {
191  iterations = (unsigned int)i;
192  timeInSeconds = 0;
193  }
194 
195  for (i=0; i<B.size(); i++)
196  B[i] = Ai[i % Ai.size()];
197 
198  Integer B1(B, B.size());
199  ++B1;
200  for (i=0; i<ILen; i+=v)
201  (Integer(I+i, v) + B1).Encode(I+i, v);
202 
203  size_t segmentLen = STDMIN(derivedLen, Ai.size());
204  memcpy(derived, Ai, segmentLen);
205  derived += segmentLen;
206  derivedLen -= segmentLen;
207  }
208 
209  return iterations;
210 }
211 
212 NAMESPACE_END
213 
214 #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:150
abstract base class for password based key derivation function
Definition: pwdbased.h:14
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
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:86
PBKDF from PKCS #12, appendix B, T should be a HashTransformation class.
Definition: pwdbased.h:141
unsigned int DigestSize() const
size of the hash/digest/MAC returned by Final()
Definition: hmac.h:22
multiple precision integer and basic arithmetics
Definition: integer.h:26
void Update(const byte *input, size_t length)
process more input
virtual void CalculateDigest(byte *digest, const byte *input, size_t length)
use this if your input is in one piece and you don't want to call Update() and Final() separately ...
Definition: cryptlib.h:568
HMAC
Definition: hmac.h:40
measure CPU time spent executing instructions of this thread (if supported by OS) ...
Definition: hrtimer.h:42
virtual void Final(byte *digest)
compute hash for current message, then restart for a new message
Definition: cryptlib.h:544