I'm missing a close quote in the example code. :(
On Feb 10, 3:17 pm, 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.
-~----------~----~----~----~------~----~------~--~---