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