summaryrefslogtreecommitdiff
path: root/seckey.h
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2017-05-01 16:23:57 -0400
committerJeffrey Walton <noloader@gmail.com>2017-05-01 16:23:57 -0400
commitbd8edfa87b579073ead850f6ed19973381620cd3 (patch)
tree366a6048c2fdfdedcc7eb13f89392733c1a4ef0f /seckey.h
parent1543649ead50f2c1a0cdb2a3a8134d0cbcc81098 (diff)
downloadcryptopp-git-bd8edfa87b579073ead850f6ed19973381620cd3.tar.gz
Add variable block size support for block ciphers
This should lead the way for more modern block ciphers like Threefish and Kalyna. It tested well with both regular cipher modes (the mode has an instance of the cipher) and external cipher modes (the cipher and mode are distinct objects, and the mode holds a reference to the cipher). We still have to work out the details of naming a cipher. For example, Kalyna with a 128-bit key can use a 128-bit or 256-bit block size. Kalyna-128 is not enough to describe the algorithm and locate it in the object registry. Kalyna-128-128 looks kind of weird; maybe Kalyna-128(128) or Kalyna-128(256) would be better. Here are the initial test cases to verify functionality: byte key[64] = {}, iv[32] = {}; ECB_Mode<Kalyna>::Encryption enc1; enc1.SetKey(key, 16); CBC_Mode<Kalyna>::Encryption enc2; enc2.SetKeyWithIV(key, 16, iv); AlgorithmParameters params = MakeParameters (Name::BlockSize(), 32) (Name::IV(), ConstByteArrayParameter(iv, 32)); CTR_Mode<Kalyna>::Encryption enc3; enc3.SetKey(key, 16, params); CBC_Mode<Kalyna>::Encryption enc4; enc4.SetKey(key, 32, params); Kalyna::Encryption enc5; ECB_Mode_ExternalCipher::Encryption ecb(enc5); ecb.SetKey(key, 16, params); Kalyna::Encryption enc6; ECB_Mode_ExternalCipher::Encryption cbc(enc6); cbc.SetKey(key, 32, params);
Diffstat (limited to 'seckey.h')
-rw-r--r--seckey.h145
1 files changed, 144 insertions, 1 deletions
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<unsigned int>(rounds);
}
};
+//! \class VariableBlockSize
+//! \brief Inherited by algorithms with variable blocksize
+//! \tparam D Default blocksize
+//! \tparam N Minimum blocksize
+//! \tparam M Maximum blocksize
+template <unsigned int D, unsigned int N=1, unsigned int M=INT_MAX> // 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 &param, 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<unsigned int>(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 INFO, class BASE = BlockCipher>
+class CRYPTOPP_NO_VTABLE VariableBlockCipherImpl : public AlgorithmImpl<SimpleKeyingInterfaceImpl<TwoBases<BASE, INFO> > >
+{
+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