summaryrefslogtreecommitdiff
path: root/modes.h
blob: 457cf16d7ecf58577a6d3937cefb4351652bf55d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
#ifndef	CRYPTOPP_MODES_H
#define	CRYPTOPP_MODES_H

/*!	\file
*/

#include "cryptlib.h"
#include "secblock.h"
#include "misc.h"
#include "strciphr.h"
#include "argnames.h"
#include "algparam.h"

NAMESPACE_BEGIN(CryptoPP)

//!	Cipher mode	documentation. See NIST	SP 800-38A for definitions of these	modes.

/*!	Each class derived from	this one defines two types,	Encryption and Decryption, 
	both of	which implement	the	SymmetricCipher	interface.
	For	each mode there	are	two	classes, one of	which is a template	class,
	and	the	other one has a	name that ends in "_ExternalCipher".
	The	"external cipher" mode objects hold	a reference	to the underlying block	cipher,
	instead	of holding an instance of it. The reference	must be	passed in to the constructor.
	For	the	"cipher	holder"	classes, the CIPHER	template parameter should be a class
	derived	from BlockCipherDocumentation, for example DES or AES.
*/
struct CipherModeDocumentation : public	SymmetricCipherDocumentation
{
};

class CipherModeBase : public SymmetricCipher
{
public:
	unsigned int MinKeyLength()	const {return m_cipher->MinKeyLength();}
	unsigned int MaxKeyLength()	const {return m_cipher->MaxKeyLength();}
	unsigned int DefaultKeyLength()	const {return m_cipher->DefaultKeyLength();}
	unsigned int GetValidKeyLength(unsigned	int	n) const {return m_cipher->GetValidKeyLength(n);}
	bool IsValidKeyLength(unsigned int n) const	{return	m_cipher->IsValidKeyLength(n);}

	void SetKey(const byte *key, unsigned int length, const	NameValuePairs &params = g_nullNameValuePairs);

	unsigned int OptimalDataAlignment()	const {return BlockSize();}

	unsigned int IVSize() const	{return	BlockSize();}
	void GetNextIV(byte	*IV);
	virtual	IV_Requirement IVRequirement() const =0;

protected:
	inline unsigned	int	BlockSize()	const {assert(m_register.size()	> 0); return m_register.size();}
	void SetIV(const byte *iv);
	virtual	void SetFeedbackSize(unsigned int feedbackSize)
	{
		if (!(feedbackSize == 0	|| feedbackSize	== BlockSize()))
			throw InvalidArgument("CipherModeBase: feedback	size cannot	be specified for this cipher mode");
	}
	virtual	void ResizeBuffers()
	{
		m_register.New(m_cipher->BlockSize());
	}
	virtual	void UncheckedSetKey(const NameValuePairs &params, const byte *key,	unsigned int length) =0;

	BlockCipher	*m_cipher;
	SecByteBlock m_register;
};

template <class	POLICY_INTERFACE>
class ModePolicyCommonTemplate : public	CipherModeBase,	public POLICY_INTERFACE
{
	unsigned int GetAlignment()	const {return m_cipher->BlockAlignment();}
	void CipherSetKey(const	NameValuePairs &params,	const byte *key, unsigned int length)
	{
		m_cipher->SetKey(key, length, params);
		ResizeBuffers();
		int	feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0);
		SetFeedbackSize(feedbackSize);
		const byte *iv = params.GetValueWithDefault(Name::IV(),	(const byte	*)NULL);
		SetIV(iv);
	}
};

class CFB_ModePolicy : public ModePolicyCommonTemplate<CFB_CipherAbstractPolicy>
{
public:
	IV_Requirement IVRequirement() const {return RANDOM_IV;}

protected:
	unsigned int GetBytesPerIteration()	const {return m_feedbackSize;}
	byte * GetRegisterBegin() {return m_register + BlockSize() - m_feedbackSize;}
	void TransformRegister()
	{
		m_cipher->ProcessBlock(m_register, m_temp);
		memmove(m_register,	m_register+m_feedbackSize, BlockSize()-m_feedbackSize);
		memcpy(m_register+BlockSize()-m_feedbackSize, m_temp, m_feedbackSize);
	}
	void CipherResynchronize(const byte	*iv)
	{
		memcpy(m_register, iv, BlockSize());
		TransformRegister();
	}
	void SetFeedbackSize(unsigned int feedbackSize)
	{
		if (feedbackSize > BlockSize())
			throw InvalidArgument("CFB_Mode: invalid feedback size");
		m_feedbackSize = feedbackSize ?	feedbackSize : BlockSize();
	}
	void ResizeBuffers()
	{
		CipherModeBase::ResizeBuffers();
		m_temp.New(BlockSize());
	}

