~zooko/cryptopp/trunk

23 by weidai
fix whitespace problems
1
// filters.cpp - written and placed in the public domain by Wei Dai
1 by weidai
Initial revision
2
3
#include "pch.h"
75 by weidai
create DLL version, fix GetNextIV() bug in CTR and OFB modes
4
5
#ifndef CRYPTOPP_IMPORTS
6
1 by weidai
Initial revision
7
#include "filters.h"
8
#include "mqueue.h"
9
#include "fltrimpl.h"
10
#include "argnames.h"
11
#include <memory>
12
#include <functional>
13
14
NAMESPACE_BEGIN(CryptoPP)
15
16
Filter::Filter(BufferedTransformation *attachment)
23 by weidai
fix whitespace problems
17
	: m_attachment(attachment), m_continueAt(0)
1 by weidai
Initial revision
18
{
19
}
20
23 by weidai
fix whitespace problems
21
BufferedTransformation * Filter::NewDefaultAttachment() const
1 by weidai
Initial revision
22
{
23
	return new MessageQueue;
24
}
25
26
BufferedTransformation * Filter::AttachedTransformation()
27
{
28
	if (m_attachment.get() == NULL)
29
		m_attachment.reset(NewDefaultAttachment());
30
	return m_attachment.get();
31
}
32
33
const BufferedTransformation *Filter::AttachedTransformation() const
34
{
35
	if (m_attachment.get() == NULL)
36
		const_cast<Filter *>(this)->m_attachment.reset(NewDefaultAttachment());
37
	return m_attachment.get();
38
}
39
40
void Filter::Detach(BufferedTransformation *newOut)
41
{
42
	m_attachment.reset(newOut);
43
}
44
45
void Filter::Insert(Filter *filter)
46
{
47
	filter->m_attachment.reset(m_attachment.release());
48
	m_attachment.reset(filter);
49
}
50
23 by weidai
fix whitespace problems
51
unsigned int Filter::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const
1 by weidai
Initial revision
52
{
53
	return AttachedTransformation()->CopyRangeTo2(target, begin, end, channel, blocking);
54
}
55
23 by weidai
fix whitespace problems
56
unsigned int Filter::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking)
1 by weidai
Initial revision
57
{
23 by weidai
fix whitespace problems
58
	return AttachedTransformation()->TransferTo2(target, transferBytes, channel, blocking);
1 by weidai
Initial revision
59
}
60
61
void Filter::Initialize(const NameValuePairs &parameters, int propagation)
62
{
63
	m_continueAt = 0;
64
	IsolatedInitialize(parameters);
23 by weidai
fix whitespace problems
65
	PropagateInitialize(parameters, propagation);
1 by weidai
Initial revision
66
}
67
23 by weidai
fix whitespace problems
68
bool Filter::Flush(bool hardFlush, int propagation, bool blocking)
1 by weidai
Initial revision
69
{
70
	switch (m_continueAt)
71
	{
72
	case 0:
73
		if (IsolatedFlush(hardFlush, blocking))
74
			return true;
75
	case 1:
76
		if (OutputFlush(1, hardFlush, propagation, blocking))
77
			return true;
78
	}
79
	return false;
80
}
81
23 by weidai
fix whitespace problems
82
bool Filter::MessageSeriesEnd(int propagation, bool blocking)
1 by weidai
Initial revision
83
{
84
	switch (m_continueAt)
85
	{
86
	case 0:
87
		if (IsolatedMessageSeriesEnd(blocking))
88
			return true;
89
	case 1:
23 by weidai
fix whitespace problems
90
		if (ShouldPropagateMessageSeriesEnd() && OutputMessageSeriesEnd(1, propagation, blocking))
1 by weidai
Initial revision
91
			return true;
92
	}
93
	return false;
94
}
95
86 by weidai
added support for using encoding parameters and key derivation parameters
96
void Filter::PropagateInitialize(const NameValuePairs &parameters, int propagation)
1 by weidai
Initial revision
97
{
98
	if (propagation)
86 by weidai
added support for using encoding parameters and key derivation parameters
99
		AttachedTransformation()->Initialize(parameters, propagation-1);
1 by weidai
Initial revision
100
}
101
64 by weidai
sync with private branch
102
unsigned int Filter::OutputModifiable(int outputSite, byte *inString, unsigned int length, int messageEnd, bool blocking, const std::string &channel)
103
{
104
	if (messageEnd)
105
		messageEnd--;
106
	unsigned int result = AttachedTransformation()->PutModifiable2(inString, length, messageEnd, blocking);
107
	m_continueAt = result ? outputSite : 0;
108
	return result;
109
}
110
23 by weidai
fix whitespace problems
111
unsigned int Filter::Output(int outputSite, const byte *inString, unsigned int length, int messageEnd, bool blocking, const std::string &channel)
1 by weidai
Initial revision
112
{
113
	if (messageEnd)
114
		messageEnd--;
23 by weidai
fix whitespace problems
115
	unsigned int result = AttachedTransformation()->Put2(inString, length, messageEnd, blocking);
116
	m_continueAt = result ? outputSite : 0;
1 by weidai
Initial revision
117
	return result;
118
}
119
120
bool Filter::OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel)
121
{
23 by weidai
fix whitespace problems
122
	if (propagation && AttachedTransformation()->ChannelFlush(channel, hardFlush, propagation-1, blocking))
1 by weidai
Initial revision
123
	{
124
		m_continueAt = outputSite;
125
		return true;
126
	}
127
	m_continueAt = 0;
128
	return false;
129
}
130
23 by weidai
fix whitespace problems
131
bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel)
1 by weidai
Initial revision
132
{
23 by weidai
fix whitespace problems
133
	if (propagation && AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation-1, blocking))
1 by weidai
Initial revision
134
	{
135
		m_continueAt = outputSite;
136
		return true;
137
	}
138
	m_continueAt = 0;
