// 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