Click here to Skip to main content
15,885,767 members
Articles / Web Development / ASP.NET

Encryption and compression, native and managed

Rate me:
Please Sign up or sign in to vote.
4.74/5 (17 votes)
29 Jun 2012CPOL7 min read 111.1K   6.9K   92  
DLL for native encryption and compression (using Crypto++). Includes RSA Key Generator in C#, and encryption and compression in ASP.NET (C#).
// queue.cpp - written and placed in the public domain by Wei Dai

#include "pch.h"

#ifndef CRYPTOPP_IMPORTS

#include "queue.h"
#include "filters.h"

NAMESPACE_BEGIN(CryptoPP)

static const unsigned int s_maxAutoNodeSize = 16*1024;

// this class for use by ByteQueue only
class ByteQueueNode
{
public:
	ByteQueueNode(size_t maxSize)
		: buf(maxSize)
	{
		m_head = m_tail = 0;
		next = 0;
	}

	inline size_t MaxSize() const {return buf.size();}

	inline size_t CurrentSize() const
	{
		return m_tail-m_head;
	}

	inline bool UsedUp() const
	{
		return (m_head==MaxSize());
	}

	inline void Clear()
	{
		m_head = m_tail = 0;
	}

	inline size_t Put(const byte *begin, size_t length)
	{
		size_t l = STDMIN(length, MaxSize()-m_tail);
		if (buf+m_tail != begin)
			memcpy(buf+m_tail, begin, l);
		m_tail += l;
		return l;
	}

	inline size_t Peek(byte &outByte) const
	{
		if (m_tail==m_head)
			return 0;

		outByte=buf[m_head];
		return 1;
	}

	inline size_t Peek(byte *target, size_t copyMax) const
	{
		size_t len = STDMIN(copyMax, m_tail-m_head);
		memcpy(target, buf+m_head, len);
		return len;
	}

	inline size_t CopyTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const
	{
		size_t len = m_tail-m_head;
		target.ChannelPut(channel, buf+m_head, len);
		return len;
	}

	inline size_t CopyTo(BufferedTransformation &target, size_t copyMax, const std::string &channel=DEFAULT_CHANNEL) const
	{
		size_t len = STDMIN(copyMax, m_tail-m_head);
		target.ChannelPut(channel, buf+m_head, len);
		return len;
	}

	inline size_t Get(byte &outByte)
	{
		size_t len = Peek(outByte);
		m_head += len;
		return len;
	}

	inline size_t Get(byte *outString, size_t getMax)
	{
		size_t len = Peek(outString, getMax);
		m_head += len;
		return len;
	}

	inline size_t TransferTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL)
	{
		size_t len = m_tail-m_head;
		target.ChannelPutModifiable(channel, buf+m_head, len);
		m_head = m_tail;
		return len;
	}

	inline size_t TransferTo(BufferedTransformation &target, lword transferMax, const std::string &channel=DEFAULT_CHANNEL)
	{
		size_t len = UnsignedMin(m_tail-m_head, transferMax);
		target.ChannelPutModifiable(channel, buf+m_head, len);
		m_head += len;
		return len;
	}

	inline size_t Skip(size_t skipMax)
	{
		size_t len = STDMIN(skipMax, m_tail-m_head);
		m_head += len;
		return len;
	}

	inline byte operator[](size_t i) const
	{
		return buf[m_head+i];
	}

	ByteQueueNode *next;

	SecByteBlock buf;
	size_t m_head, m_tail;
};

// ********************************************************

ByteQueue::ByteQueue(size_t nodeSize)
	: m_lazyString(NULL), m_lazyLength(0)
{
	SetNodeSize(nodeSize);
	m_head = m_tail = new ByteQueueNode(m_nodeSize);
}

void ByteQueue::SetNodeSize(size_t nodeSize)
{
	m_autoNodeSize = !nodeSize;
	m_nodeSize = m_autoNodeSize ? 256 : nodeSize;
}

ByteQueue::ByteQueue(const ByteQueue &copy)
	: m_lazyString(NULL)
{
	CopyFrom(copy);
}

void ByteQueue::CopyFrom(const ByteQueue &copy)
{
	m_lazyLength = 0;
	m_autoNodeSize = copy.m_autoNodeSize;
	m_nodeSize = copy.m_nodeSize;
	m_head = m_tail = new ByteQueueNode(*copy.m_head);

	for (ByteQueueNode *current=copy.m_head->next; current; current=current->next)
	{
		m_tail->next = new ByteQueueNode(*current);
		m_tail = m_tail->next;
	}

	m_tail->next = NULL;

	Put(copy.m_lazyString, copy.m_lazyLength);
}

ByteQueue::~ByteQueue()
{
	Destroy();
}

void ByteQueue::Destroy()
{
	for (ByteQueueNode *next, *current=m_head; current; current=next)
	{
		next=current->next;
		delete current;
	}
}

