Crypto++
|
00001 // pwdbased.h - written and placed in the public domain by Wei Dai 00002 00003 #ifndef CRYPTOPP_PWDBASED_H 00004 #define CRYPTOPP_PWDBASED_H 00005 00006 #include "cryptlib.h" 00007 #include "hmac.h" 00008 #include "hrtimer.h" 00009 #include "integer.h" 00010 00011 NAMESPACE_BEGIN(CryptoPP) 00012 00013 //! abstract base class for password based key derivation function 00014 class PasswordBasedKeyDerivationFunction 00015 { 00016 public: 00017 virtual size_t MaxDerivedKeyLength() const =0; 00018 virtual bool UsesPurposeByte() const =0; 00019 //! derive key from password 00020 /*! If timeInSeconds != 0, will iterate until time elapsed, as measured by ThreadUserTimer 00021 Returns actual iteration count, which is equal to iterations if timeInSeconds == 0, and not less than iterations otherwise. */ 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 //! PBKDF1 from PKCS #5, T should be a HashTransformation class 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 // PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation allows salts of any length. 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 //! PBKDF2 from PKCS #5, T should be a HashTransformation class 00037 template <class T> 00038 class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction 00039 { 00040 public: 00041 size_t MaxDerivedKeyLength() const {return 0xffffffffU;} // should multiply by T::DIGESTSIZE, but gets overflow that way 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 class PBKDF2Params 00048 { 00049 public: 00050 SecByteBlock m_salt; 00051 unsigned int m_interationCount; 00052 ASNOptional<ASNUnsignedWrapper<word32> > m_keyLength; 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 assert(derivedLen <= MaxDerivedKeyLength()); 00060 assert(iterations > 0 || timeInSeconds > 0); 00061 00062 if (!iterations) 00063 iterations = 1; 00064 00065 T hash; 00066 hash.Update(password, passwordLen); 00067 hash.Update(salt, saltLen); 00068 00069 SecByteBlock buffer(hash.DigestSize()); 00070 hash.Final(buffer); 00071 00072 unsigned int i; 00073 ThreadUserTimer timer; 00074 00075 if (timeInSeconds) 00076 timer.StartTimer(); 00077 00078 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++) 00079 hash.CalculateDigest(buffer, buffer, buffer.size()); 00080 00081 memcpy(derived, buffer, derivedLen); 00082 return i; 00083 } 00084 00085 template <class T> 00086 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 00087 { 00088 assert(derivedLen <= MaxDerivedKeyLength()); 00089 assert(iterations > 0 || timeInSeconds > 0); 00090 00091 if (!iterations) 00092 iterations = 1; 00093 00094 HMAC<T> hmac(password, passwordLen); 00095 SecByteBlock buffer(hmac.DigestSize()); 00096 ThreadUserTimer timer; 00097 00098 unsigned int i=1; 00099 while (derivedLen > 0) 00100 { 00101 hmac.Update(salt, saltLen); 00102 unsigned int j; 00103 for (j=0; j<4; j++) 00104 { 00105 byte b = byte(i >> ((3-j)*8)); 00106 hmac.Update(&b, 1); 00107 } 00108 hmac.Final(buffer); 00109 00110 size_t segmentLen = STDMIN(derivedLen, buffer.size()); 00111 memcpy(derived, buffer, segmentLen); 00112 00113 if (timeInSeconds) 00114 { 00115 timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size()); 00116 timer.StartTimer(); 00117 } 00118 00119 for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++) 00120 { 00121 hmac.CalculateDigest(buffer, buffer, buffer.size()); 00122 xorbuf(derived, buffer, segmentLen); 00123 } 00124 00125 if (timeInSeconds) 00126 { 00127 iterations = j; 00128 timeInSeconds = 0; 00129 } 00130 00131 derived += segmentLen; 00132 derivedLen -= segmentLen; 00133 i++; 00134 } 00135 00136 return iterations; 00137 } 00138 00139 //! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class 00140 template <class T> 00141 class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction 00142 { 00143 public: 00144 size_t MaxDerivedKeyLength() const {return size_t(0)-1;} 00145 bool UsesPurposeByte() const {return true;} 00146 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; 00147 }; 00148 00149 template <class T> 00150 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 00151 { 00152 assert(derivedLen <= MaxDerivedKeyLength()); 00153 assert(iterations > 0 || timeInSeconds > 0); 00154 00155 if (!iterations) 00156 iterations = 1; 00157 00158 const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12 00159 const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v); 00160 const size_t PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen; 00161 SecByteBlock buffer(DLen + SLen + PLen); 00162 byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S; 00163 00164 memset(D, purpose, DLen); 00165 size_t i; 00166 for (i=0; i<SLen; i++) 00167 S[i] = salt[i % saltLen]; 00168 for (i=0; i<PLen; i++) 00169 P[i] = password[i % passwordLen]; 00170 00171 00172 T hash; 00173 SecByteBlock Ai(T::DIGESTSIZE), B(v); 00174 ThreadUserTimer timer; 00175 00176 while (derivedLen > 0) 00177 { 00178 hash.CalculateDigest(Ai, buffer, buffer.size()); 00179 00180 if (timeInSeconds) 00181 { 00182 timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size()); 00183 timer.StartTimer(); 00184 } 00185 00186 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++) 00187 hash.CalculateDigest(Ai, Ai, Ai.size()); 00188 00189 if (timeInSeconds) 00190 { 00191 iterations = (unsigned int)i; 00192 timeInSeconds = 0; 00193 } 00194 00195 for (i=0; i<B.size(); i++) 00196 B[i] = Ai[i % Ai.size()]; 00197 00198 Integer B1(B, B.size()); 00199 ++B1; 00200 for (i=0; i<ILen; i+=v) 00201 (Integer(I+i, v) + B1).Encode(I+i, v); 00202 00203 size_t segmentLen = STDMIN(derivedLen, Ai.size()); 00204 memcpy(derived, Ai, segmentLen); 00205 derived += segmentLen; 00206 derivedLen -= segmentLen; 00207 } 00208 00209 return iterations; 00210 } 00211 00212 NAMESPACE_END 00213 00214 #endif