mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-28 06:12:37 -06:00
293 lines
No EOL
7.4 KiB
C++
293 lines
No EOL
7.4 KiB
C++
#include <Core/Core.h>
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
#define OPENSSL_SYS_WINDOWS
|
|
#define OPENSSL_SYS_WIN32
|
|
#endif
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <AESStream/AESStream.h>
|
|
|
|
#define TFILE <AESStream/AESStream.t>
|
|
#include <Core/t.h>
|
|
|
|
|
|
void AESInit();
|
|
|
|
//
|
|
// Код исходит из того, что AES_BLOCK_SIZE == 2^n
|
|
// Code has an assumption AES_BLOCK_SIZE == 2^n bytes
|
|
//----------------------------------------------------------------------------------------------
|
|
String AESRandomString(int length)
|
|
{
|
|
AESInit();
|
|
|
|
static bool sslRandInit = false;
|
|
if (!sslRandInit)
|
|
{
|
|
sslRandInit = true;
|
|
}
|
|
|
|
StringBuffer ident(length);
|
|
RAND_bytes((unsigned char *) ~ident, length);
|
|
return ident;
|
|
}
|
|
|
|
String AESPadString(const String &s, int l)
|
|
{
|
|
AESInit();
|
|
|
|
int addL = s.GetLength() % l;
|
|
if (!addL)
|
|
return s;
|
|
|
|
String outS(s);
|
|
outS << AESRandomString(l - addL);
|
|
return outS;
|
|
}
|
|
|
|
dword rdtsc()
|
|
{
|
|
return Random();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
bool aesInitDone = false;
|
|
void AESInit()
|
|
{
|
|
if (aesInitDone)
|
|
return;
|
|
aesInitDone = true;
|
|
|
|
if (RAND_status())
|
|
return;
|
|
|
|
qword qw = (((qword) GetTickCount()) << 16) ^ ((qword) (GetSysTime().Get())) ^ Random();
|
|
RAND_seed(&qw, sizeof(qw));
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
RAND_screen();
|
|
#endif
|
|
|
|
while (!RAND_status())
|
|
{
|
|
dword dw = Random();
|
|
RAND_seed(&dw, sizeof(dword));
|
|
dw = rdtsc();
|
|
RAND_seed(&dw, sizeof(dword));
|
|
|
|
static int hops = 0;
|
|
if (hops > 1000000)
|
|
throw t_("AESInit: Random generator init error");
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
AESEncoderStream::AESEncoderStream(qword _size, const String &_key) // Deprecated in C++11: throw (const char *)
|
|
: size (_size)
|
|
, blocks (_size / AES_BLOCK_SIZE)
|
|
, blocksDone (0)
|
|
, iv0 (AESRandomString(AES_BLOCK_SIZE))
|
|
, encodedHeader (false)
|
|
{
|
|
AESInit();
|
|
|
|
*((dword *) ~iv0) ^= (Random() ^ rdtsc());
|
|
*(((dword *) ~iv0) + 1) ^= (Random() ^ GetTickCount());
|
|
if (_size & (AES_BLOCK_SIZE-1))
|
|
++blocks;
|
|
|
|
iv.Cat(iv0);
|
|
|
|
if (_key.GetLength() != 16 && _key.GetLength() != 24 && _key.GetLength() != 32)
|
|
throw t_("AESEncoderStream::ctor: Key must be 16, 24 or 32 bytes long");
|
|
if (AES_set_encrypt_key((const unsigned char *) ~_key, _key.GetLength() << 3, &key))
|
|
throw t_("AESEncoderStream::ctor: Could not setup AES key. OpenSSL problem?");
|
|
}
|
|
|
|
int AESEncoderStream::AddData(const String &s)
|
|
{
|
|
int sl = s.GetLength();
|
|
|
|
if (blocksDone == blocks)
|
|
return 0;
|
|
|
|
qword sizeLeft = size - blocksDone*AES_BLOCK_SIZE;
|
|
if (((qword) s.GetLength()) <= sizeLeft)
|
|
data << s;
|
|
else
|
|
{
|
|
sl = (int) sizeLeft;
|
|
data << s.Left(sl);
|
|
}
|
|
|
|
if (blocksDone*AES_BLOCK_SIZE+data.GetLength() == size)
|
|
{
|
|
//padding last bytes to fit into AES_BLOCK_SIZE
|
|
//последние данные всегда добавляются шумом до размера, кратного блоку
|
|
int extraLength = size % AES_BLOCK_SIZE;
|
|
if (extraLength)
|
|
data << AESRandomString(AES_BLOCK_SIZE - extraLength);
|
|
}
|
|
return sl;
|
|
}
|
|
|
|
String AESEncoderStream::GetHeader()
|
|
{
|
|
if (encodedHeader)
|
|
return "";
|
|
|
|
String header;
|
|
|
|
dword magic1, magic2;
|
|
String magicS = AESRandomString(sizeof(qword));
|
|
memcpy(&magic1, ~magicS, sizeof(dword));
|
|
memcpy(&magic2, (~magicS) + sizeof(dword), sizeof(dword));
|
|
dword magicDelta = AES_CONTAINER_DWORD_HEADER - (magic1 + magic2);
|
|
magic2 += magicDelta;
|
|
header.Cat((const char *)&magic1, sizeof(dword));
|
|
header.Cat((const char *)&magic2, sizeof(dword));
|
|
|
|
header << iv0;
|
|
|
|
qword sze = (qword) size;
|
|
header.Cat((const char *) &sze, sizeof(sze));
|
|
header = AESPadString(header, AES_BLOCK_SIZE);
|
|
|
|
StringBuffer outBuffer(header.GetLength());
|
|
|
|
for (int offs = 0; offs+AES_BLOCK_SIZE <= header.GetLength(); offs += AES_BLOCK_SIZE)
|
|
AES_ecb_encrypt(((const unsigned char *) ~header)+offs, ((unsigned char *) ~outBuffer)+offs, &key, true);
|
|
|
|
encodedHeader = true;
|
|
return outBuffer;
|
|
}
|
|
|
|
String AESEncoderStream::GetEncryptedData()
|
|
{
|
|
if (blocksDone == blocks)
|
|
return "";
|
|
|
|
qword overallBlocks = (qword) (data.GetLength()/AES_BLOCK_SIZE);
|
|
int doBlocks = (int) min(overallBlocks, blocks-blocksDone);
|
|
if (!doBlocks)
|
|
return "";
|
|
|
|
int doSize = doBlocks*AES_BLOCK_SIZE;
|
|
StringBuffer outData(doSize);
|
|
|
|
AES_cbc_encrypt((const unsigned char *) ~data, (unsigned char *) ~outData, (const unsigned long) doSize, &key, (unsigned char *) ~iv, true);
|
|
if (doSize < data.GetLength())
|
|
data.Remove(0, doSize);
|
|
else
|
|
data.Clear();
|
|
blocksDone += doBlocks;
|
|
|
|
if (encodedHeader)
|
|
return outData;
|
|
else
|
|
return (GetHeader()+String(outData));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
AESDecoderStream::AESDecoderStream(const String &_key) // Deprecated in C++11: throw (const char *)
|
|
: size (0L)
|
|
, sizeDone (0L)
|
|
, iv (AES_BLOCK_SIZE)
|
|
, decodedHeader (false)
|
|
{
|
|
AESInit();
|
|
|
|
if (_key.GetLength() != 16 && _key.GetLength() != 24 && _key.GetLength() != 32)
|
|
throw t_("AESDecoderStream::ctor: Key must be 16, 24 or 32 bytes long");
|
|
if (AES_set_decrypt_key((const unsigned char *) ~_key, _key.GetLength() << 3, &key))
|
|
throw t_("AESDecoderStream::ctor: Could not setup AES key. OpenSSL problem?");
|
|
}
|
|
|
|
int AESDecoderStream::AddData(const String &s)
|
|
{
|
|
if (!size)
|
|
{
|
|
data << s;
|
|
int io = data.GetLength();
|
|
return s.GetLength();
|
|
}
|
|
|
|
qword sz = size & ~((qword) (AES_BLOCK_SIZE-1));
|
|
if (size & (AES_BLOCK_SIZE-1))
|
|
sz += AES_BLOCK_SIZE;
|
|
|
|
qword dl = (qword)data.GetLength();
|
|
if (dl >= sz)
|
|
return 0;
|
|
|
|
qword sl = (qword) s.GetLength();
|
|
if (dl+sl < sz)
|
|
data << s;
|
|
else
|
|
{
|
|
sl = sz - dl;
|
|
data << s.Left((int) sl);
|
|
}
|
|
|
|
return (int) sl;
|
|
}
|
|
|
|
String AESDecoderStream::GetDecryptedData() // Deprecated in C++1: throw (const char *)
|
|
{
|
|
#pragma pack(push,1)
|
|
struct AES_CONTAINER_HEADER
|
|
{
|
|
dword m1;
|
|
dword m2;
|
|
Upp::byte iv[AES_BLOCK_SIZE];
|
|
qword size;
|
|
} header;
|
|
#pragma pack(pop)
|
|
|
|
if (!decodedHeader)
|
|
{
|
|
if (data.GetLength() < sizeof(header))
|
|
return "";
|
|
|
|
for (int offs = 0; offs+AES_BLOCK_SIZE <= sizeof(header); offs += AES_BLOCK_SIZE)
|
|
AES_ecb_encrypt(((const unsigned char *) ~data)+offs, ((unsigned char *) &header)+offs, &key, false);
|
|
|
|
if (header.m1+header.m2 != AES_CONTAINER_DWORD_HEADER)
|
|
throw t_("Wrong key!");
|
|
|
|
memcpy(~iv, &(header.iv[0]), AES_BLOCK_SIZE);
|
|
size = header.size;
|
|
|
|
data.Remove(0, sizeof(header));
|
|
decodedHeader = true;
|
|
}
|
|
|
|
dword doSize = data.GetLength();
|
|
qword sizeLeft = size-sizeDone;
|
|
if (((qword) doSize) > sizeLeft)
|
|
doSize = (dword) sizeLeft;
|
|
if (!doSize)
|
|
return "";
|
|
|
|
dword extSize = doSize & (~(dword) (AES_BLOCK_SIZE-1));
|
|
if (extSize && ((dword) data.GetLength()) >= doSize+AES_BLOCK_SIZE)
|
|
doSize += AES_BLOCK_SIZE;
|
|
|
|
StringBuffer outData(doSize);
|
|
|
|
AES_cbc_encrypt((const unsigned char *) ~data, (unsigned char *) ~outData, (const unsigned long) doSize, &key, (unsigned char *) ~iv, false);
|
|
data.Remove(0, doSize);
|
|
sizeDone += doSize;
|
|
return outData;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
const dword AES_CONTAINER_DWORD_HEADER = 0x377FEA9F;
|
|
|
|
String SHA256Bin(const char *key) {
|
|
byte hash32[32];
|
|
SHA256(hash32, key);
|
|
return String(hash32, 32);
|
|
} |