diff --git a/cryptlib.cpp b/cryptlib.cpp index 19ea1c6a..8920d356 100644 --- a/cryptlib.cpp +++ b/cryptlib.cpp @@ -71,7 +71,7 @@ Algorithm::Algorithm(bool checkSelfTestStatus) void SimpleKeyingInterface::SetKey(const byte *key, size_t length, const NameValuePairs ¶ms) { this->ThrowIfInvalidKeyLength(length); - this->UncheckedSetKey(key, (unsigned int)length, params); + this->UncheckedSetKey(key, static_cast(length), params); } void SimpleKeyingInterface::SetKeyWithRounds(const byte *key, size_t length, int rounds) @@ -127,7 +127,7 @@ const byte * SimpleKeyingInterface::GetIVAndThrowIfInvalid(const NameValuePairs { iv = ivWithLength.begin(); ThrowIfInvalidIV(iv); - size = ThrowIfInvalidIVLength((int)ivWithLength.size()); + size = ThrowIfInvalidIVLength(static_cast(ivWithLength.size())); return iv; } else if (params.GetValue(Name::IV(), iv)) diff --git a/modes.cpp b/modes.cpp index 6b8e81ae..0d9849ce 100644 --- a/modes.cpp +++ b/modes.cpp @@ -67,7 +67,7 @@ void CFB_ModePolicy::TransformRegister() void CFB_ModePolicy::CipherResynchronize(const byte *iv, size_t length) { CRYPTOPP_ASSERT(length == BlockSize()); - CopyOrZero(m_register, iv, length); + CopyOrZero(m_register, m_register.size(), iv, length); TransformRegister(); } @@ -99,7 +99,7 @@ void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(length == BlockSize()); - CopyOrZero(m_register, iv, length); + CopyOrZero(m_register, m_register.size(), iv, length); } void CTR_ModePolicy::SeekToIteration(lword iterationCount) @@ -144,7 +144,7 @@ void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(length == BlockSize()); - CopyOrZero(m_register, iv, length); + CopyOrZero(m_register, m_register.size(), iv, length); m_counterArray = m_register; } diff --git a/modes.h b/modes.h index 78f2cd97..0955c3bd 100644 --- a/modes.h +++ b/modes.h @@ -130,12 +130,15 @@ protected: unsigned int m_feedbackSize; }; -inline void CopyOrZero(void *dest, const void *src, size_t s) +inline void CopyOrZero(void *dest, size_t d, const void *src, size_t s) { + CRYPTOPP_ASSERT(dest); + CRYPTOPP_ASSERT(d >= s); + if (src) - memcpy_s(dest, s, src, s); + memcpy_s(dest, d, src, s); else - memset(dest, 0, s); + memset(dest, 0, d); } //! \class OFB_ModePolicy diff --git a/seckey.h b/seckey.h index 0cba30e3..c8bbfc90 100644 --- a/seckey.h +++ b/seckey.h @@ -111,10 +111,121 @@ protected: { int rounds = param.GetIntValueWithDefault("Rounds", DEFAULT_ROUNDS); ThrowIfInvalidRounds(rounds, alg); - return (unsigned int)rounds; + return static_cast(rounds); } }; +//! \class VariableBlockSize +//! \brief Inherited by algorithms with variable blocksize +//! \tparam D Default blocksize +//! \tparam N Minimum blocksize +//! \tparam M Maximum blocksize +template // use INT_MAX here because enums are treated as signed ints +class VariableBlockSize +{ +public: + //! \brief The default blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(BLOCKSIZE = D) + //! \brief The default blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(DEFAULT_BLOCKSIZE = D) + //! \brief The minimum blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MIN_BLOCKSIZE = N) + //! \brief The maximum blocksize for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MAX_BLOCKSIZE = M) + //! \brief The default blocksize for the algorithm based on key length + //! provided by a static function. + //! \param keylength the size of the key, in bytes + //! \details keylength is unused in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR unsigned int StaticGetDefaultBlockSize(size_t keylength) + { + return (keylength >= 64) ? 64 : + (keylength >= 32) ? 32 : 16; + } + +protected: + //! \brief Validates the blocksize for an algorithm. + //! \param blocksize the candidate blocksize + //! \param alg an Algorithm object used if the blocksize is invalid + //! \throws InvalidBlockSize if the blocksize is invalid + //! \details ThrowIfInvalidBlockSize() validates the blocksize and throws if invalid. + inline void ThrowIfInvalidBlockSize(int blocksize, const Algorithm *alg) + { + if (M == INT_MAX) // Coverity and result_independent_of_operands + { + if (blocksize < MIN_BLOCKSIZE) + throw InvalidBlockSize(alg ? alg->AlgorithmName() : std::string("VariableBlockSize"), blocksize); + } + else + { + if (blocksize < MIN_BLOCKSIZE || blocksize > MAX_BLOCKSIZE) + throw InvalidBlockSize(alg ? alg->AlgorithmName() : std::string("VariableBlockSize"), blocksize); + } + } + + //! \brief Validates the blocksize for an algorithm + //! \param param the candidate blocksize + //! \param alg an Algorithm object used if the blocksize is invalid + //! \returns the blocksize for the algorithm + //! \throws InvalidBlockSize if the blocksize is invalid + //! \details GetBlockSizeAndThrowIfInvalid() validates the blocksize and throws if invalid. + inline unsigned int GetBlockSizeAndThrowIfInvalid(const NameValuePairs ¶m, const Algorithm *alg) + { + int keylength = param.GetIntValueWithDefault("KeySize", 0); + int blocksize = param.GetIntValueWithDefault("BlockSize", DEFAULT_BLOCKSIZE); + if (keylength > 0) + ThrowIfInvalidBlockSize(keylength, blocksize, alg); + else + ThrowIfInvalidBlockSize(blocksize, alg); + return static_cast(blocksize); + } + + //! Provides the block size of the cipher + //! \return the block size, in bytes + //! \details The sematics of BlockSize() is return DEFAULT_BLOCKSIZE if the default blocksize + //! is in effect. If the blocksize has changed, then the value returned is the BlockSize() + //! parameter used during SetKey(). + //! \details DEFAULT_BLOCKSIZE should be paired with DEFAULT_KEYLENGTH, and it is the same as + //! BLOCKSIZE in a FixedBlockSize cipher. + virtual unsigned int BlockSize() const =0; + + //! Provides the minimum block size of the cipher + //! \return the minimum block size, in bytes + //! \details MinBlockSize() returns the smallest blocksize a cipher can use. The size can + //! be affected by the key length. For example, Threefish has key sizes of 256, 512 and 1024 bits, + //! and the blocksize follows the key length. If a 512-bit key is used, then the block size is 512 + //! bits. Once keyed, the minimum block size of 256 is not accurate, nor is a block size of 1024 bit. + virtual unsigned int MinBlockSize() const + { return MIN_BLOCKSIZE; } + + //! Provides the maximum block size of the cipher + //! \return the maximum block size, in bytes + //! \details MaxBlockSize() returns the largest blocksize a cipher can use. The size can + //! be affected by the key length. For example, Threefish has key sizes of 256, 512 and 1024 bits, + //! and the blocksize follows the key length. If a 512-bit key is used, then the block size is 512 + //! bits. Once keyed, the minimum block size of 256 is not accurate, nor is a block size of 1024 bit. + virtual unsigned int MaxBlockSize() const + { return MAX_BLOCKSIZE; } + + //! Provides the initialization vector length of the cipher + //! \return the initialization vector length, in bytes + //! \details The sematics of IVSize() is return IV_LENGTH if the default blocksize is + //! in effect. If the blocksize has changed, then the default implentation returns the value of + //! the BlockSize() parameter used during SetKey(). + //! \details Derived classes may override the behavior such that a different value is returned. + //! This may happen with a cipher that requires an IV that is twice the block size. + virtual unsigned int IVSize() const =0; + + //! \brief Provides the minimum size of an IV + //! \return minimal length of IVs accepted by this cipher, in bytes + virtual unsigned int MinIVLength() const + { return MIN_BLOCKSIZE; } + + //! \brief Provides the maximum size of an IV + //! \return maximal length of IVs accepted by this cipher, in bytes + virtual unsigned int MaxIVLength() const + { return MAX_BLOCKSIZE; } +}; + // ************** key length *************** //! \class FixedKeyLength @@ -316,6 +427,38 @@ public: unsigned int BlockSize() const {return this->BLOCKSIZE;} }; +//! \class VariableBlockCipherImpl +//! \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for block ciphers with varibale block sizes +//! \tparam INFO a SimpleKeyingInterface derived class +//! \tparam BASE a SimpleKeyingInterface derived class +//! \details VariableBlockCipherImpl() provides a default implementation for block ciphers with varibale block sizes using AlgorithmImpl() +//! and SimpleKeyingInterfaceImpl(). +//! \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class CRYPTOPP_NO_VTABLE VariableBlockCipherImpl : public AlgorithmImpl > > +{ +public: + VariableBlockCipherImpl() : m_blocksize(0) {} + VariableBlockCipherImpl(unsigned int blocksize) : m_blocksize(blocksize) {} + + //! Provides the block size of the algorithm + //! \returns the block size, in bytes + unsigned int BlockSize() const { + return m_blocksize ? m_blocksize : this->BLOCKSIZE; + } + + //! Provides the initialization vector length of the algorithm + //! \returns the initialization vector length, in bytes + unsigned int IVSize() const { + if (!this->IsResynchronizable()) + throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization"); + return m_blocksize ? m_blocksize : this->IV_LENGTH; + } + +protected: + unsigned int m_blocksize; +}; + //! \class BlockCipherFinal //! \brief Provides class member functions to key a block cipher //! \tparam DIR a CipherDir diff --git a/simple.h b/simple.h index 2b92d343..8be4d422 100644 --- a/simple.h +++ b/simple.h @@ -58,6 +58,14 @@ public: explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {} }; +//! \class InvalidBlockSize +//! \brief Exception thrown when an invalid block size is encountered +class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument +{ +public: + explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {} +}; + //! \class InvalidPersonalizationLength //! \brief Exception thrown when an invalid personalization string length is encountered class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument