1/*! \file 2 This file contains helper classes for implementing stream ciphers. 3 4 All this infrastructure may look very complex compared to what's in Crypto++ 4.x, 5 but stream ciphers implementations now support a lot of new functionality, 6 including better performance (minimizing copying), resetting of keys and IVs, and methods to 7 query which features are supported by a cipher. 8 9 Here's an explanation of these classes. The word "policy" is used here to mean a class with a 10 set of methods that must be implemented by individual stream cipher implementations. 11 This is usually much simpler than the full stream cipher API, which is implemented by 12 either AdditiveCipherTemplate or CFB_CipherTemplate using the policy. So for example, an 13 implementation of SEAL only needs to implement the AdditiveCipherAbstractPolicy interface 14 (since it's an additive cipher, i.e., it xors a keystream into the plaintext). 15 See this line in seal.h: 16 17 typedef SymmetricCipherFinal\<ConcretePolicyHolder\<SEAL_Policy\<B\>, AdditiveCipherTemplate\<\> \> \> Encryption; 18 19 AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't need 20 to take a policy class as a template parameter (although this is allowed), so that 21 their code is not duplicated for each new cipher. Instead they each 22 get a reference to an abstract policy interface by calling AccessPolicy() on itself, so 23 AccessPolicy() must be overriden to return the actual policy reference. This is done 24 by the ConceretePolicyHolder class. Finally, SymmetricCipherFinal implements the constructors and 25 other functions that must be implemented by the most derived class. 26*/ 27 28#ifndef CRYPTOPP_STRCIPHR_H 29#define CRYPTOPP_STRCIPHR_H 30 31#include "seckey.h" 32#include "secblock.h" 33#include "argnames.h" 34 35NAMESPACE_BEGIN(CryptoPP) 36 37template <class POLICY_INTERFACE, class BASE = Empty> 38class CRYPTOPP_NO_VTABLE AbstractPolicyHolder : public BASE 39{ 40public: 41 typedef POLICY_INTERFACE PolicyInterface; 42 virtual ~AbstractPolicyHolder() {} 43 44protected: 45 virtual const POLICY_INTERFACE & GetPolicy() const =0; 46 virtual POLICY_INTERFACE & AccessPolicy() =0; 47}; 48 49template <class POLICY, class BASE, class POLICY_INTERFACE = CPP_TYPENAME BASE::PolicyInterface> 50class ConcretePolicyHolder : public BASE, protected POLICY 51{ 52protected: 53 const POLICY_INTERFACE & GetPolicy() const {return *this;} 54 POLICY_INTERFACE & AccessPolicy() {return *this;} 55}; 56 57enum KeystreamOperationFlags {OUTPUT_ALIGNED=1, INPUT_ALIGNED=2, INPUT_NULL = 4}; 58enum KeystreamOperation { 59 WRITE_KEYSTREAM = INPUT_NULL, 60 WRITE_KEYSTREAM_ALIGNED = INPUT_NULL | OUTPUT_ALIGNED, 61 XOR_KEYSTREAM = 0, 62 XOR_KEYSTREAM_INPUT_ALIGNED = INPUT_ALIGNED, 63 XOR_KEYSTREAM_OUTPUT_ALIGNED= OUTPUT_ALIGNED, 64 XOR_KEYSTREAM_BOTH_ALIGNED = OUTPUT_ALIGNED | INPUT_ALIGNED}; 65 66struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy 67{ 68 virtual ~AdditiveCipherAbstractPolicy() {} 69 virtual unsigned int GetAlignment() const {return 1;} 70 virtual unsigned int GetBytesPerIteration() const =0; 71 virtual unsigned int GetOptimalBlockSize() const {return GetBytesPerIteration();} 72 virtual unsigned int GetIterationsToBuffer() const =0; 73 virtual void WriteKeystream(byte *keystream, size_t iterationCount) 74 {OperateKeystream(KeystreamOperation(INPUT_NULL | (KeystreamOperationFlags)IsAlignedOn(keystream, GetAlignment())), keystream, NULL, iterationCount);} 75 virtual bool CanOperateKeystream() const {return false;} 76 virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) {assert(false);} 77 virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; 78 virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} 79 virtual bool CipherIsRandomAccess() const =0; 80 virtual void SeekToIteration(lword iterationCount) {assert(!CipherIsRandomAccess()); throw NotImplemented("StreamTransformation: this object doesn't support random access");} 81}; 82 83template <typename WT, unsigned int W, unsigned int X = 1, class BASE = AdditiveCipherAbstractPolicy> 84struct CRYPTOPP_NO_VTABLE AdditiveCipherConcretePolicy : public BASE 85{ 86 typedef WT WordType; 87 CRYPTOPP_CONSTANT(BYTES_PER_ITERATION = sizeof(WordType) * W) 88 89#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X64) 90 unsigned int GetAlignment() const {return GetAlignmentOf<WordType>();} 91#endif 92 unsigned int GetBytesPerIteration() const {return BYTES_PER_ITERATION;} 93 unsigned int GetIterationsToBuffer() const {return X;} 94 bool CanOperateKeystream() const {return true;} 95 virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) =0; 96}; 97 98// use these to implement OperateKeystream 99#define CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, b, i, a) \ 100 PutWord(bool(x & OUTPUT_ALIGNED), b, output+i*sizeof(WordType), (x & INPUT_NULL) ? a : a ^ GetWord<WordType>(bool(x & INPUT_ALIGNED), b, input+i*sizeof(WordType))); 101#define CRYPTOPP_KEYSTREAM_OUTPUT_XMM(x, i, a) {\ 102 __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));\ 103 if (x & OUTPUT_ALIGNED) _mm_store_si128((__m128i *)output+i, t);\ 104 else _mm_storeu_si128((__m128i *)output+i, t);} 105#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y) \ 106 switch (operation) \ 107 { \ 108 case WRITE_KEYSTREAM: \ 109 x(WRITE_KEYSTREAM) \ 110 break; \ 111 case XOR_KEYSTREAM: \ 112 x(XOR_KEYSTREAM) \ 113 input += y; \ 114 break; \ 115 case XOR_KEYSTREAM_INPUT_ALIGNED: \ 116 x(XOR_KEYSTREAM_INPUT_ALIGNED) \ 117 input += y; \ 118 break; \ 119 case XOR_KEYSTREAM_OUTPUT_ALIGNED: \ 120 x(XOR_KEYSTREAM_OUTPUT_ALIGNED) \ 121 input += y; \ 122 break; \ 123 case WRITE_KEYSTREAM_ALIGNED: \ 124 x(WRITE_KEYSTREAM_ALIGNED) \ 125 break; \ 126 case XOR_KEYSTREAM_BOTH_ALIGNED: \ 127 x(XOR_KEYSTREAM_BOTH_ALIGNED) \ 128 input += y; \ 129 break; \ 130 } \ 131 output += y; 132 133template <class BASE = AbstractPolicyHolder<AdditiveCipherAbstractPolicy, SymmetricCipher> > 134class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE, public RandomNumberGenerator 135{ 136public: 137 void GenerateBlock(byte *output, size_t size); 138 void ProcessData(byte *outString, const byte *inString, size_t length); 139 void Resynchronize(const byte *iv, int length=-1); 140 unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();} 141 unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;} 142 unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} 143 bool IsSelfInverting() const {return true;} 144 bool IsForwardTransformation() const {return true;} 145 bool IsRandomAccess() const {return this->GetPolicy().CipherIsRandomAccess();} 146 void Seek(lword position); 147 148 typedef typename BASE::PolicyInterface PolicyInterface; 149 150protected: 151 void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); 152 153 unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();} 154 155 inline byte * KeystreamBufferBegin() {return this->m_buffer.data();} 156 inline byte * KeystreamBufferEnd() {return (this->m_buffer.data() + this->m_buffer.size());} 157 158 SecByteBlock m_buffer; 159 size_t m_leftOver; 160}; 161 162class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_CipherAbstractPolicy 163{ 164public: 165 virtual ~CFB_CipherAbstractPolicy() {} 166 virtual unsigned int GetAlignment() const =0; 167 virtual unsigned int GetBytesPerIteration() const =0; 168 virtual byte * GetRegisterBegin() =0; 169 virtual void TransformRegister() =0; 170 virtual bool CanIterate() const {return false;} 171 virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) {assert(false); throw 0;} 172 virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; 173 virtual void CipherResynchronize(const byte *iv, size_t length) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} 174}; 175 176template <typename WT, unsigned int W, class BASE = CFB_CipherAbstractPolicy> 177struct CRYPTOPP_NO_VTABLE CFB_CipherConcretePolicy : public BASE 178{ 179 typedef WT WordType; 180 181 unsigned int GetAlignment() const {return sizeof(WordType);} 182 unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} 183 bool CanIterate() const {return true;} 184 void TransformRegister() {this->Iterate(NULL, NULL, ENCRYPTION, 1);} 185 186 template <class B> 187 struct RegisterOutput 188 { 189 RegisterOutput(byte *output, const byte *input, CipherDir dir) 190 : m_output(output), m_input(input), m_dir(dir) {} 191 192 inline RegisterOutput& operator()(WordType ®isterWord) 193 { 194 assert(IsAligned<WordType>(m_output)); 195 assert(IsAligned<WordType>(m_input)); 196 197 if (!NativeByteOrderIs(B::ToEnum())) 198 registerWord = ByteReverse(registerWord); 199 200 if (m_dir == ENCRYPTION) 201 { 202 if (m_input == NULL) 203 assert(m_output == NULL); 204 else 205 { 206 WordType ct = *(const WordType *)m_input ^ registerWord; 207 registerWord = ct; 208 *(WordType*)m_output = ct; 209 m_input += sizeof(WordType); 210 m_output += sizeof(WordType); 211 } 212 } 213 else 214 { 215 WordType ct = *(const WordType *)m_input; 216 *(WordType*)m_output = registerWord ^ ct; 217 registerWord = ct; 218 m_input += sizeof(WordType); 219 m_output += sizeof(WordType); 220 } 221 222 // registerWord is left unreversed so it can be xor-ed with further input 223 224 return *this; 225 } 226 227 byte *m_output; 228 const byte *m_input; 229 CipherDir m_dir; 230 }; 231}; 232 233template <class BASE> 234class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE 235{ 236public: 237 void ProcessData(byte *outString, const byte *inString, size_t length); 238 void Resynchronize(const byte *iv, int length=-1); 239 unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();} 240 unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;} 241 unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} 242 bool IsRandomAccess() const {return false;} 243 bool IsSelfInverting() const {return false;} 244 245 typedef typename BASE::PolicyInterface PolicyInterface; 246 247protected: 248 virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) =0; 249 250 void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); 251 252 size_t m_leftOver; 253}; 254 255template <class BASE = AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> > 256class CRYPTOPP_NO_VTABLE CFB_EncryptionTemplate : public CFB_CipherTemplate<BASE> 257{ 258 bool IsForwardTransformation() const {return true;} 259 void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); 260}; 261 262template <class BASE = AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> > 263class CRYPTOPP_NO_VTABLE CFB_DecryptionTemplate : public CFB_CipherTemplate<BASE> 264{ 265 bool IsForwardTransformation() const {return false;} 266 void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); 267}; 268 269template <class BASE> 270class CFB_RequireFullDataBlocks : public BASE 271{ 272public: 273 unsigned int MandatoryBlockSize() const {return this->OptimalBlockSize();} 274}; 275 276//! _ 277template <class BASE, class INFO = BASE> 278class SymmetricCipherFinal : public AlgorithmImpl<SimpleKeyingInterfaceImpl<BASE, INFO>, INFO> 279{ 280public: 281 SymmetricCipherFinal() {} 282 SymmetricCipherFinal(const byte *key) 283 {this->SetKey(key, this->DEFAULT_KEYLENGTH);} 284 SymmetricCipherFinal(const byte *key, size_t length) 285 {this->SetKey(key, length);} 286 SymmetricCipherFinal(const byte *key, size_t length, const byte *iv) 287 {this->SetKeyWithIV(key, length, iv);} 288 289 Clonable * Clone() const {return static_cast<SymmetricCipher *>(new SymmetricCipherFinal<BASE, INFO>(*this));} 290}; 291 292NAMESPACE_END 293 294#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES 295#include "strciphr.cpp" 296#endif 297 298NAMESPACE_BEGIN(CryptoPP) 299CRYPTOPP_DLL_TEMPLATE_CLASS AbstractPolicyHolder<AdditiveCipherAbstractPolicy, SymmetricCipher>; 300CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, SymmetricCipher> >; 301CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> >; 302CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> >; 303CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, SymmetricCipher> >; 304NAMESPACE_END 305 306#endif 307