• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • 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 size_t 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, 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;
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     size_t 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, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t 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     size_t 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, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t 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, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t 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, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t 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 = byte(i >> ((3-j)*8));
00105             hmac.Update(&b, 1);
00106         }
00107         hmac.Final(buffer);
00108 
00109         size_t segmentLen = STDMIN(derivedLen, 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     size_t MaxDerivedKeyLength() const {return size_t(0)-1;}
00144     bool UsesPurposeByte() const {return true;}
00145     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;
00146 };
00147 
00148 template <class T>
00149 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
00150 {
00151     assert(derivedLen <= MaxDerivedKeyLength());
00152     assert(iterations > 0 || timeInSeconds > 0);
00153 
00154     if (!iterations)
00155         iterations = 1;
00156 
00157     const size_t v = T::BLOCKSIZE;  // v is in bytes rather than bits as in PKCS #12
00158     const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
00159     const size_t 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     size_t 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 = (unsigned int)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         size_t segmentLen = STDMIN(derivedLen, 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 Sun Jul 25 2010 14:44:11 for Crypto++ by  doxygen 1.7.1