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); > m_cipher.SetKeyWithIV(keyIV,KEY_SIZE,keyIV+KEY_SIZE); > > // Make an instance of the decryption cipher > std::auto_ptr<StreamTransformationFilter> decryptor(new > StreamTransformationFilter(m_cipher)); > > // Put the keyCheck read in from the file into the > decryption cipher > decryptor->Put(encCheck, ENC_DIGESTSIZE); > // Force it to be processed now. > decryptor->ForceNextPut(); > // Read back the decrypted keyCheck value. > decryptor->Get(readCheck, readCheck.size()); > // Skip over the extra padding > Base::SkipPad(decryptor.get()); > // Set the decryption cipher as the filter for this > object. > SetFilter(decryptor.release()); > > // Compare the calculated keyCheck with the one decrypted > from the file > if (memcmp(calcCheck, readCheck, calcCheck.size())) > { > m_state = KEY_BAD; > if (m_throwException) > throw KeyBadErr(); > } > else > m_state = KEY_GOOD; > > } > > }; > > NAMESPACE_END > > #endif // PASSCRYPT_H_INCLUDED > > > > --~--~---------~--~----~------------~-------~--~----~ 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. -~----------~----~----~----~------~----~------~--~---
