Crypto++
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 #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