00001
00002
00003 #ifndef CRYPTOPP_PWDBASED_H
00004 #define CRYPTOPP_PWDBASED_H
00005
00006 #include "cryptlib.h"
00007 #include "hrtimer.h"
00008 #include "integer.h"
00009 #include "hmac.h"
00010
00011 NAMESPACE_BEGIN(CryptoPP)
00012
00013
00014 class PasswordBasedKeyDerivationFunction
00015 {
00016 public:
00017 virtual size_t MaxDerivedKeyLength() const =0;
00018 virtual bool UsesPurposeByte() const =0;
00019
00020
00021
00022 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;
00023 };
00024
00025
00026 template <class T>
00027 class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction
00028 {
00029 public:
00030 size_t MaxDerivedKeyLength() const {return T::DIGESTSIZE;}
00031 bool UsesPurposeByte() const {return false;}
00032
00033 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;
00034 };
00035
00036
00037 template <class T>
00038 class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction
00039 {
00040 public:
00041 size_t MaxDerivedKeyLength() const {return 0xffffffffU;}
00042 bool UsesPurposeByte() const {return false;}
00043 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;
00044 };
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 template <class T>
00057 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
00058 {
00059 CRYPTOPP_UNUSED(purpose);
00060 assert(derivedLen <= MaxDerivedKeyLength());
00061 assert(iterations > 0 || timeInSeconds > 0);
00062
00063 if (!iterations)
00064 iterations = 1;
00065
00066 T hash;
00067 hash.Update(password, passwordLen);
00068 hash.Update(salt, saltLen);
00069
00070 SecByteBlock buffer(hash.DigestSize());
00071 hash.Final(buffer);
00072
00073 unsigned int i;
00074 ThreadUserTimer timer;
00075
00076 if (timeInSeconds)
00077 timer.StartTimer();
00078
00079 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
00080 hash.CalculateDigest(buffer, buffer, buffer.size());
00081
00082 memcpy(derived, buffer, derivedLen);
00083 return i;
00084 }
00085
00086 template <class T>
00087 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
00088 {
00089 CRYPTOPP_UNUSED(purpose);
00090 assert(derivedLen <= MaxDerivedKeyLength());
00091 assert(iterations > 0 || timeInSeconds > 0);
00092
00093 if (!iterations)
00094 iterations = 1;
00095
00096 HMAC<T> hmac(password, passwordLen);
00097 SecByteBlock buffer(hmac.DigestSize());
00098 ThreadUserTimer timer;
00099
00100 unsigned int i=1;
00101 while (derivedLen > 0)
00102 {
00103 hmac.Update(salt, saltLen);
00104 unsigned int j;
00105 for (j=0; j<4; j++)
00106 {
00107 byte b = byte(i >> ((3-j)*8));
00108 hmac.Update(&b, 1);
00109 }
00110 hmac.Final(buffer);
00111
00112 #if CRYPTOPP_MSC_VERSION
00113 const size_t segmentLen = STDMIN(derivedLen, buffer.size());
00114 memcpy_s(derived, segmentLen, buffer, segmentLen);
00115 #else
00116 const size_t segmentLen = STDMIN(derivedLen, buffer.size());
00117 memcpy(derived, buffer, segmentLen);
00118 #endif
00119
00120 if (timeInSeconds)
00121 {
00122 timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
00123 timer.StartTimer();
00124 }
00125
00126 for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
00127 {
00128 hmac.CalculateDigest(buffer, buffer, buffer.size());
00129 xorbuf(derived, buffer, segmentLen);
00130 }
00131
00132 if (timeInSeconds)
00133 {
00134 iterations = j;
00135 timeInSeconds = 0;
00136 }
00137
00138 derived += segmentLen;
00139 derivedLen -= segmentLen;
00140 i++;
00141 }
00142
00143 return iterations;
00144 }
00145
00146
00147 template <class T>
00148 class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction
00149 {
00150 public:
00151 size_t MaxDerivedKeyLength() const {return size_t(0)-1;}
00152 bool UsesPurposeByte() const {return true;}
00153 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;
00154 };
00155
00156 template <class T>
00157 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
00158 {
00159 assert(derivedLen <= MaxDerivedKeyLength());
00160 assert(iterations > 0 || timeInSeconds > 0);
00161
00162 if (!iterations)
00163 iterations = 1;
00164
00165 const size_t v = T::BLOCKSIZE;
00166 const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
00167 const size_t PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen;
00168 SecByteBlock buffer(DLen + SLen + PLen);
00169 byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
00170
00171 memset(D, purpose, DLen);
00172 size_t i;
00173 for (i=0; i<SLen; i++)
00174 S[i] = salt[i % saltLen];
00175 for (i=0; i<PLen; i++)
00176 P[i] = password[i % passwordLen];
00177
00178
00179 T hash;
00180 SecByteBlock Ai(T::DIGESTSIZE), B(v);
00181 ThreadUserTimer timer;
00182
00183 while (derivedLen > 0)
00184 {
00185 hash.CalculateDigest(Ai, buffer, buffer.size());
00186
00187 if (timeInSeconds)
00188 {
00189 timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
00190 timer.StartTimer();
00191 }
00192
00193 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
00194 hash.CalculateDigest(Ai, Ai, Ai.size());
00195
00196 if (timeInSeconds)
00197 {
00198 iterations = (unsigned int)i;
00199 timeInSeconds = 0;
00200 }
00201
00202 for (i=0; i<B.size(); i++)
00203 B[i] = Ai[i % Ai.size()];
00204
00205 Integer B1(B, B.size());
00206 ++B1;
00207 for (i=0; i<ILen; i+=v)
00208 (Integer(I+i, v) + B1).Encode(I+i, v);
00209
00210 #if CRYPTOPP_MSC_VERSION
00211 const size_t segmentLen = STDMIN(derivedLen, Ai.size());
00212 memcpy_s(derived, segmentLen, Ai, segmentLen);
00213 #else
00214 const size_t segmentLen = STDMIN(derivedLen, Ai.size());
00215 std::memcpy(derived, Ai, segmentLen);
00216 #endif
00217
00218 derived += segmentLen;
00219 derivedLen -= segmentLen;
00220 }
00221
00222 return iterations;
00223 }
00224
00225 NAMESPACE_END
00226
00227 #endif