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

Reply via email to