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.
-~----------~----~----~----~------~----~------~--~---

Reply via email to