void ByteQueue::IsolatedInitialize(const NameValuePairs &parameters)
{
	m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256);
	Clear();
}

lword ByteQueue::CurrentSize() const
{
	lword size=0;

	for (ByteQueueNode *current=m_head; current; current=current->next)
		size += current->CurrentSize();

	return size + m_lazyLength;
}

bool ByteQueue::IsEmpty() const
{
	return m_head==m_tail && m_head->CurrentSize()==0 && m_lazyLength==0;
}

void ByteQueue::Clear()
{
	for (ByteQueueNode *next, *current=m_head->next; current; current=next)
	{
		next=current->next;
		delete current;
	}

	m_tail = m_head;
	m_head->Clear();
	m_head->next = NULL;
	m_lazyLength = 0;
}

size_t ByteQueue::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{
	if (m_lazyLength > 0)
		FinalizeLazyPut();

	size_t len;
	while ((len=m_tail->Put(inString, length)) < length)
	{
		inString += len;
		length -= len;
		if (m_autoNodeSize && m_nodeSize < s_maxAutoNodeSize)
			do
			{
				m_nodeSize *= 2;
			}
			while (m_nodeSize < length && m_nodeSize < s_maxAutoNodeSize);
		m_tail->next = new ByteQueueNode(STDMAX(m_nodeSize, length));
		m_tail = m_tail->next;
	}

	return 0;
}

void ByteQueue::CleanupUsedNodes()
{
	while (m_head != m_tail && m_head->UsedUp())
	{
		ByteQueueNode *temp=m_head;
		m_head=m_head->next;
		delete temp;
	}

	if (m_head->CurrentSize() == 0)
		m_head->Clear();
}

void ByteQueue::LazyPut(const byte *inString, size_t size)
{
	if (m_lazyLength > 0)
		FinalizeLazyPut();

	if (inString == m_tail->buf+m_tail->m_tail)
		Put(inString, size);
	else
	{
		m_lazyString = const_cast<byte *>(inString);
		m_lazyLength = size;
		m_lazyStringModifiable = false;
	}
}

void ByteQueue::LazyPutModifiable(byte *inString, size_t size)
{
	if (m_lazyLength > 0)
		FinalizeLazyPut();
	m_lazyString = inString;
	m_lazyLength = size;
	m_lazyStringModifiable = true;
}

void ByteQueue::UndoLazyPut(size_t size)
{
	if (m_lazyLength < size)
		throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large");

	m_lazyLength -= size;
}

void ByteQueue::FinalizeLazyPut()
{
	size_t len = m_lazyLength;
	m_lazyLength = 0;
	if (len)
		Put(m_lazyString, len);
}

size_t ByteQueue::Get(byte &outByte)
{
	if (m_head->Get(outByte))
	{
		if (m_head->UsedUp())
			CleanupUsedNodes();
		return 1;
	}
	else if (m_lazyLength > 0)
	{
		outByte = *m_lazyString++;
		m_lazyLength--;
		return 1;
	}
	else
		return 0;
}

size_t ByteQueue::Get(byte *outString, size_t getMax)
{
	ArraySink sink(outString, getMax);
	return (size_t)TransferTo(sink, getMax);
}

size_t ByteQueue::Peek(byte &outByte) const
{
	if (m_head->Peek(outByte))
		return 1;
	else if (m_lazyLength > 0)
	{
		outByte = *m_lazyString;
		return 1;
	}
	else
		return 0;
}

size_t ByteQueue::Peek(byte *outString, size_t peekMax) const
{
	ArraySink sink(outString, peekMax);
	return (size_t)CopyTo(sink, peekMax);
}

size_t ByteQueue::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
{
	if (blocking)
	{
		lword bytesLeft = transferBytes;
		for (ByteQueueNode *current=m_head; bytesLeft && current; current=current->next)
			bytesLeft -= current->TransferTo(target, bytesLeft, channel);
		CleanupUsedNodes();

		size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength);
		if (len)
		{
			if (m_lazyStringModifiable)
				target.ChannelPutModifiable(channel, m_lazyString, len);
			else
				target.ChannelPut(channel, m_lazyString, len);
			m_lazyString += len;
			m_lazyLength -= len;
			bytesLeft -= len;
		}
		transferBytes -= bytesLeft;
		return 0;
	}
	else
	{
		Walker walker(*this);
		size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
		Skip(transferBytes);
		return blockedBytes;
	}
}

size_t ByteQueue::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
{
	Walker walker(*this);
	walker.Skip(begin);
	lword transferBytes = end-begin;
	size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
	begin += transferBytes;
	return blockedBytes;
}

void ByteQueue::Unget(byte inByte)
{
	Unget(&inByte, 1);
}

void ByteQueue::Unget(const byte *inString, size_t length)
{
	size_t len = STDMIN(length, m_head->m_head);
	length -= len;
	m_head->m_head -= len;
	memcpy(m_head->buf + m_head->m_head, inString + length, len);

	if (length > 0)
	{
		ByteQueueNode *newHead = new ByteQueueNode(length);
		newHead->next = m_head;
		m_head = newHead;
		m_head->Put(inString, length);
	}
}

