Crypto++
modes.h
Go to the documentation of this file.
1 #ifndef CRYPTOPP_MODES_H
2 #define CRYPTOPP_MODES_H
3 
4 /*! \file
5 */
6 
7 #include "cryptlib.h"
8 #include "secblock.h"
9 #include "misc.h"
10 #include "strciphr.h"
11 #include "argnames.h"
12 #include "algparam.h"
13 
14 NAMESPACE_BEGIN(CryptoPP)
15 
16 //! Cipher modes documentation. See NIST SP 800-38A for definitions of these modes. See AuthenticatedSymmetricCipherDocumentation for authenticated encryption modes.
17 
18 /*! Each class derived from this one defines two types, Encryption and Decryption,
19  both of which implement the SymmetricCipher interface.
20  For each mode there are two classes, one of which is a template class,
21  and the other one has a name that ends in "_ExternalCipher".
22  The "external cipher" mode objects hold a reference to the underlying block cipher,
23  instead of holding an instance of it. The reference must be passed in to the constructor.
24  For the "cipher holder" classes, the CIPHER template parameter should be a class
25  derived from BlockCipherDocumentation, for example DES or AES.
26 */
28 {
29 };
30 
31 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CipherModeBase : public SymmetricCipher
32 {
33 public:
34  size_t MinKeyLength() const {return m_cipher->MinKeyLength();}
35  size_t MaxKeyLength() const {return m_cipher->MaxKeyLength();}
36  size_t DefaultKeyLength() const {return m_cipher->DefaultKeyLength();}
37  size_t GetValidKeyLength(size_t n) const {return m_cipher->GetValidKeyLength(n);}
38  bool IsValidKeyLength(size_t n) const {return m_cipher->IsValidKeyLength(n);}
39 
40  unsigned int OptimalDataAlignment() const {return m_cipher->OptimalDataAlignment();}
41 
42  unsigned int IVSize() const {return BlockSize();}
43  virtual IV_Requirement IVRequirement() const =0;
44 
45  void SetCipher(BlockCipher &cipher)
46  {
47  this->ThrowIfResynchronizable();
48  this->m_cipher = &cipher;
49  this->ResizeBuffers();
50  }
51 
52  void SetCipherWithIV(BlockCipher &cipher, const byte *iv, int feedbackSize = 0)
53  {
54  this->ThrowIfInvalidIV(iv);
55  this->m_cipher = &cipher;
56  this->ResizeBuffers();
57  this->SetFeedbackSize(feedbackSize);
58  if (this->IsResynchronizable())
59  this->Resynchronize(iv);
60  }
61 
62 protected:
63  CipherModeBase() : m_cipher(NULL) {}
64  inline unsigned int BlockSize() const {assert(m_register.size() > 0); return (unsigned int)m_register.size();}
65  virtual void SetFeedbackSize(unsigned int feedbackSize)
66  {
67  if (!(feedbackSize == 0 || feedbackSize == BlockSize()))
68  throw InvalidArgument("CipherModeBase: feedback size cannot be specified for this cipher mode");
69  }
70  virtual void ResizeBuffers()
71  {
72  m_register.New(m_cipher->BlockSize());
73  }
74 
75  BlockCipher *m_cipher;
76  AlignedSecByteBlock m_register;
77 };
78 
79 template <class POLICY_INTERFACE>
80 class CRYPTOPP_NO_VTABLE ModePolicyCommonTemplate : public CipherModeBase, public POLICY_INTERFACE
81 {
82  unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();}
83  void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
84 };
85 
86 template <class POLICY_INTERFACE>
87 void ModePolicyCommonTemplate<POLICY_INTERFACE>::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
88 {
89  m_cipher->SetKey(key, length, params);
90  ResizeBuffers();
91  int feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0);
92  SetFeedbackSize(feedbackSize);
93 }
94 
95 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_ModePolicy : public ModePolicyCommonTemplate<CFB_CipherAbstractPolicy>
96 {
97 public:
98  IV_Requirement IVRequirement() const {return RANDOM_IV;}
99  static const char * CRYPTOPP_API StaticAlgorithmName() {return "CFB";}
100 
101 protected:
102  unsigned int GetBytesPerIteration() const {return m_feedbackSize;}
103  byte * GetRegisterBegin() {return m_register + BlockSize() - m_feedbackSize;}
104  bool CanIterate() const {return m_feedbackSize == BlockSize();}
105  void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount);
106  void TransformRegister();
107  void CipherResynchronize(const byte *iv, size_t length);
108  void SetFeedbackSize(unsigned int feedbackSize);
109  void ResizeBuffers();
110 
111  SecByteBlock m_temp;
112  unsigned int m_feedbackSize;
113 };
114 
115 inline void CopyOrZero(void *dest, const void *src, size_t s)
116 {
117  if (src)
118  memcpy_s(dest, s, src, s);
119  else
120  memset(dest, 0, s);
121 }
122 
123 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE OFB_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy>
124 {
125 public:
126  bool CipherIsRandomAccess() const {return false;}
127  IV_Requirement IVRequirement() const {return UNIQUE_IV;}
128  static const char * CRYPTOPP_API StaticAlgorithmName() {return "OFB";}
129 
130 private:
131  unsigned int GetBytesPerIteration() const {return BlockSize();}
132  unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();}
133  void WriteKeystream(byte *keystreamBuffer, size_t iterationCount);
134  void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length);
135 };
136 
137 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CTR_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy>
138 {
139 public:
140  bool CipherIsRandomAccess() const {return true;}
141  IV_Requirement IVRequirement() const {return RANDOM_IV;}
142  static const char * CRYPTOPP_API StaticAlgorithmName() {return "CTR";}
143 
144 protected:
145  virtual void IncrementCounterBy256();
146 
147  unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();}
148  unsigned int GetBytesPerIteration() const {return BlockSize();}
149  unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();}
150  void WriteKeystream(byte *buffer, size_t iterationCount)
151  {OperateKeystream(WRITE_KEYSTREAM, buffer, NULL, iterationCount);}
152  bool CanOperateKeystream() const {return true;}
153  void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
154  void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length);
155  void SeekToIteration(lword iterationCount);
156 
157  AlignedSecByteBlock m_counterArray;
158 };
159 
160 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockOrientedCipherModeBase : public CipherModeBase
161 {
162 public:
163  void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
164  unsigned int MandatoryBlockSize() const {return BlockSize();}
165  bool IsRandomAccess() const {return false;}
166  bool IsSelfInverting() const {return false;}
167  bool IsForwardTransformation() const {return m_cipher->IsForwardTransformation();}
168  void Resynchronize(const byte *iv, int length=-1) {memcpy_s(m_register, m_register.size(), iv, ThrowIfInvalidIVLength(length));}
169 
170 protected:
171  bool RequireAlignedInput() const {return true;}
172  void ResizeBuffers()
173  {
174  CipherModeBase::ResizeBuffers();
175  m_buffer.New(BlockSize());
176  }
177 
178  SecByteBlock m_buffer;
179 };
180 
181 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ECB_OneWay : public BlockOrientedCipherModeBase
182 {
183 public:
184  void SetKey(const byte *key, size_t length, const NameValuePairs &params = g_nullNameValuePairs)
185  {m_cipher->SetKey(key, length, params); BlockOrientedCipherModeBase::ResizeBuffers();}
186  IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;}
187  unsigned int OptimalBlockSize() const {return BlockSize() * m_cipher->OptimalNumberOfParallelBlocks();}
188  void ProcessData(byte *outString, const byte *inString, size_t length);
189  static const char * CRYPTOPP_API StaticAlgorithmName() {return "ECB";}
190 };
191 
192 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_ModeBase : public BlockOrientedCipherModeBase
193 {
194 public:
195  IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;}
196  bool RequireAlignedInput() const {return false;}
197  unsigned int MinLastBlockSize() const {return 0;}
198  static const char * CRYPTOPP_API StaticAlgorithmName() {return "CBC";}
199 };
200 
201 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Encryption : public CBC_ModeBase
202 {
203 public:
204  void ProcessData(byte *outString, const byte *inString, size_t length);
205 };
206 
207 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Encryption : public CBC_Encryption
208 {
209 public:
210  void SetStolenIV(byte *iv) {m_stolenIV = iv;}
211  unsigned int MinLastBlockSize() const {return BlockSize()+1;}
212  void ProcessLastBlock(byte *outString, const byte *inString, size_t length);
213  static const char * CRYPTOPP_API StaticAlgorithmName() {return "CBC/CTS";}
214 
215 protected:
216  void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
217  {
218  CBC_Encryption::UncheckedSetKey(key, length, params);
219  m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), (byte *)NULL);
220  }
221 
222  byte *m_stolenIV;
223 };
224 
225 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Decryption : public CBC_ModeBase
226 {
227 public:
228  void ProcessData(byte *outString, const byte *inString, size_t length);
229 
230 protected:
231  void ResizeBuffers()
232  {
233  BlockOrientedCipherModeBase::ResizeBuffers();
234  m_temp.New(BlockSize());
235  }
236  AlignedSecByteBlock m_temp;
237 };
238 
239 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption
240 {
241 public:
242  unsigned int MinLastBlockSize() const {return BlockSize()+1;}
243  void ProcessLastBlock(byte *outString, const byte *inString, size_t length);
244 };
245 
246 //! _
247 template <class CIPHER, class BASE>
248 class CipherModeFinalTemplate_CipherHolder : protected ObjectHolder<CIPHER>, public AlgorithmImpl<BASE, CipherModeFinalTemplate_CipherHolder<CIPHER, BASE> >
249 {
250 public:
252  {
253  this->m_cipher = &this->m_object;
254  this->ResizeBuffers();
255  }
256  CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length)
257  {
258  this->m_cipher = &this->m_object;
259  this->SetKey(key, length);
260  }
261  CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv)
262  {
263  this->m_cipher = &this->m_object;
264  this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize())));
265  }
266  CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv, int feedbackSize)
267  {
268  this->m_cipher = &this->m_object;
269  this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))(Name::FeedbackSize(), feedbackSize));
270  }
271 
272  static std::string CRYPTOPP_API StaticAlgorithmName()
273  {return CIPHER::StaticAlgorithmName() + "/" + BASE::StaticAlgorithmName();}
274 };
275 
276 //! _
277 template <class BASE>
279 {
280 public:
283  {this->SetCipher(cipher);}
284  CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher, const byte *iv, int feedbackSize = 0)
285  {this->SetCipherWithIV(cipher, iv, feedbackSize);}
286 
287  std::string AlgorithmName() const
288  {return (this->m_cipher ? this->m_cipher->AlgorithmName() + "/" : std::string("")) + BASE::StaticAlgorithmName();}
289 };
290 
294 
295 //! CFB mode
296 template <class CIPHER>
298 {
301 };
302 
303 //! CFB mode, external cipher
305 {
308 };
309 
310 //! CFB mode FIPS variant, requiring full block plaintext according to FIPS 800-38A
311 template <class CIPHER>
313 {
316 };
317 
318 //! CFB mode FIPS variant, requiring full block plaintext according to FIPS 800-38A, external cipher
320 {
323 };
324 
326 
327 //! OFB mode
328 template <class CIPHER>
330 {
333 };
334 
335 //! OFB mode, external cipher
337 {
340 };
341 
344 
345 //! CTR mode
346 template <class CIPHER>
348 {
351 };
352 
353 //! CTR mode, external cipher
355 {
356  typedef CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, CTR_ModePolicy> > > > Encryption;
358 };
359 
360 //! ECB mode
361 template <class CIPHER>
363 {
366 };
367 
368 CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher<ECB_OneWay>;
369 
370 //! ECB mode, external cipher
372 {
373  typedef CipherModeFinalTemplate_ExternalCipher<ECB_OneWay> Encryption;
375 };
376 
377 //! CBC mode
378 template <class CIPHER>
380 {
383 };
384 
387 
388 //! CBC mode, external cipher
390 {
391  typedef CipherModeFinalTemplate_ExternalCipher<CBC_Encryption> Encryption;
392  typedef CipherModeFinalTemplate_ExternalCipher<CBC_Decryption> Decryption;
393 };
394 
395 //! CBC mode with ciphertext stealing
396 template <class CIPHER>
398 {
401 };
402 
405 
406 //! CBC mode with ciphertext stealing, external cipher
408 {
409  typedef CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Encryption> Encryption;
410  typedef CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Decryption> Decryption;
411 };
412 
413 #ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY
414 typedef CFB_Mode_ExternalCipher::Encryption CFBEncryption;
415 typedef CFB_Mode_ExternalCipher::Decryption CFBDecryption;
417 typedef CTR_Mode_ExternalCipher::Encryption CounterMode;
418 #endif
419 
420 NAMESPACE_END
421 
422 #endif