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 Sat Dec 23 02:07:09 2006 for Crypto++ by  doxygen 1.5.1-p1