	SecByteBlock m_temp;
	unsigned int m_feedbackSize;
};

class OFB_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy>
{
	unsigned int GetBytesPerIteration()	const {return BlockSize();}
	unsigned int GetIterationsToBuffer() const {return 1;}
	void WriteKeystream(byte *keystreamBuffer, unsigned	int	iterationCount)
	{
		assert(iterationCount == 1);
		m_cipher->ProcessBlock(keystreamBuffer);
	}
	void CipherResynchronize(byte *keystreamBuffer,	const byte *iv)
	{
		memcpy(keystreamBuffer,	iv,	BlockSize());
	}
	bool IsRandomAccess() const	{return	false;}
	IV_Requirement IVRequirement() const {return STRUCTURED_IV;}
};

class CTR_ModePolicy : public ModePolicyCommonTemplate<AdditiveCipherAbstractPolicy>
{
	unsigned int GetBytesPerIteration()	const {return BlockSize();}
	unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();}
	void WriteKeystream(byte *buffer, unsigned int iterationCount)
		{OperateKeystream(WRITE_KEYSTREAM, buffer, NULL, iterationCount);}
	bool CanOperateKeystream() const {return true;}
	void OperateKeystream(KeystreamOperation operation,	byte *output, const	byte *input, unsigned int iterationCount);
	void CipherResynchronize(byte *keystreamBuffer,	const byte *iv);
	bool IsRandomAccess() const	{return	true;}
	void SeekToIteration(dword iterationCount);
	IV_Requirement IVRequirement() const {return STRUCTURED_IV;}

	inline void	ProcessMultipleBlocks(byte *output,	const byte *input, unsigned	int	n);

	SecByteBlock m_counterArray;
};

class BlockOrientedCipherModeBase :	public CipherModeBase
{
public:
	void UncheckedSetKey(const NameValuePairs &params, const byte *key,	unsigned int length);
	unsigned int MandatoryBlockSize() const	{return	BlockSize();}
	bool IsRandomAccess() const	{return	false;}
	bool IsSelfInverting() const {return false;}
	bool IsForwardTransformation() const {return m_cipher->IsForwardTransformation();}
	void Resynchronize(const byte *iv) {memcpy(m_register, iv, BlockSize());}
	void ProcessData(byte *outString, const	byte *inString,	unsigned int length);

protected:
	bool RequireAlignedInput() const {return true;}
	virtual	void ProcessBlocks(byte	*outString,	const byte *inString, unsigned int numberOfBlocks) =0;
	void ResizeBuffers()
	{
		CipherModeBase::ResizeBuffers();
		m_buffer.New(BlockSize());
	}

	SecByteBlock m_buffer;
};

class ECB_OneWay : public BlockOrientedCipherModeBase
{
public:
	IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;}
	unsigned int OptimalBlockSize()	const {return BlockSize() *	m_cipher->OptimalNumberOfParallelBlocks();}
	void ProcessBlocks(byte	*outString,	const byte *inString, unsigned int numberOfBlocks)
		{m_cipher->ProcessAndXorMultipleBlocks(inString, NULL, outString, numberOfBlocks);}
};

class CBC_ModeBase : public	BlockOrientedCipherModeBase
{
public:
	IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;}
	bool RequireAlignedInput() const {return false;}
	unsigned int MinLastBlockSize()	const {return 0;}
};

class CBC_Encryption : public CBC_ModeBase
{
public:
	void ProcessBlocks(byte	*outString,	const byte *inString, unsigned int numberOfBlocks);
};

class CBC_CTS_Encryption : public CBC_Encryption
{
public:
	void SetStolenIV(byte *iv) {m_stolenIV = iv;}
	unsigned int MinLastBlockSize()	const {return BlockSize()+1;}
	void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length);

protected:
	void UncheckedSetKey(const NameValuePairs &params, const byte *key,	unsigned int length)
	{
		CBC_Encryption::UncheckedSetKey(params,	key, length);
		m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), (byte	*)NULL);
	}

	byte *m_stolenIV;
};

class CBC_Decryption : public CBC_ModeBase
{
public:
	void ProcessBlocks(byte	*outString,	const byte *inString, unsigned int numberOfBlocks);
	
protected:
	void ResizeBuffers()
	{
		BlockOrientedCipherModeBase::ResizeBuffers();
		m_temp.New(BlockSize());
	}
	SecByteBlock m_temp;
};