139
	return false;
140
}
141
142
// *************************************************************
143
23 by weidai
fix whitespace problems
144
unsigned int MeterFilter::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking)
1 by weidai
Initial revision
145
{
31 by weidai
fix bug in MeterFilter
146
	if (m_transparent)
1 by weidai
Initial revision
147
	{
31 by weidai
fix bug in MeterFilter
148
		FILTER_BEGIN;
149
		m_currentMessageBytes += length;
150
		m_totalBytes += length;
151
152
		if (messageEnd)
153
		{
154
			m_currentMessageBytes = 0;
155
			m_currentSeriesMessages++;
156
			m_totalMessages++;
157
		}
75 by weidai
create DLL version, fix GetNextIV() bug in CTR and OFB modes
158
31 by weidai
fix bug in MeterFilter
159
		FILTER_OUTPUT(1, begin, length, messageEnd);
160
		FILTER_END_NO_MESSAGE_END;
1 by weidai
Initial revision
161
	}
31 by weidai
fix bug in MeterFilter
162
	return 0;
1 by weidai
Initial revision
163
}
164
64 by weidai
sync with private branch
165
unsigned int MeterFilter::PutModifiable2(byte *begin, unsigned int length, int messageEnd, bool blocking)
166
{
167
	if (m_transparent)
168
	{
169
		FILTER_BEGIN;
170
		m_currentMessageBytes += length;
171
		m_totalBytes += length;
172
173
		if (messageEnd)
174
		{
175
			m_currentMessageBytes = 0;
176
			m_currentSeriesMessages++;
177
			m_totalMessages++;
178
		}
179
		
180
		FILTER_OUTPUT_MODIFIABLE(1, begin, length, messageEnd);
181
		FILTER_END_NO_MESSAGE_END;
182
	}
183
	return 0;
184
}
185
23 by weidai
fix whitespace problems
186
bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking)
1 by weidai
Initial revision
187
{
23 by weidai
fix whitespace problems
188
	m_currentMessageBytes = 0;
189
	m_currentSeriesMessages = 0;
1 by weidai
Initial revision
190
	m_totalMessageSeries++;
191
	return false;
192
}
193
194
// *************************************************************
195
196
void FilterWithBufferedInput::BlockQueue::ResetQueue(unsigned int blockSize, unsigned int maxBlocks)
197
{
198
	m_buffer.New(blockSize * maxBlocks);
23 by weidai
fix whitespace problems
199
	m_blockSize = blockSize;
200
	m_maxBlocks = maxBlocks;
1 by weidai
Initial revision
201
	m_size = 0;
23 by weidai
fix whitespace problems
202
	m_begin = m_buffer;
1 by weidai
Initial revision
203
}
204
205
byte *FilterWithBufferedInput::BlockQueue::GetBlock()
206
{
207
	if (m_size >= m_blockSize)
208
	{
23 by weidai
fix whitespace problems
209
		byte *ptr = m_begin;
1 by weidai
Initial revision
210
		if ((m_begin+=m_blockSize) == m_buffer.end())
23 by weidai
fix whitespace problems
211
			m_begin = m_buffer;
1 by weidai
Initial revision
212
		m_size -= m_blockSize;
213
		return ptr;
214
	}
215
	else
216
		return NULL;
217
}
218
219
byte *FilterWithBufferedInput::BlockQueue::GetContigousBlocks(unsigned int &numberOfBytes)
220
{
23 by weidai
fix whitespace problems
221
	numberOfBytes = STDMIN(numberOfBytes, STDMIN((unsigned int)(m_buffer.end()-m_begin), m_size));
222
	byte *ptr = m_begin;
223
	m_begin += numberOfBytes;
1 by weidai
Initial revision
224
	m_size -= numberOfBytes;
23 by weidai
fix whitespace problems
225
	if (m_size == 0 || m_begin == m_buffer.end())
226
		m_begin = m_buffer;
1 by weidai
Initial revision
227
	return ptr;
228
}
229
230
unsigned int FilterWithBufferedInput::BlockQueue::GetAll(byte *outString)
231
{
23 by weidai
fix whitespace problems
232
	unsigned int size = m_size;
1 by weidai
Initial revision
233
	unsigned int numberOfBytes = m_maxBlocks*m_blockSize;
23 by weidai
fix whitespace problems
234
	const byte *ptr = GetContigousBlocks(numberOfBytes);
1 by weidai
Initial revision
235
	memcpy(outString, ptr, numberOfBytes);
23 by weidai
fix whitespace problems
236
	memcpy(outString+numberOfBytes, m_begin, m_size);
1 by weidai
Initial revision
237
	m_size = 0;
238
	return size;
239
}
240
23 by weidai
fix whitespace problems
241
void FilterWithBufferedInput::BlockQueue::Put(const byte *inString, unsigned int length)
1 by weidai
Initial revision
242
{
23 by weidai
fix whitespace problems
243
	assert(m_size + length <= m_buffer.size());
244
	byte *end = (m_size < (unsigned int)(m_buffer.end()-m_begin)) ? m_begin + m_size : m_begin + m_size - m_buffer.size();
245
	unsigned int len = STDMIN(length, (unsigned int)(m_buffer.end()-end));
246
	memcpy(end, inString, len);
247
	if (len < length)
1 by weidai
Initial revision
248
		memcpy(m_buffer, inString+len, length-len);
249
	m_size += length;
250
}
251
23 by weidai
fix whitespace problems
252
FilterWithBufferedInput::FilterWithBufferedInput(BufferedTransformation *attachment)
1 by weidai
Initial revision
253
	: Filter(attachment)
254
{
255
}
256
23 by weidai
fix whitespace problems
257
FilterWithBufferedInput::FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation *attachment)
1 by weidai
Initial revision
258
	: Filter(attachment), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize)
259
	, m_firstInputDone(false)
260
{
23 by weidai
fix whitespace problems
261
	if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0)