const byte * ByteQueue::Spy(size_t &contiguousSize) const
{
	contiguousSize = m_head->m_tail - m_head->m_head;
	if (contiguousSize == 0 && m_lazyLength > 0)
	{
		contiguousSize = m_lazyLength;
		return m_lazyString;
	}
	else
		return m_head->buf + m_head->m_head;
}

byte * ByteQueue::CreatePutSpace(size_t &size)
{
	if (m_lazyLength > 0)
		FinalizeLazyPut();

	if (m_tail->m_tail == m_tail->MaxSize())
	{
		m_tail->next = new ByteQueueNode(STDMAX(m_nodeSize, size));
		m_tail = m_tail->next;
	}

	size = m_tail->MaxSize() - m_tail->m_tail;
	return m_tail->buf + m_tail->m_tail;
}

ByteQueue & ByteQueue::operator=(const ByteQueue &rhs)
{
	Destroy();
	CopyFrom(rhs);
	return *this;
}

bool ByteQueue::operator==(const ByteQueue &rhs) const
{
	const lword currentSize = CurrentSize();

	if (currentSize != rhs.CurrentSize())
		return false;

	Walker walker1(*this), walker2(rhs);
	byte b1, b2;

	while (walker1.Get(b1) && walker2.Get(b2))
		if (b1 != b2)
			return false;

	return true;
}

byte ByteQueue::operator[](lword i) const
{
	for (ByteQueueNode *current=m_head; current; current=current->next)
	{
		if (i < current->CurrentSize())
			return (*current)[(size_t)i];
		
		i -= current->CurrentSize();
	}

	assert(i < m_lazyLength);
	return m_lazyString[i];
}

void ByteQueue::swap(ByteQueue &rhs)
{
	std::swap(m_autoNodeSize, rhs.m_autoNodeSize);
	std::swap(m_nodeSize, rhs.m_nodeSize);
	std::swap(m_head, rhs.m_head);
	std::swap(m_tail, rhs.m_tail);
	std::swap(m_lazyString, rhs.m_lazyString);
	std::swap(m_lazyLength, rhs.m_lazyLength);
	std::swap(m_lazyStringModifiable, rhs.m_lazyStringModifiable);
}

// ********************************************************

void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs &parameters)
{
	m_node = m_queue.m_head;
	m_position = 0;
	m_offset = 0;
	m_lazyString = m_queue.m_lazyString;
	m_lazyLength = m_queue.m_lazyLength;
}

size_t ByteQueue::Walker::Get(byte &outByte)
{
	ArraySink sink(&outByte, 1);
	return (size_t)TransferTo(sink, 1);
}

size_t ByteQueue::Walker::Get(byte *outString, size_t getMax)
{
	ArraySink sink(outString, getMax);
	return (size_t)TransferTo(sink, getMax);
}

size_t ByteQueue::Walker::Peek(byte &outByte) const
{
	ArraySink sink(&outByte, 1);
	return (size_t)CopyTo(sink, 1);
}

size_t ByteQueue::Walker::Peek(byte *outString, size_t peekMax) const
{
	ArraySink sink(outString, peekMax);
	return (size_t)CopyTo(sink, peekMax);
}

size_t ByteQueue::Walker::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
{
	lword bytesLeft = transferBytes;
	size_t blockedBytes = 0;

	while (m_node)
	{
		size_t len = (size_t)STDMIN(bytesLeft, (lword)m_node->CurrentSize()-m_offset);
		blockedBytes = target.ChannelPut2(channel, m_node->buf+m_node->m_head+m_offset, len, 0, blocking);

		if (blockedBytes)
			goto done;

		m_position += len;
		bytesLeft -= len;

		if (!bytesLeft)
		{
			m_offset += len;
			goto done;
		}

		m_node = m_node->next;
		m_offset = 0;
	}

	if (bytesLeft && m_lazyLength)
	{
		size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength);
		blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking);
		if (blockedBytes)
			goto done;

		m_lazyString += len;
		m_lazyLength -= len;
		bytesLeft -= len;
	}

done:
	transferBytes -= bytesLeft;
	return blockedBytes;
}

size_t ByteQueue::Walker::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
{
	Walker walker(*this);
	walker.Skip(begin);
	lword transferBytes = end-begin;
	size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
	begin += transferBytes;
	return blockedBytes;
}

NAMESPACE_END

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Argentina Argentina
System developer from Argentina.

Programmed in VB 5,6,.NET, C#, Java, PL-SQL, Transac-SQL, C, C++ and even some "calculator" language.

Love to build small, useful applications.
Usually building big and complicated apps based on solid, reliable components.

Hobbies: reading, photography, chess, paddle, running.

Comments and Discussions