class CBC_CTS_Decryption : public CBC_Decryption
{
public:
	unsigned int MinLastBlockSize()	const {return BlockSize()+1;}
	void ProcessLastBlock(byte *outString, const byte *inString, unsigned int length);
};

//!	.
template <class	CIPHER,	class BASE>
class CipherModeFinalTemplate_CipherHolder : public	ObjectHolder<CIPHER>, public BASE
{
public:
	CipherModeFinalTemplate_CipherHolder()
	{
		m_cipher = &m_object;
		ResizeBuffers();
	}
	CipherModeFinalTemplate_CipherHolder(const byte	*key, unsigned int length)
	{
		m_cipher = &m_object;
		SetKey(key,	length);
	}
	CipherModeFinalTemplate_CipherHolder(const byte	*key, unsigned int length, const byte *iv, int feedbackSize	= 0)
	{
		m_cipher = &m_object;
		SetKey(key,	length,	MakeParameters("IV", iv)("FeedbackSize", feedbackSize));
	}
};

//!	.
template <class	BASE>
class CipherModeFinalTemplate_ExternalCipher : public BASE
{
public:
	CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher,	const byte *iv = NULL, int feedbackSize	= 0)
	{
		m_cipher = &cipher;
		ResizeBuffers();
		SetFeedbackSize(feedbackSize);
		SetIV(iv);
	}
};

//!	CFB	mode
template <class	CIPHER>
struct CFB_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy,	CFB_ModePolicy>	> >	> Encryption;
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy,	CFB_ModePolicy>	> >	> Decryption;
};

//!	CFB	mode, external cipher
struct CFB_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, CFB_EncryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Encryption;
	typedef	CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, CFB_DecryptionTemplate<AbstractPolicyHolder<CFB_CipherAbstractPolicy, CFB_ModePolicy> > > > Decryption;
};

//!	OFB	mode
template <class	CIPHER>
struct OFB_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy,	OFB_ModePolicy>	> >	> Encryption;
	typedef	Encryption Decryption;
};

//!	OFB	mode, external cipher
struct OFB_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, OFB_ModePolicy> > > > Encryption;
	typedef	Encryption Decryption;
};

//!	CTR	mode
template <class	CIPHER>
struct CTR_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy,	CTR_ModePolicy>	> >	> Encryption;
	typedef	Encryption Decryption;
};

//!	CTR	mode, external cipher
struct CTR_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<ConcretePolicyHolder<Empty, AdditiveCipherTemplate<AbstractPolicyHolder<AdditiveCipherAbstractPolicy, CTR_ModePolicy> > > > Encryption;
	typedef	Encryption Decryption;
};

//!	ECB	mode
template <class	CIPHER>
struct ECB_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, ECB_OneWay> Encryption;
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, ECB_OneWay> Decryption;
};

//!	ECB	mode, external cipher
struct ECB_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<ECB_OneWay> Encryption;
	typedef	Encryption Decryption;
};

//!	CBC	mode
template <class	CIPHER>
struct CBC_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, CBC_Encryption> Encryption;
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, CBC_Decryption> Decryption;
};

//!	CBC	mode, external cipher
struct CBC_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<CBC_Encryption> Encryption;
	typedef	CipherModeFinalTemplate_ExternalCipher<CBC_Decryption> Decryption;
};

//!	CBC	mode with ciphertext stealing
template <class	CIPHER>
struct CBC_CTS_Mode	: public CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Encryption, CBC_CTS_Encryption> Encryption;
	typedef	CipherModeFinalTemplate_CipherHolder<CPP_TYPENAME CIPHER::Decryption, CBC_CTS_Decryption> Decryption;
};

//!	CBC	mode with ciphertext stealing, external	cipher
struct CBC_CTS_Mode_ExternalCipher : public	CipherModeDocumentation
{
	typedef	CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Encryption> Encryption;
	typedef	CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Decryption> Decryption;
};

#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY
typedef	CFB_Mode_ExternalCipher::Encryption	CFBEncryption;
typedef	CFB_Mode_ExternalCipher::Decryption	CFBDecryption;
typedef	OFB_Mode_ExternalCipher::Encryption	OFB;
typedef	CTR_Mode_ExternalCipher::Encryption	CounterMode;
#endif

NAMESPACE_END

#endif