262
		throw InvalidArgument("FilterWithBufferedInput: invalid buffer size");
1 by weidai
Initial revision
263
264
	m_queue.ResetQueue(1, m_firstSize);
265
}
266
267
void FilterWithBufferedInput::IsolatedInitialize(const NameValuePairs &parameters)
268
{
23 by weidai
fix whitespace problems
269
	InitializeDerivedAndReturnNewSizes(parameters, m_firstSize, m_blockSize, m_lastSize);
270
	if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0)
271
		throw InvalidArgument("FilterWithBufferedInput: invalid buffer size");
1 by weidai
Initial revision
272
	m_queue.ResetQueue(1, m_firstSize);
273
	m_firstInputDone = false;
274
}
275
23 by weidai
fix whitespace problems
276
bool FilterWithBufferedInput::IsolatedFlush(bool hardFlush, bool blocking)
1 by weidai
Initial revision
277
{
278
	if (!blocking)
279
		throw BlockingInputOnly("FilterWithBufferedInput");
280
	
281
	if (hardFlush)
282
		ForceNextPut();
283
	FlushDerived();
284
	
285
	return false;
286
}
287
288
unsigned int FilterWithBufferedInput::PutMaybeModifiable(byte *inString, unsigned int length, int messageEnd, bool blocking, bool modifiable)
289
{
290
	if (!blocking)
291
		throw BlockingInputOnly("FilterWithBufferedInput");
292
293
	if (length != 0)
294
	{
295
		unsigned int newLength = m_queue.CurrentSize() + length;
296
297
		if (!m_firstInputDone && newLength >= m_firstSize)
298
		{
299
			unsigned int len = m_firstSize - m_queue.CurrentSize();
300
			m_queue.Put(inString, len);
301
			FirstPut(m_queue.GetContigousBlocks(m_firstSize));
23 by weidai
fix whitespace problems
302
			assert(m_queue.CurrentSize() == 0);
303
			m_queue.ResetQueue(m_blockSize, (2*m_blockSize+m_lastSize-2)/m_blockSize);
1 by weidai
Initial revision
304
23 by weidai
fix whitespace problems
305
			inString += len;
1 by weidai
Initial revision
306
			newLength -= m_firstSize;
307
			m_firstInputDone = true;
308
		}
309
310
		if (m_firstInputDone)
311
		{
23 by weidai
fix whitespace problems
312
			if (m_blockSize == 1)
1 by weidai
Initial revision
313
			{
314
				while (newLength > m_lastSize && m_queue.CurrentSize() > 0)
315
				{
316
					unsigned int len = newLength - m_lastSize;
23 by weidai
fix whitespace problems
317
					byte *ptr = m_queue.GetContigousBlocks(len);
1 by weidai
Initial revision
318
					NextPutModifiable(ptr, len);
319
					newLength -= len;
320
				}
321
23 by weidai
fix whitespace problems
322
				if (newLength > m_lastSize)
1 by weidai
Initial revision
323
				{
324
					unsigned int len = newLength - m_lastSize;
325
					NextPutMaybeModifiable(inString, len, modifiable);
23 by weidai
fix whitespace problems
326
					inString += len;
1 by weidai
Initial revision
327
					newLength -= len;
328
				}
329
			}
330
			else
331
			{
23 by weidai
fix whitespace problems
332
				while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize)
1 by weidai
Initial revision
333
				{
334
					NextPutModifiable(m_queue.GetBlock(), m_blockSize);
335
					newLength -= m_blockSize;
336
				}
337
338
				if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0)
339
				{
340
					assert(m_queue.CurrentSize() < m_blockSize);
341
					unsigned int len = m_blockSize - m_queue.CurrentSize();
342
					m_queue.Put(inString, len);
23 by weidai
fix whitespace problems
343
					inString += len;
1 by weidai
Initial revision
344
					NextPutModifiable(m_queue.GetBlock(), m_blockSize);
345
					newLength -= m_blockSize;
346
				}
347
348
				if (newLength >= m_blockSize + m_lastSize)
349
				{
350
					unsigned int len = RoundDownToMultipleOf(newLength - m_lastSize, m_blockSize);
351
					NextPutMaybeModifiable(inString, len, modifiable);
23 by weidai
fix whitespace problems
352
					inString += len;
1 by weidai
Initial revision
353
					newLength -= len;
354
				}
355
			}
356
		}
357
23 by weidai
fix whitespace problems
358
		m_queue.Put(inString, newLength - m_queue.CurrentSize());
1 by weidai
Initial revision
359
	}
360
361
	if (messageEnd)
362
	{
363
		if (!m_firstInputDone && m_firstSize==0)
364
			FirstPut(NULL);
365
366
		SecByteBlock temp(m_queue.CurrentSize());
367
		m_queue.GetAll(temp);
368
		LastPut(temp, temp.size());
369
370
		m_firstInputDone = false;
371
		m_queue.ResetQueue(1, m_firstSize);
372
23 by weidai
fix whitespace problems
373
		Output(1, NULL, 0, messageEnd, blocking);
1 by weidai
Initial revision
374
	}
375
	return 0;
