Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

pwdbased.h

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

Generated on Wed Jul 21 19:15:31 2004 for Crypto++ by doxygen 1.3.7-20040704