// strciphr.h - originally written and placed in the public domain by Wei Dai
/// \file strciphr.h
/// \brief Classes for implementing stream ciphers
/// \details This file contains helper classes for implementing stream ciphers.
/// All this infrastructure may look very complex compared to what's in Crypto++ 4.x,
/// but stream ciphers implementations now support a lot of new functionality,
/// including better performance (minimizing copying), resetting of keys and IVs, and methods to
/// query which features are supported by a cipher.
/// \details Here's an explanation of these classes. The word "policy" is used here to mean a class with a
/// set of methods that must be implemented by individual stream cipher implementations.
/// This is usually much simpler than the full stream cipher API, which is implemented by
/// either AdditiveCipherTemplate or CFB_CipherTemplate using the policy. So for example, an
/// implementation of SEAL only needs to implement the AdditiveCipherAbstractPolicy interface
/// (since it's an additive cipher, i.e., it xors a keystream into the plaintext).
/// See this line in seal.h:
///
/// typedef SymmetricCipherFinal\, AdditiveCipherTemplate\<\> \> \> Encryption;
///
/// \details AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't need
/// to take a policy class as a template parameter (although this is allowed), so that
/// their code is not duplicated for each new cipher. Instead they each
/// get a reference to an abstract policy interface by calling AccessPolicy() on itself, so
/// AccessPolicy() must be overridden to return the actual policy reference. This is done
/// by the ConceretePolicyHolder class. Finally, SymmetricCipherFinal implements the constructors and
/// other functions that must be implemented by the most derived class.
#ifndef CRYPTOPP_STRCIPHR_H
#define CRYPTOPP_STRCIPHR_H
#include "config.h"
#if CRYPTOPP_MSC_VERSION
# pragma warning(push)
# pragma warning(disable: 4127 4189 4231 4275)
#endif
#include "cryptlib.h"
#include "seckey.h"
#include "secblock.h"
#include "argnames.h"
NAMESPACE_BEGIN(CryptoPP)
/// \class AbstractPolicyHolder
/// \brief Access a stream cipher policy object
/// \tparam POLICY_INTERFACE class implementing AbstractPolicyHolder
/// \tparam BASE class or type to use as a base class
template
class CRYPTOPP_NO_VTABLE AbstractPolicyHolder : public BASE
{
public:
typedef POLICY_INTERFACE PolicyInterface;
virtual ~AbstractPolicyHolder() {}
protected:
virtual const POLICY_INTERFACE & GetPolicy() const =0;
virtual POLICY_INTERFACE & AccessPolicy() =0;
};
/// \class ConcretePolicyHolder
/// \brief Stream cipher policy object
/// \tparam POLICY class implementing AbstractPolicyHolder
/// \tparam BASE class or type to use as a base class
template
class ConcretePolicyHolder : public BASE, protected POLICY
{
public:
virtual ~ConcretePolicyHolder() {}
protected:
const POLICY_INTERFACE & GetPolicy() const {return *this;}
POLICY_INTERFACE & AccessPolicy() {return *this;}
};
/// \brief Keystream operation flags
/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize()
/// and AdditiveCipherAbstractPolicy::GetAlignment()
enum KeystreamOperationFlags {
/// \brief Output buffer is aligned
OUTPUT_ALIGNED=1,
/// \brief Input buffer is aligned
INPUT_ALIGNED=2,
/// \brief Input buffer is NULL
INPUT_NULL = 4
};
/// \brief Keystream operation flags
/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize()
/// and AdditiveCipherAbstractPolicy::GetAlignment()
enum KeystreamOperation {
/// \brief Wirte the keystream to the output buffer, input is NULL
WRITE_KEYSTREAM = INPUT_NULL,
/// \brief Wirte the keystream to the aligned output buffer, input is NULL
WRITE_KEYSTREAM_ALIGNED = INPUT_NULL | OUTPUT_ALIGNED,
/// \brief XOR the input buffer and keystream, write to the output buffer
XOR_KEYSTREAM = 0,
/// \brief XOR the aligned input buffer and keystream, write to the output buffer
XOR_KEYSTREAM_INPUT_ALIGNED = INPUT_ALIGNED,
/// \brief XOR the input buffer and keystream, write to the aligned output buffer
XOR_KEYSTREAM_OUTPUT_ALIGNED= OUTPUT_ALIGNED,
/// \brief XOR the aligned input buffer and keystream, write to the aligned output buffer
XOR_KEYSTREAM_BOTH_ALIGNED = OUTPUT_ALIGNED | INPUT_ALIGNED};
/// \class AdditiveCipherAbstractPolicy
/// \brief Policy object for additive stream ciphers
struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy
{
virtual ~AdditiveCipherAbstractPolicy() {}
/// \brief Provides data alignment requirements
/// \returns data alignment requirements, in bytes
/// \details Internally, the default implementation returns 1. If the stream cipher is implemented
/// using an SSE2 ASM or intrinsics, then the value returned is usually 16.
virtual unsigned int GetAlignment() const {return 1;}
/// \brief Provides number of bytes operated upon during an iteration
/// \returns bytes operated upon during an iteration, in bytes
/// \sa GetOptimalBlockSize()
virtual unsigned int GetBytesPerIteration() const =0;
/// \brief Provides number of ideal bytes to process
/// \returns the ideal number of bytes to process
/// \details Internally, the default implementation returns GetBytesPerIteration()
/// \sa GetBytesPerIteration()
virtual unsigned int GetOptimalBlockSize() const {return GetBytesPerIteration();}
/// \brief Provides buffer size based on iterations
/// \returns the buffer size based on iterations, in bytes
virtual unsigned int GetIterationsToBuffer() const =0;
/// \brief Generate the keystream
/// \param keystream the key stream
/// \param iterationCount the number of iterations to generate the key stream
/// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream()
virtual void WriteKeystream(byte *keystream, size_t iterationCount)
{OperateKeystream(KeystreamOperation(INPUT_NULL | (KeystreamOperationFlags)IsAlignedOn(keystream, GetAlignment())), keystream, NULLPTR, iterationCount);}
/// \brief Flag indicating
/// \returns true if the stream can be generated independent of the transformation input, false otherwise
/// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream()
virtual bool CanOperateKeystream() const {return false;}
/// \brief Operates the keystream
/// \param operation the operation with additional flags
/// \param output the output buffer
/// \param input the input buffer
/// \param iterationCount the number of iterations to perform on the input
/// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer,
/// which will be derived from GetBytesPerIteration().
/// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation()
virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
{CRYPTOPP_UNUSED(operation); CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false);}
/// \brief Key the cipher
/// \param params set of NameValuePairs use to initialize this object
/// \param key a byte array used to key the cipher
/// \param length the size of the key array
virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0;
/// \brief Resynchronize the cipher
/// \param keystreamBuffer the keystream buffer
/// \param iv a byte array used to resynchronize the cipher
/// \param length the size of the IV array
virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
{CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");}
/// \brief Flag indicating random access
/// \returns true if the cipher is seekable, false otherwise
/// \sa SeekToIteration()
virtual bool CipherIsRandomAccess() const =0;
/// \brief Seeks to a random position in the stream
/// \sa CipherIsRandomAccess()
virtual void SeekToIteration(lword iterationCount)
{CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(!CipherIsRandomAccess()); throw NotImplemented("StreamTransformation: this object doesn't support random access");}
};
/// \class AdditiveCipherConcretePolicy
/// \brief Base class for additive stream ciphers
/// \tparam WT word type
/// \tparam W count of words
/// \tparam X bytes per iteration count
/// \tparam BASE AdditiveCipherAbstractPolicy derived base class
template
struct CRYPTOPP_NO_VTABLE AdditiveCipherConcretePolicy : public BASE
{
typedef WT WordType;
CRYPTOPP_CONSTANT(BYTES_PER_ITERATION = sizeof(WordType) * W)
#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X64)
/// \brief Provides data alignment requirements
/// \returns data alignment requirements, in bytes
/// \details Internally, the default implementation returns 1. If the stream cipher is implemented
/// using an SSE2 ASM or intrinsics, then the value returned is usually 16.
unsigned int GetAlignment() const {return GetAlignmentOf();}
#endif
/// \brief Provides number of bytes operated upon during an iteration
/// \returns bytes operated upon during an iteration, in bytes
/// \sa GetOptimalBlockSize()
unsigned int GetBytesPerIteration() const {return BYTES_PER_ITERATION;}
/// \brief Provides buffer size based on iterations
/// \returns the buffer size based on iterations, in bytes
unsigned int GetIterationsToBuffer() const {return X;}
/// \brief Flag indicating
/// \returns true if the stream can be generated independent of the transformation input, false otherwise
/// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream()
bool CanOperateKeystream() const {return true;}
/// \brief Operates the keystream
/// \param operation the operation with additional flags
/// \param output the output buffer
/// \param input the input buffer
/// \param iterationCount the number of iterations to perform on the input
/// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer,
/// which will be derived from GetBytesPerIteration().
/// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation()
virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) =0;
};
/// \brief Helper macro to implement OperateKeystream
#define CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, b, i, a) \
PutWord(bool(x & OUTPUT_ALIGNED), b, output+i*sizeof(WordType), (x & INPUT_NULL) ? (a) : (a) ^ GetWord(bool(x & INPUT_ALIGNED), b, input+i*sizeof(WordType)));
/// \brief Helper macro to implement OperateKeystream
#define CRYPTOPP_KEYSTREAM_OUTPUT_XMM(x, i, a) {\
__m128i t = (x & INPUT_NULL) ? a : _mm_xor_si128(a, (x & INPUT_ALIGNED) ? _mm_load_si128((__m128i *)input+i) : _mm_loadu_si128((__m128i *)input+i));\
if (x & OUTPUT_ALIGNED) _mm_store_si128((__m128i *)output+i, t);\
else _mm_storeu_si128((__m128i *)output+i, t);}
/// \brief Helper macro to implement OperateKeystream
#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y) \
switch (operation) \
{ \
case WRITE_KEYSTREAM: \
x(WRITE_KEYSTREAM) \
break; \
case XOR_KEYSTREAM: \
x(XOR_KEYSTREAM) \
input += y; \
break; \
case XOR_KEYSTREAM_INPUT_ALIGNED: \
x(XOR_KEYSTREAM_INPUT_ALIGNED) \
input += y; \
break; \
case XOR_KEYSTREAM_OUTPUT_ALIGNED: \
x(XOR_KEYSTREAM_OUTPUT_ALIGNED) \
input += y; \
break; \
case WRITE_KEYSTREAM_ALIGNED: \
x(WRITE_KEYSTREAM_ALIGNED) \
break; \
case XOR_KEYSTREAM_BOTH_ALIGNED: \
x(XOR_KEYSTREAM_BOTH_ALIGNED) \
input += y; \
break; \
} \
output += y;
/// \class AdditiveCipherTemplate
/// \brief Base class for additive stream ciphers with SymmetricCipher interface
/// \tparam BASE AbstractPolicyHolder base class
template >
class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE, public RandomNumberGenerator
{
public:
virtual ~AdditiveCipherTemplate() {}
/// \brief Generate random array of bytes
/// \param output the byte buffer
/// \param size the length of the buffer, in bytes
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
void GenerateBlock(byte *output, size_t size);
/// \brief Apply keystream to data
/// \param outString a buffer to write the transformed data
/// \param inString a buffer to read the data
/// \param length the size fo the buffers, in bytes
/// \details This is the primary method to operate a stream cipher. For example:
///
/// size_t size = 30;
/// byte plain[size] = "Do or do not; there is no try";
/// byte cipher[size];
/// ...
/// ChaCha20 chacha(key, keySize);
/// chacha.ProcessData(cipher, plain, size);
///
void ProcessData(byte *outString, const byte *inString, size_t length);
/// \brief Resynchronize the cipher
/// \param iv a byte array used to resynchronize the cipher
/// \param length the size of the IV array
void Resynchronize(const byte *iv, int length=-1);
/// \brief Provides number of ideal bytes to process
/// \returns the ideal number of bytes to process
/// \details Internally, the default implementation returns GetBytesPerIteration()
/// \sa GetBytesPerIteration() and GetOptimalNextBlockSize()
unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();}
/// \brief Provides number of ideal bytes to process
/// \returns the ideal number of bytes to process
/// \details Internally, the default implementation returns remaining unprocessed bytes
/// \sa GetBytesPerIteration() and OptimalBlockSize()
unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;}
/// \brief Provides number of ideal data alignment
/// \returns the ideal data alignment, in bytes
/// \sa GetAlignment() and OptimalBlockSize()
unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();}
/// \brief Determines if the cipher is self inverting
/// \returns true if the stream cipher is self inverting, false otherwise
bool IsSelfInverting() const {return true;}
/// \brief Determines if the cipher is a forward transformation
/// \returns true if the stream cipher is a forward transformation, false otherwise
bool IsForwardTransformation() const {return true;}
/// \brief Flag indicating random access
/// \returns true if the cipher is seekable, false otherwise
/// \sa Seek()
bool IsRandomAccess() const {return this->GetPolicy().CipherIsRandomAccess();}
/// \brief Seeks to a random position in the stream
/// \param position the absolute position in the stream
/// \sa IsRandomAccess()
void Seek(lword position);
typedef typename BASE::PolicyInterface PolicyInterface;
protected:
void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms);
unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();}
inline byte * KeystreamBufferBegin() {return this->m_buffer.data();}
inline byte * KeystreamBufferEnd() {return (this->m_buffer.data() + this->m_buffer.size());}
SecByteBlock m_buffer;
size_t m_leftOver;
};
/// \class CFB_CipherAbstractPolicy
/// \brief Policy object for feeback based stream ciphers
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_CipherAbstractPolicy
{
public:
virtual ~CFB_CipherAbstractPolicy() {}
/// \brief Provides data alignment requirements
/// \returns data alignment requirements, in bytes
/// \details Internally, the default implementation returns 1. If the stream cipher is implemented
/// using an SSE2 ASM or intrinsics, then the value returned is usually 16.
virtual unsigned int GetAlignment() const =0;
/// \brief Provides number of bytes operated upon during an iteration
/// \returns bytes operated upon during an iteration, in bytes
/// \sa GetOptimalBlockSize()
virtual unsigned int GetBytesPerIteration() const =0;
/// \brief Access the feedback register
/// \returns pointer to the first byte of the feedback register
virtual byte * GetRegisterBegin() =0;
/// \brief TODO
virtual void TransformRegister() =0;
/// \brief Flag indicating iteration support
/// \returns true if the cipher supports iteration, false otherwise
virtual bool CanIterate() const {return false;}
/// \brief Iterate the cipher
/// \param output the output buffer
/// \param input the input buffer
/// \param dir the direction of the cipher
/// \param iterationCount the number of iterations to perform on the input
/// \sa IsSelfInverting() and IsForwardTransformation()
virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount)
{CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(dir); CRYPTOPP_UNUSED(iterationCount);
CRYPTOPP_ASSERT(false); /*throw 0;*/ throw Exception(Exception::OTHER_ERROR, "SimpleKeyingInterface: unexpected error");}
/// \brief Key the cipher
/// \param params set of NameValuePairs use to initialize this object
/// \param key a byte array used to key the cipher
/// \param length the size of the key array
virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0;
/// \brief Resynchronize the cipher
/// \param iv a byte array used to resynchronize the cipher
/// \param length the size of the IV array
virtual void CipherResynchronize(const byte *iv, size_t length)
{CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");}
};
/// \class CFB_CipherConcretePolicy
/// \brief Base class for feedback based stream ciphers
/// \tparam WT word type
/// \tparam W count of words
/// \tparam BASE CFB_CipherAbstractPolicy derived base class
template
struct CRYPTOPP_NO_VTABLE CFB_CipherConcretePolicy : public BASE
{
typedef WT WordType;
/// \brief Provides data alignment requirements
/// \returns data alignment requirements, in bytes
/// \details Internally, the default implementation returns 1. If the stream cipher is implemented
/// using an SSE2 ASM or intrinsics, then the value returned is usually 16.
unsigned int GetAlignment() const {return sizeof(WordType);}
/// \brief Provides number of bytes operated upon during an iteration
/// \returns bytes operated upon during an iteration, in bytes
/// \sa GetOptimalBlockSize()
unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;}
/// \brief Flag indicating iteration support
/// \returns true if the cipher supports iteration, false otherwise
bool CanIterate() const {return true;}
/// \brief Perform one iteration in the forward direction
void TransformRegister() {this->Iterate(NULLPTR, NULLPTR, ENCRYPTION, 1);}
/// \brief Provides alternate access to a feedback register
/// \tparam B enumeration indicating endianness
/// \details RegisterOutput() provides alternate access to the feedback register. The
/// enumeration B is BigEndian or LittleEndian. Repeatedly applying operator()
/// results in advancing in the register.
template
struct RegisterOutput
{
RegisterOutput(byte *output, const byte *input, CipherDir dir)
: m_output(output), m_input(input), m_dir(dir) {}
/// \brief XOR feedback register with data
/// \param registerWord data represented as a word type
/// \returns reference to the next feedback register word
inline RegisterOutput& operator()(WordType ®isterWord)
{
CRYPTOPP_ASSERT(IsAligned(m_output));
CRYPTOPP_ASSERT(IsAligned(m_input));
if (!NativeByteOrderIs(B::ToEnum()))
registerWord = ByteReverse(registerWord);
if (m_dir == ENCRYPTION)
{
if (m_input == NULLPTR)
{
CRYPTOPP_ASSERT(m_output == NULLPTR);
}
else
{
WordType ct = *(const WordType *)m_input ^ registerWord;
registerWord = ct;
*(WordType*)m_output = ct;
m_input += sizeof(WordType);
m_output += sizeof(WordType);
}
}
else
{
WordType ct = *(const WordType *)m_input;
*(WordType*)m_output = registerWord ^ ct;
registerWord = ct;
m_input += sizeof(WordType);
m_output += sizeof(WordType);
}
// registerWord is left unreversed so it can be xor-ed with further input
return *this;
}
byte *m_output;
const byte *m_input;
CipherDir m_dir;
};
};
/// \class CFB_CipherTemplate
/// \brief Base class for feedback based stream ciphers with SymmetricCipher interface
/// \tparam BASE AbstractPolicyHolder base class
template
class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE
{
public:
/// \brief Apply keystream to data
/// \param outString a buffer to write the transformed data
/// \param inString a buffer to read the data
/// \param length the size fo the buffers, in bytes
/// \details This is the primary method to operate a stream cipher. For example:
///
/// size_t size = 30;
/// byte plain[size] = "Do or do not; there is no try";
/// byte cipher[size];
/// ...
/// ChaCha20 chacha(key, keySize);
/// chacha.ProcessData(cipher, plain, size);
///
void ProcessData(byte *outString, const byte *inString, size_t length);
/// \brief Resynchronize the cipher
/// \param iv a byte array used to resynchronize the cipher
/// \param length the size of the IV array
void Resynchronize(const byte *iv, int length=-1);
/// \brief Provides number of ideal bytes to process
/// \returns the ideal number of bytes to process
/// \details Internally, the default implementation returns GetBytesPerIteration()
/// \sa GetBytesPerIteration() and GetOptimalNextBlockSize()
unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();}
/// \brief Provides number of ideal bytes to process
/// \returns the ideal number of bytes to process
/// \details Internally, the default implementation returns remaining unprocessed bytes
/// \sa GetBytesPerIteration() and OptimalBlockSize()
unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;}
/// \brief Provides number of ideal data alignment
/// \returns the ideal data alignment, in bytes
/// \sa GetAlignment() and OptimalBlockSize()
unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();}
/// \brief Flag indicating random access
/// \returns true if the cipher is seekable, false otherwise
/// \sa Seek()
bool IsRandomAccess() const {return false;}
/// \brief Determines if the cipher is self inverting
/// \returns true if the stream cipher is self inverting, false otherwise
bool IsSelfInverting() const {return false;}
typedef typename BASE::PolicyInterface PolicyInterface;
protected:
virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) =0;
void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms);
size_t m_leftOver;
};
/// \class CFB_EncryptionTemplate
/// \brief Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface
/// \tparam BASE AbstractPolicyHolder base class
template >
class CRYPTOPP_NO_VTABLE CFB_EncryptionTemplate : public CFB_CipherTemplate
{
bool IsForwardTransformation() const {return true;}
void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length);
};
/// \class CFB_DecryptionTemplate
/// \brief Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface
/// \tparam BASE AbstractPolicyHolder base class
template >
class CRYPTOPP_NO_VTABLE CFB_DecryptionTemplate : public CFB_CipherTemplate
{
bool IsForwardTransformation() const {return false;}
void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length);
};
/// \class CFB_RequireFullDataBlocks
/// \brief Base class for feedback based stream ciphers with a mandatory block size
/// \tparam BASE CFB_EncryptionTemplate or CFB_DecryptionTemplate base class
template
class CFB_RequireFullDataBlocks : public BASE
{
public:
unsigned int MandatoryBlockSize() const {return this->OptimalBlockSize();}
};
/// \class SymmetricCipherFinal
/// \brief SymmetricCipher implementation
/// \tparam BASE AbstractPolicyHolder derived base class
/// \tparam INFO AbstractPolicyHolder derived information class
/// \sa Weak::ARC4, ChaCha8, ChaCha12, ChaCha20, Salsa20, SEAL, Sosemanuk, WAKE
template
class SymmetricCipherFinal : public AlgorithmImpl, INFO>
{
public:
virtual ~SymmetricCipherFinal() {}
/// \brief Construct a stream cipher
SymmetricCipherFinal() {}
/// \brief Construct a stream cipher
/// \param key a byte array used to key the cipher
/// \details This overload uses DEFAULT_KEYLENGTH
SymmetricCipherFinal(const byte *key)
{this->SetKey(key, this->DEFAULT_KEYLENGTH);}
/// \brief Construct a stream cipher
/// \param key a byte array used to key the cipher
/// \param length the size of the key array
SymmetricCipherFinal(const byte *key, size_t length)
{this->SetKey(key, length);}
/// \brief Construct a stream cipher
/// \param key a byte array used to key the cipher
/// \param length the size of the key array
/// \param iv a byte array used as an initialization vector
SymmetricCipherFinal(const byte *key, size_t length, const byte *iv)
{this->SetKeyWithIV(key, length, iv);}
/// \brief Clone a SymmetricCipher
/// \returns a new SymmetricCipher based on this object
Clonable * Clone() const {return static_cast(new SymmetricCipherFinal(*this));}
};
NAMESPACE_END
#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
#include "strciphr.cpp"
#endif
NAMESPACE_BEGIN(CryptoPP)
CRYPTOPP_DLL_TEMPLATE_CLASS AbstractPolicyHolder;
CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >;
CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >;
CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >;
CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >;
NAMESPACE_END
#if CRYPTOPP_MSC_VERSION
# pragma warning(pop)
#endif
#endif