376
}
377
378
void FilterWithBufferedInput::ForceNextPut()
379
{
380
	if (!m_firstInputDone)
381
		return;
382
	
23 by weidai
fix whitespace problems
383
	if (m_blockSize > 1)
1 by weidai
Initial revision
384
	{
23 by weidai
fix whitespace problems
385
		while (m_queue.CurrentSize() >= m_blockSize)
1 by weidai
Initial revision
386
			NextPutModifiable(m_queue.GetBlock(), m_blockSize);
387
	}
388
	else
389
	{
390
		unsigned int len;
23 by weidai
fix whitespace problems
391
		while ((len = m_queue.CurrentSize()) > 0)
1 by weidai
Initial revision
392
			NextPutModifiable(m_queue.GetContigousBlocks(len), len);
393
	}
394
}
395
23 by weidai
fix whitespace problems
396
void FilterWithBufferedInput::NextPutMultiple(const byte *inString, unsigned int length)
1 by weidai
Initial revision
397
{
398
	assert(m_blockSize > 1);	// m_blockSize = 1 should always override this function
23 by weidai
fix whitespace problems
399
	while (length > 0)
1 by weidai
Initial revision
400
	{
401
		assert(length >= m_blockSize);
402
		NextPutSingle(inString);
23 by weidai
fix whitespace problems
403
		inString += m_blockSize;
1 by weidai
Initial revision
404
		length -= m_blockSize;
405
	}
406
}
407
408
// *************************************************************
409
86 by weidai
added support for using encoding parameters and key derivation parameters
410
void Redirector::Initialize(const NameValuePairs &parameters, int propagation)
1 by weidai
Initial revision
411
{
86 by weidai
added support for using encoding parameters and key derivation parameters
412
	m_target = parameters.GetValueWithDefault("RedirectionTargetPointer", (BufferedTransformation*)NULL);
413
	m_behavior = parameters.GetIntValueWithDefault("RedirectionBehavior", PASS_EVERYTHING);
1 by weidai
Initial revision
414
43 by weidai
fix bug in Grouper
415
	if (m_target && GetPassSignals())
86 by weidai
added support for using encoding parameters and key derivation parameters
416
		m_target->Initialize(parameters, propagation);
1 by weidai
Initial revision
417
}
418
419
// *************************************************************
420
23 by weidai
fix whitespace problems
421
ProxyFilter::ProxyFilter(BufferedTransformation *filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation *attachment)
422
	: FilterWithBufferedInput(firstSize, 1, lastSize, attachment), m_filter(filter)
1 by weidai
Initial revision
423
{
424
	if (m_filter.get())
3 by weidai
bug fixes
425
		m_filter->Attach(new OutputProxy(*this, false));
1 by weidai
Initial revision
426
}
427
23 by weidai
fix whitespace problems
428
bool ProxyFilter::IsolatedFlush(bool hardFlush, bool blocking)
1 by weidai
Initial revision
429
{
3 by weidai
bug fixes
430
	return m_filter.get() ? m_filter->Flush(hardFlush, -1, blocking) : false;
1 by weidai
Initial revision
431
}
432
433
void ProxyFilter::SetFilter(Filter *filter)
434
{
435
	m_filter.reset(filter);
436
	if (filter)
437
	{
23 by weidai
fix whitespace problems
438
		OutputProxy *proxy;
3 by weidai
bug fixes
439
		std::auto_ptr<OutputProxy> temp(proxy = new OutputProxy(*this, false));
440
		m_filter->TransferAllTo(*proxy);
1 by weidai
Initial revision
441
		m_filter->Attach(temp.release());
442
	}
443
}
444
64 by weidai
sync with private branch
445
void ProxyFilter::NextPutMultiple(const byte *s, unsigned int len)
1 by weidai
Initial revision
446
{
447
	if (m_filter.get())
448
		m_filter->Put(s, len);
449
}
450
64 by weidai
sync with private branch
451
void ProxyFilter::NextPutModifiable(byte *s, unsigned int len)
452
{
453
	if (m_filter.get())
454
		m_filter->PutModifiable(s, len);
455
}
456
1 by weidai
Initial revision
457
// *************************************************************
458
23 by weidai
fix whitespace problems
459
unsigned int ArraySink::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking)
1 by weidai
Initial revision
460
{
23 by weidai
fix whitespace problems
461
	memcpy(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total)));
462
	m_total += length;
1 by weidai
Initial revision
463
	return 0;
464
}
465
466
byte * ArraySink::CreatePutSpace(unsigned int &size)
467
{
23 by weidai
fix whitespace problems
468
	size = m_size - m_total;
1 by weidai
Initial revision
469
	return m_buf + m_total;
470
}
471
23 by weidai
fix whitespace problems
472
void ArraySink::IsolatedInitialize(const NameValuePairs &parameters)
1 by weidai
Initial revision
473
{
474
	ByteArrayParameter array;
475
	if (!parameters.GetValue(Name::OutputBuffer(), array))
476
		throw InvalidArgument("ArraySink: missing OutputBuffer argument");
23 by weidai
fix whitespace problems
477
	m_buf = array.begin();
1 by weidai
Initial revision
478
	m_size = array.size();
23 by weidai
fix whitespace problems
479
	m_total = 0;
1 by weidai
Initial revision
480
}
481
23 by weidai
fix whitespace problems
482
unsigned int ArrayXorSink::Put2(const byte *begin, unsigned int length, int messageEnd, bool blocking)
1 by weidai
Initial revision
483
{
23 by weidai
fix whitespace problems
484
	xorbuf(m_buf+m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total)));
485
	m_total += length;
1 by weidai
Initial revision
486
	return 0;
487
}
488
489
// *************************************************************
490
23 by weidai
fix whitespace problems
491
unsigned int StreamTransformationFilter::LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding)
1 by weidai
Initial revision
492
{
493
	if (c.MinLastBlockSize() > 0)
494
		return c.MinLastBlockSize();
23 by weidai
fix whitespace problems
495
	else if (c.MandatoryBlockSize() > 1 && !c.IsForwardTransformation() && padding != NO_PADDING && padding != ZEROS_PADDING)
1 by weidai
Initial revision
496
		return c.MandatoryBlockSize();
497
	else
498
		return 0;
499
}
500
23 by weidai
fix whitespace problems
501
StreamTransformationFilter::StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding)
502
   : FilterWithBufferedInput(0, c.MandatoryBlockSize(), LastBlockSize(c, padding), attachment)
1 by weidai
Initial revision
503
	, m_cipher(c)
