Crypto++

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