• 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

Generated on Mon Aug 9 2010 15:56:35 for Crypto++ by  doxygen 1.7.1