504
{
23 by weidai
fix whitespace problems
505
	assert(c.MinLastBlockSize() == 0 || c.MinLastBlockSize() > c.MandatoryBlockSize());
506
507
	bool isBlockCipher = (c.MandatoryBlockSize() > 1 && c.MinLastBlockSize() == 0);
508
509
	if (padding == DEFAULT_PADDING)
1 by weidai
Initial revision
510
	{
511
		if (isBlockCipher)
23 by weidai
fix whitespace problems
512
			m_padding = PKCS_PADDING;
1 by weidai
Initial revision
513
		else
23 by weidai
fix whitespace problems
514
			m_padding = NO_PADDING;
1 by weidai
Initial revision
515
	}
516
	else
23 by weidai
fix whitespace problems
517
		m_padding = padding;
1 by weidai
Initial revision
518
23 by weidai
fix whitespace problems
519
	if (!isBlockCipher && (m_padding == PKCS_PADDING || m_padding == ONE_AND_ZEROS_PADDING))
520
		throw InvalidArgument("StreamTransformationFilter: PKCS_PADDING and ONE_AND_ZEROS_PADDING cannot be used with " + c.AlgorithmName());
1 by weidai
Initial revision
521
}
522
23 by weidai
fix whitespace problems
523
void StreamTransformationFilter::FirstPut(const byte *inString)
1 by weidai
Initial revision
524
{
23 by weidai
fix whitespace problems
525
	m_optimalBufferSize = m_cipher.OptimalBlockSize();
526
	m_optimalBufferSize = STDMAX(m_optimalBufferSize, RoundDownToMultipleOf(4096U, m_optimalBufferSize));
1 by weidai
Initial revision
527
}
528
23 by weidai
fix whitespace problems
529
void StreamTransformationFilter::NextPutMultiple(const byte *inString, unsigned int length)
1 by weidai
Initial revision
530
{
531
	if (!length)
532
		return;
533
534
	unsigned int s = m_cipher.MandatoryBlockSize();
535
536
	do
537
	{
538
		unsigned int len = m_optimalBufferSize;
23 by weidai
fix whitespace problems
539
		byte *space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, s, length, len);
540
		if (len < length)
1 by weidai
Initial revision
541
		{
23 by weidai
fix whitespace problems
542
			if (len == m_optimalBufferSize)
543
				len -= m_cipher.GetOptimalBlockSizeUsed();
544
			len = RoundDownToMultipleOf(len, s);
1 by weidai
Initial revision
545
		}
546
		else
23 by weidai
fix whitespace problems
547
			len = length;
548
		m_cipher.ProcessString(space, inString, len);
1 by weidai
Initial revision
549
		AttachedTransformation()->PutModifiable(space, len);
23 by weidai
fix whitespace problems
550
		inString += len;
1 by weidai
Initial revision
551
		length -= len;
552
	}
23 by weidai
fix whitespace problems
553
	while (length > 0);
1 by weidai
Initial revision
554
}
555
23 by weidai
fix whitespace problems
556
void StreamTransformationFilter::NextPutModifiable(byte *inString, unsigned int length)
1 by weidai
Initial revision
557
{
558
	m_cipher.ProcessString(inString, length);
559
	AttachedTransformation()->PutModifiable(inString, length);
560
}
561
23 by weidai
fix whitespace problems
562
void StreamTransformationFilter::LastPut(const byte *inString, unsigned int length)
1 by weidai
Initial revision
563
{
23 by weidai
fix whitespace problems
564
	byte *space = NULL;
1 by weidai
Initial revision
565
	
566
	switch (m_padding)
567
	{
568
	case NO_PADDING:
569
	case ZEROS_PADDING:
570
		if (length > 0)
571
		{
23 by weidai
fix whitespace problems
572
			unsigned int minLastBlockSize = m_cipher.MinLastBlockSize();
1 by weidai
Initial revision
573
			bool isForwardTransformation = m_cipher.IsForwardTransformation();
574
23 by weidai
fix whitespace problems
575
			if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize))
1 by weidai
Initial revision
576
			{
577
				// do padding
578
				unsigned int blockSize = STDMAX(minLastBlockSize, m_cipher.MandatoryBlockSize());
23 by weidai
fix whitespace problems
579
				space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, blockSize);
580
				memcpy(space, inString, length);
581
				memset(space + length, 0, blockSize - length);
582
				m_cipher.ProcessLastBlock(space, space, blockSize);
1 by weidai
Initial revision
583
				AttachedTransformation()->Put(space, blockSize);
584
			}
585
			else
586
			{
23 by weidai
fix whitespace problems
587
				if (minLastBlockSize == 0)
1 by weidai
Initial revision
588
				{
589
					if (isForwardTransformation)
23 by weidai
fix whitespace problems
590
						throw InvalidDataFormat("StreamTransformationFilter: plaintext length is not a multiple of block size and NO_PADDING is specified");
1 by weidai
Initial revision
591
					else
23 by weidai
fix whitespace problems
592
						throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
1 by weidai
Initial revision
593
				}
594
23 by weidai
fix whitespace problems
595
				space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, length, m_optimalBufferSize);
1 by weidai
Initial revision
596
				m_cipher.ProcessLastBlock(space, inString, length);
597
				AttachedTransformation()->Put(space, length);
598
			}
599
		}
600
		break;
601
602
	case PKCS_PADDING:
603
	case ONE_AND_ZEROS_PADDING:
604
		unsigned int s;
23 by weidai
fix whitespace problems
605
		s = m_cipher.MandatoryBlockSize();
1 by weidai
Initial revision
606
		assert(s > 1);
23 by weidai
fix whitespace problems
607
		space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, s, m_optimalBufferSize);
1 by weidai
Initial revision
608
		if (m_cipher.IsForwardTransformation())
