Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | 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 
00009 NAMESPACE_BEGIN(CryptoPP)
00010 
00011 class PasswordBasedKeyDerivationFunction
00012 {
00013 public:
00014         virtual unsigned int MaxDerivedKeyLength() const =0;
00015         virtual void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte purpose, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const =0;
00016 };
00017 
00018 //! PBKDF1 from PKCS #5, T should be a HashTransformation class
00019 template <class T>
00020 class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction
00021 {
00022 public:
00023         unsigned int MaxDerivedKeyLength() const {return T::DIGESTSIZE;}
00024         // PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation allows salts of any length.
00025         void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte ignored, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00026                 {DeriveKey(derived, derivedLen, password, passwordLen, salt, saltLen, iterations);}
00027         void DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen=8, unsigned int iterations=1000) const;
00028 };
00029 
00030 //! PBKDF2 from PKCS #5, T should be a HashTransformation class
00031 template <class T>
00032 class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction
00033 {
00034 public:
00035         unsigned int MaxDerivedKeyLength() const {return 0xffffffffU;}  // should multiply by T::DIGESTSIZE, but gets overflow that way
00036         void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte ignored, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00037                 {DeriveKey(derived, derivedLen, password, passwordLen, salt, saltLen, iterations);}
00038         void DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations=1000) const;
00039 };
00040 
00041 /*
00042 class PBKDF2Params
00043 {
00044 public:
00045         SecByteBlock m_salt;
00046         unsigned int m_interationCount;
00047         ASNOptional<ASNUnsignedWrapper<word32> > m_keyLength;
00048 };
00049 */
00050 
00051 template <class T>
00052 void PKCS5_PBKDF1<T>::DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00053 {
00054         assert(derivedLen <= MaxDerivedLength());
00055         assert(iterations > 0);
00056 
00057         T hash;
00058         hash.Update(password, passwordLen);
00059         hash.Update(salt, saltLen);
00060 
00061         SecByteBlock buffer(hash.DigestSize());
00062         hash.Final(buffer);
00063 
00064         for (unsigned int i=1; i<iterations; i++)
00065                 hash.CalculateDigest(buffer, buffer, buffer.size());
00066 
00067         memcpy(derived, buffer, derivedLen);
00068 }
00069 
00070 template <class T>
00071 void PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, unsigned int derivedLen, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00072 {
00073         assert(derivedLen <= MaxDerivedKeyLength());
00074         assert(iterations > 0);
00075 
00076         HMAC<T> hmac(password, passwordLen);
00077         SecByteBlock buffer(hmac.DigestSize());
00078 
00079         unsigned int i=1;
00080         while (derivedLen > 0)
00081         {
00082                 hmac.Update(salt, saltLen);
00083                 unsigned int j;
00084                 for (j=0; j<4; j++)
00085                 {
00086                         byte b = i >> ((3-j)*8);
00087                         hmac.Update(&b, 1);
00088                 }
00089                 hmac.Final(buffer);
00090 
00091                 unsigned int segmentLen = STDMIN(derivedLen, (unsigned int)buffer.size());
00092                 memcpy(derived, buffer, segmentLen);
00093 
00094                 for (j=1; j<iterations; j++)
00095                 {
00096                         hmac.CalculateDigest(buffer, buffer, buffer.size());
00097                         xorbuf(derived, buffer, segmentLen);
00098                 }
00099 
00100                 derived += segmentLen;
00101                 derivedLen -= segmentLen;
00102                 i++;
00103         }
00104 }
00105 
00106 //! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class
00107 template <class T>
00108 class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction
00109 {
00110 public:
00111         unsigned int MaxDerivedKeyLength() const {return UINT_MAX;}
00112         void GeneralDeriveKey(byte *derived, unsigned int derivedLen, byte purpose, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00113                 {DeriveKey(derived, derivedLen, purpose, password, passwordLen, salt, saltLen, iterations);}
00114         void DeriveKey(byte *derived, unsigned int derivedLen, byte ID, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations=1000) const;
00115 };
00116 
00117 template <class T>
00118 void PKCS12_PBKDF<T>::DeriveKey(byte *derived, unsigned int derivedLen, byte ID, const byte *password, unsigned int passwordLen, const byte *salt, unsigned int saltLen, unsigned int iterations) const
00119 {
00120         assert(derivedLen <= MaxDerivedKeyLength());
00121         assert(iterations > 0);
00122 
00123         const unsigned int v = T::BLOCKSIZE;    // v is in bytes rather than bits as in PKCS #12
00124         const unsigned int DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
00125         const unsigned int PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen;
00126         SecByteBlock buffer(DLen + SLen + PLen);
00127         byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
00128 
00129         memset(D, ID, DLen);
00130         unsigned int i;
00131         for (i=0; i<SLen; i++)
00132                 S[i] = salt[i % saltLen];
00133         for (i=0; i<PLen; i++)
00134                 P[i] = password[i % passwordLen];
00135 
00136 
00137         T hash;
00138         SecByteBlock Ai(T::DIGESTSIZE), B(v);
00139 
00140         while (derivedLen > 0)
00141         {
00142                 hash.CalculateDigest(Ai, buffer, buffer.size());
00143                 for (i=1; i<iterations; i++)
00144                         hash.CalculateDigest(Ai, Ai, Ai.size());
00145                 for (i=0; i<B.size(); i++)
00146                         B[i] = Ai[i % Ai.size()];
00147 
00148                 Integer B1(B, B.size());
00149                 ++B1;
00150                 for (i=0; i<ILen; i+=v)
00151                         (Integer(I+i, v) + B1).Encode(I+i, v);
00152 
00153                 unsigned int segmentLen = STDMIN(derivedLen, (unsigned int)Ai.size());
00154                 memcpy(derived, Ai, segmentLen);
00155                 derived += segmentLen;
00156                 derivedLen -= segmentLen;
00157         }
00158 }
00159 
00160 NAMESPACE_END
00161 
00162 #endif

Generated on Sun Mar 14 20:44:28 2004 for Crypto++ by doxygen 1.3.6-20040222