ultimatepp/bazaar/Cypher/CypherBase.cpp
micio 716ef4b9c6 Bazaar/Cypher : Renamed base class CypherBase to Cypher
Better name when creating generic cypher pointers

git-svn-id: svn://ultimatepp.org/upp/trunk@2760 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2010-10-09 22:15:30 +00:00

337 lines
7.6 KiB
C++

#include "CypherBase.h"
NAMESPACE_UPP
////////////////////////////////////////////////////////////////////////////////////////////
// CypherFifo class //
////////////////////////////////////////////////////////////////////////////////////////////
// inserts data
void CypherFifo::Put(byte const *buf, int len)
{
int l = data.GetCount();
data.AddN(len);
byte *b = &data.At(l);
memcpy(b, buf, len);
}
void CypherFifo::Put(String const &s)
{
Put((byte const *)~s, s.GetCount());
}
void CypherFifo::Put(byte b)
{
data.Add(b);
}
// extract data
bool CypherFifo::Get(byte *buf, int len)
{
if(data.GetCount() < len)
return false;
memcpy(buf, &data.At(0), len);
data.Remove(0, len);
return true;
}
bool CypherFifo::Get(String &s)
{
if(!data.GetCount())
return false;
StringBuffer sb;
sb.Cat((const char *)&data.At(0), data.GetCount());
data.Clear();
s = sb;
return true;
}
bool CypherFifo::Get(byte &b)
{
if(!data.GetCount())
return false;
b = data.At(0);
data.Remove(0);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
// Cypher class //
////////////////////////////////////////////////////////////////////////////////////////
Cypher::Cypher(size_t _blockSize)
{
// still no key present
keyOk = false;
// Cypher in IDLE mode at startup
mode = IDLE;
// clears FIFO
FIFO.Clear();
// sets the encryption block size
blockSize = _blockSize;
// resets total stream size
// should be set BEFORE streaming (decoding)
// if we want the resulting stream truncated on right length
// otherwise we get also the pad bytes
streamSize = 0;
}
void Cypher::Reset()
{
keyOk = false;
mode = IDLE;
FIFO.Clear();
streamSize = 0;
}
// set mode (either STREAM or BLOCK
// throws an exception if another mode was already active
void Cypher::SetMode(Mode m)
{
// checks if another mode already in progress, if so throws an exception
if(mode != m && mode != IDLE)
throw "A different encoding mode was already in progress";
// if starting stream mode, allocate block buffer if
// working with a Block-Cypher
if(m == STREAM_MODE && mode == IDLE && blockSize > 1)
{
// allocates block buffer and set pointer to its start
blockBuffer.Alloc(blockSize);
blockBytes = 0;
// resets streamedIn and streamedOut values
streamedIn = streamedOut = 0;
}
mode = m;
}
// checks if key was set, otherwise throws an exception
void Cypher::CheckKey(void)
{
if(!keyOk)
throw "Missing key";
}
// checks buffer size if it must be multiple of block size
// for Block-Cyphers. Throws an exception if not
void Cypher::CheckBufSize(size_t bufSize)
{
if(blockSize == 1)
return;
if(bufSize % blockSize)
throw "Buffer size mismatch - not a multiple of block size";
}
// rounds buffer size to nearest bigger multiple of block size
size_t Cypher::RoundBufSize(size_t bufSize)
{
size_t rem = bufSize % blockSize;
if(rem)
bufSize += blockSize - rem;
return bufSize;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// key setting
void Cypher::SetKey(byte const *keyBuf, size_t keyLen, byte const *_nonce, size_t nonceLen)
{
nonce.Clear();
if(!_nonce || !nonceLen)
{
for(size_t i = 0; i < 8; i++)
nonce.Cat(Random() & 0xff);
}
else
{
for(size_t i = 0; i < nonceLen; i++)
nonce.Cat(_nonce[i]);
}
if(!CypherKey(keyBuf, keyLen, (const byte *)~nonce, nonce.GetCount()))
throw "Invalid key";
keyOk = true;
}
void Cypher::SetKey(String const &key, String const &nonce)
{
if(IsNull(nonce))
SetKey((byte const *)~key, key.GetCount(), NULL, 0);
else
SetKey((byte const *)~key, key.GetCount(), (byte const *)~nonce, nonce.GetCount());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// encrypt/decrypt functions
String Cypher::operator()(String const &s)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets buffer mode, exception if already in stream mode
SetMode(BUFFER_MODE);
// checks buffer size, exception if not multiple of block size
CheckBufSize(s.GetCount());
StringBuffer sb(s.GetCount());
CypherCypher((const byte *)~s, (byte *)~sb, s.GetCount());
return sb;
}
void Cypher::operator()(byte const *sourceBuf, byte *destBuf, size_t bufLen)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets buffer mode, exception if already in stream mode
SetMode(BUFFER_MODE);
// checks buffer size, exception if not multiple of block size
CheckBufSize(bufLen);
CypherCypher(sourceBuf, destBuf, bufLen);
}
void Cypher::operator()(byte *buf, size_t bufLen)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets buffer mode, exception if already in stream mode
SetMode(BUFFER_MODE);
// checks buffer size, exception if not multiple of block size
CheckBufSize(bufLen);
CypherCypher(buf, buf, bufLen);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// streaming support
String Cypher::StreamOut(void)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets stream mode, exception if already in buffer mode
SetMode(STREAM_MODE);
String res;
FIFO.Get(res);
// if blockSize == 1 OR user didn't set stream size, simple behaviour
if(blockSize != 1 && streamSize != 0)
{
if(streamedOut >= streamSize)
return "";
if(streamedOut + res.GetCount() > streamSize)
res = res.Left(streamSize - streamedOut);
}
// returns encoded buffer from FIFO
streamedOut += res.GetCount();
return res;
}
void Cypher::StreamIn(String const &s)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets stream mode, exception if already in buffer mode
SetMode(STREAM_MODE);
// simpler streaming if blockSize == 1
if(blockSize == 1)
{
// en/decode string and put into FIFO
StringBuffer sb(s.GetCount());
CypherCypher((const byte *)~s, (byte *)~sb, s.GetCount());
FIFO.Put(sb);
}
else
{
size_t len = s.GetCount();
size_t idx = 0;
// if block buffer is partially filled, try to finish it before
if(blockBytes)
{
size_t count = min(len, blockSize - blockBytes);
idx += count;
len -= count;
memcpy(blockBuffer + blockBytes, ~s, count);
blockBytes += count;
if(blockBytes >= blockSize)
{
CypherCypher(blockBuffer, blockBuffer, blockSize);
FIFO.Put(blockBuffer, blockSize);
blockBytes = 0;
}
}
// stream in full block buffers
if(len)
{
// get number of bytes composing FULL blocks
size_t count = len - (len % blockSize);
if(count)
{
Buffer<byte> buf(count);
CypherCypher((const byte *)~s + idx, buf, count);
FIFO.Put(buf, count);
len -= count;
idx += count;
}
}
// fills block buffer with remaining data, if any
if(len)
{
memcpy(blockBuffer, ~s + idx, len);
blockBytes = len;
}
}
// updates number of streamed-in bytes
streamedIn += s.GetCount();
}
size_t Cypher::Flush(void)
{
// checks if KEY is ok, exception if not
CheckKey();
// sets stream mode, exception if already in buffer mode
SetMode(STREAM_MODE);
// nothing to do on Stream-Cyphers, just return stream total size
if(blockSize == 1)
return streamedIn;
// on block stream, we should pad partial data (if any)
// and encrypt them; we pad them with plain random data
if(blockBytes)
{
for(size_t i = blockBytes; i < blockSize; i++)
blockBuffer[i] = (byte)(Random() & 0xff);
CypherCypher(blockBuffer, blockBuffer, blockSize);
FIFO.Put(blockBuffer, blockSize);
blockBytes = 0;
}
// return the true streamed-in byte count, not the padded one
return streamedIn;
};
END_UPP_NAMESPACE