609
		{
23 by weidai
fix whitespace problems
610
			assert(length < s);
611
			memcpy(space, inString, length);
1 by weidai
Initial revision
612
			if (m_padding == PKCS_PADDING)
613
			{
614
				assert(s < 256);
615
				byte pad = s-length;
616
				memset(space+length, pad, s-length);
617
			}
618
			else
619
			{
134 by weidai
fix ONE_AND_ZEROS_PADDING
620
				space[length] = 0x80;
1 by weidai
Initial revision
621
				memset(space+length+1, 0, s-length-1);
622
			}
23 by weidai
fix whitespace problems
623
			m_cipher.ProcessData(space, space, s);
1 by weidai
Initial revision
624
			AttachedTransformation()->Put(space, s);
625
		}
626
		else
627
		{
628
			if (length != s)
23 by weidai
fix whitespace problems
629
				throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
630
			m_cipher.ProcessData(space, inString, s);
1 by weidai
Initial revision
631
			if (m_padding == PKCS_PADDING)
632
			{
633
				byte pad = space[s-1];
23 by weidai
fix whitespace problems
634
				if (pad < 1 || pad > s || std::find_if(space+s-pad, space+s, std::bind2nd(std::not_equal_to<byte>(), pad)) != space+s)
1 by weidai
Initial revision
635
					throw InvalidCiphertext("StreamTransformationFilter: invalid PKCS #7 block padding found");
636
				length = s-pad;
637
			}
638
			else
639
			{
134 by weidai
fix ONE_AND_ZEROS_PADDING
640
				while (length > 1 && space[length-1] == 0)
1 by weidai
Initial revision
641
					--length;
134 by weidai
fix ONE_AND_ZEROS_PADDING
642
				if (space[--length] != 0x80)
23 by weidai
fix whitespace problems
643
					throw InvalidCiphertext("StreamTransformationFilter: invalid ones-and-zeros padding found");
1 by weidai
Initial revision
644
			}
645
			AttachedTransformation()->Put(space, length);
646
		}
647
		break;
648
649
	default:
650
		assert(false);
651
	}
652
}
653
654
// *************************************************************
655
656
void HashFilter::IsolatedInitialize(const NameValuePairs &parameters)
657
{
658
	m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false);
659
	m_hashModule.Restart();
660
}
661
23 by weidai
fix whitespace problems
662
unsigned int HashFilter::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking)
1 by weidai
Initial revision
663
{
664
	FILTER_BEGIN;
665
	m_hashModule.Update(inString, length);
666
	if (m_putMessage)
667
		FILTER_OUTPUT(1, inString, length, 0);
668
	if (messageEnd)
669
	{
670
		{
23 by weidai
fix whitespace problems
671
			unsigned int size, digestSize = m_hashModule.DigestSize();
672
			m_space = HelpCreatePutSpace(*AttachedTransformation(), NULL_CHANNEL, digestSize, digestSize, size = digestSize);
1 by weidai
Initial revision
673
			m_hashModule.Final(m_space);
674
		}
675
		FILTER_OUTPUT(2, m_space, m_hashModule.DigestSize(), messageEnd);
676
	}
677
	FILTER_END_NO_MESSAGE_END;
678
}
679
680
// *************************************************************
681
682
HashVerificationFilter::HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment, word32 flags)
683
	: FilterWithBufferedInput(attachment)
684
	, m_hashModule(hm)
685
{
686
	IsolatedInitialize(MakeParameters(Name::HashVerificationFilterFlags(), flags));
687
}
688
23 by weidai
fix whitespace problems
689
void HashVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize)
1 by weidai
Initial revision
690
{
23 by weidai
fix whitespace problems
691
	m_flags = parameters.GetValueWithDefault(Name::HashVerificationFilterFlags(), (word32)DEFAULT_FLAGS);
1 by weidai
Initial revision
692
	m_hashModule.Restart();
23 by weidai
fix whitespace problems
693
	unsigned int size = m_hashModule.DigestSize();
1 by weidai
Initial revision
694
	m_verified = false;
23 by weidai
fix whitespace problems
695
	firstSize = m_flags & HASH_AT_BEGIN ? size : 0;
696
	blockSize = 1;
1 by weidai
Initial revision
697
	lastSize = m_flags & HASH_AT_BEGIN ? 0 : size;
698
}
699
23 by weidai
fix whitespace problems
700
void HashVerificationFilter::FirstPut(const byte *inString)
1 by weidai
Initial revision
701
{
23 by weidai
fix whitespace problems
702
	if (m_flags & HASH_AT_BEGIN)
1 by weidai
Initial revision
703
	{
704
		m_expectedHash.New(m_hashModule.DigestSize());
705
		memcpy(m_expectedHash, inString, m_expectedHash.size());
23 by weidai
fix whitespace problems
706
		if (m_flags & PUT_HASH)
707
			AttachedTransformation()->Put(inString, m_expectedHash.size());
1 by weidai
Initial revision
708
	}
709
}
710
23 by weidai
fix whitespace problems
711
void HashVerificationFilter::NextPutMultiple(const byte *inString, unsigned int length)
1 by weidai
Initial revision
712
{
713
	m_hashModule.Update(inString, length);
23 by weidai
fix whitespace problems
714
	if (m_flags & PUT_MESSAGE)
715
		AttachedTransformation()->Put(inString, length);
1 by weidai
Initial revision
716
}
717
23 by weidai
fix whitespace problems
718
void HashVerificationFilter::LastPut(const byte *inString, unsigned int length)
1 by weidai
Initial revision
719
{
23 by weidai
fix whitespace problems
720
	if (m_flags & HASH_AT_BEGIN)
1 by weidai
Initial revision
721
	{
722
		assert(length == 0);
723
		m_verified = m_hashModule.Verify(m_expectedHash);
724
	}
725
	else
726
	{
23 by weidai
fix whitespace problems
727
		m_verified = (length==m_hashModule.DigestSize() && m_hashModule.Verify(inString));
728
		if (m_flags & PUT_HASH)
729
			AttachedTransformation()->Put(inString, length);
1 by weidai
Initial revision
730
	}
731
23 by weidai
fix whitespace problems
732
	if (m_flags & PUT_RESULT)
1 by weidai
Initial revision
733
		AttachedTransformation()->Put(m_verified);
734
23 by weidai
fix whitespace problems
735
	if ((m_flags & THROW_EXCEPTION) && !m_verified)
1 by weidai
Initial revision
736
		throw HashVerificationFailed();
737
}
738
739
// *************************************************************
740
23 by weidai
fix whitespace problems
741
void SignerFilter::IsolatedInitialize(const NameValuePairs &parameters)
1 by weidai
Initial revision
742
{
743
	m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false);
