Mash was written by Wei prior to having a standard password to key implementation such as KDF. Hence why this is an improvement. One thing that could be done is that it could be converted to take pointers to the hash/cipher most likely instead of using template parameters, but I'm unsure where the cleanup for all these random "new" objects goes, so I wasn't comfortable with making that change. But yeah, I think it would be a good addition (given likely small adjustments) as, according to the comments in the default.h files, the Mash function is kind of obsolete in the presence of the KDF functions, and also the hash used by the existing functions is SHA1... _and_ only the first BLOCKSIZE bytes of the hash are actually written to the file for the keyCheck, increasing the likelihood that an incorrect password is assumed to be correct during decryption (as it is unlikely to find two different strings producing the same hash, but it's far more likely that you'll find two strings producing the same first half of the hash, for example).
But anyhow, even if not a _replacement_, an improved alternative could be derived from this. Jacob On Feb 11, 5:35 am, Jeffrey Walton <[email protected]> wrote: > Hi nacitar, > > Wei provides a DefaultEncryptorWithMac in default.h. I know the cipehr > and hash function are typedef for quick switching. > > As with your suggestion, the functions take a password. However, > Crypto++ uses a Mash() function where it appears your use a KDF (which > I like). > > Jeff > > On 2/10/09, nacitar <[email protected]> wrote: > > > > > Allows the user to specify what hash and what block cipher to use. > > Uses the max keylength by default, but can also specify that template > > parameter (assuming you specify a valid keylength for your algorithm > > of choice!). > > > I propose this is reviewed/committed. > > > Example usage: > > > typedef > > CryptoPP::PassphrasedDecryptor<CryptoPP::SHA512,CryptoPP::Serpent> > > Decryptor; > > typedef > > CryptoPP::PassphrasedEncryptor<CryptoPP::SHA512,CryptoPP::Serpent> > > Encryptor; > > std::string strIn, strOut; > > strIn = "Hello World!; > > CryptoPP::StringSource( strIn, true, > > new Encryptor("password", > > new Decryptor("password", > > new CryptoPP::StringSink( strOut ) > > ) > > ) > > ); > > std::cout << "Out: " << strOut << std::endl; > > > Code: > > > #ifndef PASSCRYPT_H_INCLUDED > > #define PASSCRYPT_H_INCLUDED > > #include <cryptopp/rsa.h> // required or pwdbased errors > > #include <cryptopp/pwdbased.h> > > #include <cryptopp/filters.h> > > #include <cryptopp/modes.h> > > #include <ctime> > > > NAMESPACE_BEGIN(CryptoPP) > > > // ******************************************************** > > > // Common base class, used to keep constant definitions in one place, > > and add two functions. > > template <class HashType,class CipherType> > > class PassphrasedCommon > > { > > protected: > > PassphrasedCommon() { } > > typedef typename CryptoPP::CBC_Mode<CipherType>::Encryption > > EncryptionCipher; > > typedef typename CryptoPP::CBC_Mode<CipherType>::Decryption > > DecryptionCipher; > > CRYPTOPP_CONSTANT(BLOCKSIZE = > > CipherType::Encryption::BLOCKSIZE); > > CRYPTOPP_CONSTANT(DIGESTSIZE = HashType::DIGESTSIZE) > > // Digest size aligned to a BLOCKSIZE boundary (so, >= > > DIGESTSIZE) > > CRYPTOPP_CONSTANT(ENC_DIGESTSIZE = (BLOCKSIZE*((DIGESTSIZE > > +BLOCKSIZE-1)/BLOCKSIZE)) ) > > // Amount of padding required to make DIGESTSIZE fill > > ENC_DIGESTSIZE > > CRYPTOPP_CONSTANT(DIGEST_PAD = (ENC_DIGESTSIZE-DIGESTSIZE)) > > // Amount of data to frontload for decryption > > CRYPTOPP_CONSTANT(HEADER_SIZE = (2*ENC_DIGESTSIZE) ); > > // Number of iterations to run through the key derivation > > function > > CRYPTOPP_CONSTANT(KEY_ITERATIONS = 2000 ); > > > // Put out the proper amount of badding > > size_t PutPad(BufferedTransformation*transformation) > > { > > size_t ret=0; > > if (transformation) > > for (size_t count=DIGEST_PAD;count;--count) > > ret += transformation->Put('\0'); > > return ret; > > } > > // Skip the proper amount of padding > > size_t SkipPad(BufferedTransformation*transformation) > > { > > if (!transformation) > > return 0; > > return transformation->Skip(DIGEST_PAD); > > } > > > }; > > > // ******************************************************** > > > // Encryption filter > > template <class HashType,class CipherType,const size_t > > KEY_SIZE=CipherType::MAX_KEYLENGTH> > > class PassphrasedEncryptor : public ProxyFilter, public > > PassphrasedCommon<HashType,CipherType> > > { > > private: > > // Pull in base values > > typedef PassphrasedCommon<HashType,CipherType> Base; > > CRYPTOPP_CONSTANT(BLOCKSIZE = Base::BLOCKSIZE); > > CRYPTOPP_CONSTANT(DIGESTSIZE = Base::DIGESTSIZE) > > CRYPTOPP_CONSTANT(ENC_DIGESTSIZE = Base::ENC_DIGESTSIZE ); > > CRYPTOPP_CONSTANT(KEY_ITERATIONS = Base::KEY_ITERATIONS ); > > typename Base::EncryptionCipher m_cipher; > > > SecByteBlock m_passphrase; > > > public: > > PassphrasedEncryptor(const char *passphrase, > > BufferedTransformation *attachment = NULL) > > : ProxyFilter(NULL,0,0,attachment), m_passphrase((const byte *) > > passphrase, strlen(passphrase)) > > { > > > } > > PassphrasedEncryptor(const byte *passphrase, size_t > > passphraseLength, BufferedTransformation *attachment = NULL) > > : ProxyFilter(NULL,0,0,attachment), m_passphrase(passphrase, > > passphraseLength) > > { > > > } > > > protected: > > void FirstPut(const byte *inString) > > { > > SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE); > > > HashType hash; > > > // use hash(passphrase | time | clock) as salt > > hash.Update(m_passphrase, m_passphrase.size()); > > std::time_t t=std::time(0); > > hash.Update((byte *)&t, sizeof(t)); > > std::clock_t c=std::clock(); > > hash.Update((byte *)&c, sizeof(c)); > > hash.Final(salt); > > > // use hash(passphrase | salt) as key check > > hash.Update(m_passphrase, m_passphrase.size()); > > hash.Update(salt, salt.size()); > > hash.Final(keyCheck); > > > // put the salt into the output stream, unencrypted > > AttachedTransformation()->Put(salt, salt.size()); > > // padd it to an even BLOCKSIZE boundary > > Base::PutPad(AttachedTransformation()); > > > // Buffer with room for the key and the initial value > > SecByteBlock keyIV(KEY_SIZE+BLOCKSIZE); > > // Derive the key > > PKCS5_PBKDF2_HMAC<HashType>().DeriveKey(keyIV,keyIV.size(), > > 0,m_passphrase,m_passphrase.size(),salt,salt.size(),KEY_ITERATIONS); > > > // Prepare the cipher for use given our key and initial > > value > > m_cipher.SetKeyWithIV(keyIV,KEY_SIZE,keyIV+KEY_SIZE); > > > // Set the cipher as the filter > > SetFilter(new StreamTransformationFilter(m_cipher)); > > // Output the keyCheck value before all others > > m_filter->Put(keyCheck, keyCheck.size()); > > // Pad it to an even BLOCKSIZE boundary > > Base::PutPad(m_filter.get()); > > } > > void LastPut(const byte *inString, size_t length) > > { > > m_filter->MessageEnd(); > > } > > }; > > > // ******************************************************** > > > // Decryption filter > > template <class HashType,class CipherType,const size_t > > KEY_SIZE=CipherType::MAX_KEYLENGTH> > > class PassphrasedDecryptor : public ProxyFilter, public > > PassphrasedCommon<HashType,CipherType> > > { > > private: > > typedef PassphrasedCommon<HashType,CipherType> Base; > > typename Base::DecryptionCipher m_cipher; > > CRYPTOPP_CONSTANT(BLOCKSIZE = Base::BLOCKSIZE); > > CRYPTOPP_CONSTANT(DIGESTSIZE = Base::DIGESTSIZE) > > CRYPTOPP_CONSTANT(ENC_DIGESTSIZE = Base::ENC_DIGESTSIZE ); > > CRYPTOPP_CONSTANT(HEADER_SIZE = Base::HEADER_SIZE ); > > CRYPTOPP_CONSTANT(KEY_ITERATIONS = Base::KEY_ITERATIONS ); > > > SecByteBlock m_passphrase; > > bool m_throwException; > > > public: > > class Err : public Exception > > { > > public: > > Err(const std::string &s) > > : Exception(DATA_INTEGRITY_CHECK_FAILED, s) {} > > }; > > class KeyBadErr : public Err {public: KeyBadErr() : Err > > ("PassphrasedDecryptor: cannot decrypt message with this passphrase") > > {}}; > > > enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD}; > > protected: > > State m_state; > > public: > > PassphrasedDecryptor(const char *passphrase, > > BufferedTransformation *attachment = NULL, bool throwException=true) > > : ProxyFilter(NULL, HEADER_SIZE, 0, attachment) > > , m_passphrase((const byte *)passphrase, strlen(passphrase)) > > , m_throwException(throwException) > > , m_state(WAITING_FOR_KEYCHECK) > > { > > > } > > > PassphrasedDecryptor(const byte *passphrase, size_t > > passphraseLength, BufferedTransformation *attachment = NULL, bool > > throwException=true) > > : ProxyFilter(NULL, HEADER_SIZE, 0, attachment) > > , m_passphrase(passphrase, passphraseLength) > > , m_throwException(throwException) > > , m_state(WAITING_FOR_KEYCHECK) > > { > > > } > > > State CurrentState() const {return m_state;} > > > protected: > > void FirstPut(const byte *inString) > > { > > CheckKey(inString, inString+ENC_DIGESTSIZE); > > } > > void LastPut(const byte *inString, size_t length) > > { > > if (m_filter.get() == NULL) > > { > > m_state = KEY_BAD; > > if (m_throwException) > > throw KeyBadErr(); > > } > > else > > { > > m_filter->MessageEnd(); > > m_state = WAITING_FOR_KEYCHECK; > > } > > > } > > > void CheckKey(const byte *salt, const byte *encCheck) > > { > > //(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int) > > DefaultHashModule::DIGESTSIZE)); > > SecByteBlock calcCheck(DIGESTSIZE); > > SecByteBlock readCheck(DIGESTSIZE); > > > // Calculate the expected keyCheck value using the salt > > from the input stream > > HashType hash; > > hash.Update(m_passphrase, m_passphrase.size()); > > hash.Update(salt, DIGESTSIZE); > > hash.Final(calcCheck); > > > // Prepare the cipher using the key derived from the input > > password and the salt > > SecByteBlock keyIV(KEY_SIZE+BLOCKSIZE); > > CryptoPP::PKCS5_PBKDF2_HMAC<HashType>().DeriveKey > > (keyIV,keyIV.size(),0,m_passphrase,m_passphrase.size > > (),salt,DIGESTSIZE,KEY_ITERATIONS); > > ... > > read more » --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the "Crypto++ Users" Google Group. To unsubscribe, send an email to [email protected]. More information about Crypto++ and this group is available at http://www.cryptopp.com. -~----------~----~----~----~------~----~------~--~---