49 by weidai
remove default NullRNG() for signing
744
	m_messageAccumulator.reset(m_signer.NewSignatureAccumulator(m_rng));
1 by weidai
Initial revision
745
}
746
23 by weidai
fix whitespace problems
747
unsigned int SignerFilter::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking)
1 by weidai
Initial revision
748
{
749
	FILTER_BEGIN;
750
	m_messageAccumulator->Update(inString, length);
751
	if (m_putMessage)
752
		FILTER_OUTPUT(1, inString, length, 0);
753
	if (messageEnd)
754
	{
755
		m_buf.New(m_signer.SignatureLength());
756
		m_signer.Sign(m_rng, m_messageAccumulator.release(), m_buf);
23 by weidai
fix whitespace problems
757
		FILTER_OUTPUT(2, m_buf, m_buf.size(), messageEnd);
49 by weidai
remove default NullRNG() for signing
758
		m_messageAccumulator.reset(m_signer.NewSignatureAccumulator(m_rng));
1 by weidai
Initial revision
759
	}
760
	FILTER_END_NO_MESSAGE_END;
761
}
762
763
SignatureVerificationFilter::SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment, word32 flags)
764
	: FilterWithBufferedInput(attachment)
765
	, m_verifier(verifier)
766
{
23 by weidai
fix whitespace problems
767
	IsolatedInitialize(MakeParameters(Name::SignatureVerificationFilterFlags(), flags));
1 by weidai
Initial revision
768
}
769
23 by weidai
fix whitespace problems
770
void SignatureVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs &parameters, unsigned int &firstSize, unsigned int &blockSize, unsigned int &lastSize)
1 by weidai
Initial revision
771
{
23 by weidai
fix whitespace problems
772
	m_flags = parameters.GetValueWithDefault(Name::SignatureVerificationFilterFlags(), (word32)DEFAULT_FLAGS);
1 by weidai
Initial revision
773
	m_messageAccumulator.reset(m_verifier.NewVerificationAccumulator());
75 by weidai
create DLL version, fix GetNextIV() bug in CTR and OFB modes
774
	unsigned int size = m_verifier.SignatureLength();
27 by weidai
various changes for 5.1
775
	assert(size != 0);	// TODO: handle recoverable signature scheme
1 by weidai
Initial revision
776
	m_verified = false;
23 by weidai
fix whitespace problems
777
	firstSize = m_flags & SIGNATURE_AT_BEGIN ? size : 0;
778
	blockSize = 1;
779
	lastSize = m_flags & SIGNATURE_AT_BEGIN ? 0 : size;
1 by weidai
Initial revision
780
}
781
782
void SignatureVerificationFilter::FirstPut(const byte *inString)
783
{
23 by weidai
fix whitespace problems
784
	if (m_flags & SIGNATURE_AT_BEGIN)
1 by weidai
Initial revision
785
	{
27 by weidai
various changes for 5.1
786
		if (m_verifier.SignatureUpfront())
787
			m_verifier.InputSignature(*m_messageAccumulator, inString, m_verifier.SignatureLength());
1 by weidai
Initial revision
788
		else
789
		{
790
			m_signature.New(m_verifier.SignatureLength());
23 by weidai
fix whitespace problems
791
			memcpy(m_signature, inString, m_signature.size());
1 by weidai
Initial revision
792
		}
793
23 by weidai
fix whitespace problems
794
		if (m_flags & PUT_SIGNATURE)
795
			AttachedTransformation()->Put(inString, m_signature.size());
1 by weidai
Initial revision
796
	}
797
	else
798
	{
27 by weidai
various changes for 5.1
799
		assert(!m_verifier.SignatureUpfront());
1 by weidai
Initial revision
800
	}
801
}
802
23 by weidai
fix whitespace problems
803
void SignatureVerificationFilter::NextPutMultiple(const byte *inString, unsigned int length)
1 by weidai
Initial revision
804
{
805
	m_messageAccumulator->Update(inString, length);
23 by weidai
fix whitespace problems
806
	if (m_flags & PUT_MESSAGE)
807
		AttachedTransformation()->Put(inString, length);
1 by weidai
Initial revision
808
}
809
23 by weidai
fix whitespace problems
810
void SignatureVerificationFilter::LastPut(const byte *inString, unsigned int length)
1 by weidai
Initial revision
811
{
23 by weidai
fix whitespace problems
812
	if (m_flags & SIGNATURE_AT_BEGIN)
1 by weidai
Initial revision
813
	{
814
		assert(length == 0);
27 by weidai
various changes for 5.1
815
		m_verifier.InputSignature(*m_messageAccumulator, m_signature, m_signature.size());
816
		m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator);
1 by weidai
Initial revision
817
	}
818
	else
819
	{
27 by weidai
various changes for 5.1
820
		m_verifier.InputSignature(*m_messageAccumulator, inString, length);
821
		m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator);
23 by weidai
fix whitespace problems
822
		if (m_flags & PUT_SIGNATURE)
823
			AttachedTransformation()->Put(inString, length);
1 by weidai
Initial revision
824
	}
825
23 by weidai
fix whitespace problems
826
	if (m_flags & PUT_RESULT)
1 by weidai
Initial revision
827
		AttachedTransformation()->Put(m_verified);
828
23 by weidai
fix whitespace problems
829
	if ((m_flags & THROW_EXCEPTION) && !m_verified)
1 by weidai
Initial revision
830
		throw SignatureVerificationFailed();
831
}
832
833
// *************************************************************
834
835
unsigned int Source::PumpAll2(bool blocking)
836
{
23 by weidai
fix whitespace problems
837
	// TODO: switch length type
838
	unsigned long i = UINT_MAX;
1 by weidai
Initial revision
839
	RETURN_IF_NONZERO(Pump2(i, blocking));
840
	unsigned int j = UINT_MAX;
23 by weidai
fix whitespace problems
841
	return PumpMessages2(j, blocking);
1 by weidai
Initial revision
842
}
843
844
bool Store::GetNextMessage()
845
{
846
	if (!m_messageEnd && !AnyRetrievable())
847
	{
848
		m_messageEnd=true;
849
		return true;
850
	}
851
	else
852
		return false;
853
}
854
23 by weidai
fix whitespace problems
855
unsigned int Store::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const
1 by weidai
Initial revision
856
{
23 by weidai
fix whitespace problems
857
	if (m_messageEnd || count == 0)
1 by weidai
Initial revision
858
		return 0;
859
	else
860
	{
861
		CopyTo(target, ULONG_MAX, channel);
862
		if (GetAutoSignalPropagation())
863
			target.ChannelMessageEnd(channel, GetAutoSignalPropagation()-1);
864
		return 1;
865
	}
866
}
867
23 by weidai
fix whitespace problems
868
void StringStore::StoreInitialize(const NameValuePairs &parameters)
1 by weidai
Initial revision
869
{
23 by weidai
fix whitespace problems
870
	ConstByteArrayParameter array;
1 by weidai
Initial revision
871
	if (!parameters.GetValue(Name::InputBuffer(), array))
23 by weidai
fix whitespace problems
872
		throw InvalidArgument("StringStore: missing InputBuffer argument");
873
	m_store = array.begin();
1 by weidai
Initial revision
874
	m_length = array.size();
23 by weidai
fix whitespace problems
875
	m_count = 0;
1 by weidai
Initial revision
876
}
877
23 by weidai
fix whitespace problems
878
unsigned int StringStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking)
1 by weidai
Initial revision
879
{
880
	unsigned long position = 0;
23 by weidai
fix whitespace problems
881
	unsigned int blockedBytes = CopyRangeTo2(target, position, transferBytes, channel, blocking);
882
	m_count += position;
883
	transferBytes = position;
1 by weidai
Initial revision
884
	return blockedBytes;
885
}
886
23 by weidai
fix whitespace problems
887
unsigned int StringStore::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const
1 by weidai
Initial revision
888
{
23 by weidai
fix whitespace problems
889
	unsigned int i = (unsigned int)STDMIN((unsigned long)m_count+begin, (unsigned long)m_length);
1 by weidai
Initial revision
890
	unsigned int len = (unsigned int)STDMIN((unsigned long)m_length-i, end-begin);
23 by weidai
fix whitespace problems
891
	unsigned int blockedBytes = target.ChannelPut2(channel, m_store+i, len, 0, blocking);
1 by weidai
Initial revision
892
	if (!blockedBytes)
893
		begin += len;
894
	return blockedBytes;
895
}
896
92 by weidai
allow DLL to be built with VC++ .NET
897
void RandomNumberStore::StoreInitialize(const NameValuePairs &parameters)
898
{
899
	parameters.GetRequiredParameter("RandomNumberStore", "RandomNumberGeneratorPointer", m_rng);
900
	parameters.GetRequiredIntParameter("RandomNumberStore", "RandomNumberStoreSize", m_length);
901
}
902
23 by weidai
fix whitespace problems
903
unsigned int RandomNumberStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking)
1 by weidai
Initial revision
904
{
905
	if (!blocking)
23 by weidai
fix whitespace problems
906
		throw NotImplemented("RandomNumberStore: nonblocking transfer is not implemented by this object");
1 by weidai
Initial revision
907
23 by weidai
fix whitespace problems
908
	unsigned long transferMax = transferBytes;
92 by weidai
allow DLL to be built with VC++ .NET
909
	for (transferBytes = 0; transferBytes<transferMax && m_count < (unsigned long)m_length; ++transferBytes, ++m_count)
910
		target.ChannelPut(channel, m_rng->GenerateByte());
1 by weidai
Initial revision
911
	return 0;
912
}
913
23 by weidai
fix whitespace problems
914
unsigned int NullStore::CopyRangeTo2(BufferedTransformation &target, unsigned long &begin, unsigned long end, const std::string &channel, bool blocking) const
1 by weidai
Initial revision
915
{
916
	static const byte nullBytes[128] = {0};
917
	while (begin < end)
918
	{
919
		unsigned int len = STDMIN(end-begin, 128UL);
23 by weidai
fix whitespace problems
920
		unsigned int blockedBytes = target.ChannelPut2(channel, nullBytes, len, 0, blocking);
1 by weidai
Initial revision
921
		if (blockedBytes)
922
			return blockedBytes;
923
		begin += len;
924
	}
925
	return 0;
926
}
927
23 by weidai
fix whitespace problems
928
unsigned int NullStore::TransferTo2(BufferedTransformation &target, unsigned long &transferBytes, const std::string &channel, bool blocking)
1 by weidai
Initial revision
929
{
23 by weidai
fix whitespace problems
930
	unsigned long begin = 0;
931
	unsigned int blockedBytes = NullStore::CopyRangeTo2(target, begin, transferBytes, channel, blocking);
932
	transferBytes = begin;
1 by weidai
Initial revision
933
	m_size -= begin;
934
	return blockedBytes;
935
}
936
937
NAMESPACE_END
75 by weidai
create DLL version, fix GetNextIV() bug in CTR and OFB modes
938
939
#endif