1 #include <Core/Core.h>
2 
3 #ifdef PLATFORM_WIN32
4 #define OPENSSL_SYS_WINDOWS
5 #define OPENSSL_SYS_WIN32
6 #endif
7 
8 #include <openssl/rand.h>
9 
10 #include <AESStream/AESStream.h>
11 
12 #define TFILE <AESStream/AESStream.t>
13 #include <Core/t.h>
14 
15 
16 void AESInit();
17 
18 //
19 // Код исходит из того, что AES_BLOCK_SIZE == 2^n
20 // Code has an assumption AES_BLOCK_SIZE == 2^n bytes
21 //----------------------------------------------------------------------------------------------
AESRandomString(int length)22 String AESRandomString(int length)
23 {
24 	AESInit();
25 
26 	static bool sslRandInit = false;
27 	if (!sslRandInit)
28 	{
29 		sslRandInit = true;
30 	}
31 
32 	StringBuffer ident(length);
33 	RAND_bytes((unsigned char *) ~ident, length);
34 	return ident;
35 }
36 
AESPadString(const String & s,int l)37 String AESPadString(const String &s, int l)
38 {
39 	AESInit();
40 
41 	int addL = s.GetLength() % l;
42 	if (!addL)
43 		return s;
44 
45 	String outS(s);
46 	outS << AESRandomString(l - addL);
47 	return outS;
48 }
49 
rdtsc()50 dword rdtsc()
51 {
52 	return Random();
53 }
54 
55 //----------------------------------------------------------------------------------------------
56 bool aesInitDone = false;
AESInit()57 void AESInit()
58 {
59 	if (aesInitDone)
60 		return;
61 	aesInitDone = true;
62 
63 	if (RAND_status())
64 		return;
65 
66 	qword qw = (((qword) GetTickCount()) << 16) ^ ((qword) (GetSysTime().Get())) ^ Random();
67 	RAND_seed(&qw, sizeof(qw));
68 
69 	#ifdef PLATFORM_WIN32
70 	RAND_screen();
71 	#endif
72 
73 	while (!RAND_status())
74 	{
75 		dword dw = Random();
76 		RAND_seed(&dw, sizeof(dword));
77 		dw = rdtsc();
78 		RAND_seed(&dw, sizeof(dword));
79 
80 		static int hops = 0;
81 		if (hops > 1000000)
82 			throw t_("AESInit: Random generator init error");
83 	}
84 }
85 
86 //----------------------------------------------------------------------------------------------
AESEncoderStream(qword _size,const String & _key)87 AESEncoderStream::AESEncoderStream(qword _size, const String &_key) // Deprecated in C++11:  throw (const char *)
88 	: size       (_size)
89 	, blocks     (_size / AES_BLOCK_SIZE)
90 	, blocksDone (0)
91 	, iv0        (AESRandomString(AES_BLOCK_SIZE))
92 	, encodedHeader (false)
93 {
94 	AESInit();
95 
96 	*((dword *) ~iv0)       ^= (Random() ^ rdtsc());
97 	*(((dword *) ~iv0) + 1) ^= (Random() ^ GetTickCount());
98 	if (_size & (AES_BLOCK_SIZE-1))
99 		++blocks;
100 
101 	iv.Cat(iv0);
102 
103 	if (_key.GetLength() != 16 && _key.GetLength() != 24 && _key.GetLength() != 32)
104 		throw t_("AESEncoderStream::ctor: Key must be 16, 24 or 32 bytes long");
105 	if (AES_set_encrypt_key((const unsigned char *) ~_key, _key.GetLength() << 3, &key))
106 		throw t_("AESEncoderStream::ctor: Could not setup AES key. OpenSSL problem?");
107 }
108 
AddData(const String & s)109 int AESEncoderStream::AddData(const String &s)
110 {
111 	int sl = s.GetLength();
112 
113 	if (blocksDone == blocks)
114 		return 0;
115 
116 	qword sizeLeft = size - blocksDone*AES_BLOCK_SIZE;
117 	if (((qword) s.GetLength()) <= sizeLeft)
118 		data << s;
119 	else
120 	{
121 		sl = (int) sizeLeft;
122 		data << s.Left(sl);
123 	}
124 
125 	if (blocksDone*AES_BLOCK_SIZE+data.GetLength() == size)
126 	{
127 		//padding last bytes to fit into AES_BLOCK_SIZE
128 		//последние данные всегда добавляются шумом до размера, кратного блоку
129 		int extraLength = size % AES_BLOCK_SIZE;
130 		if (extraLength)
131 			data << AESRandomString(AES_BLOCK_SIZE - extraLength);
132 	}
133 	return sl;
134 }
135 
GetHeader()136 String AESEncoderStream::GetHeader()
137 {
138 	if (encodedHeader)
139 		return "";
140 
141 	String header;
142 
143 	dword magic1, magic2;
144 	String magicS = AESRandomString(sizeof(qword));
145 	memcpy(&magic1, ~magicS, sizeof(dword));
146 	memcpy(&magic2, (~magicS) + sizeof(dword), sizeof(dword));
147 	dword magicDelta = AES_CONTAINER_DWORD_HEADER - (magic1 + magic2);
148 	magic2 += magicDelta;
149 	header.Cat((const char *)&magic1, sizeof(dword));
150 	header.Cat((const char *)&magic2, sizeof(dword));
151 
152 	header << iv0;
153 
154 	qword sze = (qword) size;
155 	header.Cat((const char *) &sze, sizeof(sze));
156 	header = AESPadString(header, AES_BLOCK_SIZE);
157 
158 	StringBuffer outBuffer(header.GetLength());
159 
160 	for (int offs = 0; offs+AES_BLOCK_SIZE <= header.GetLength(); offs += AES_BLOCK_SIZE)
161 		AES_ecb_encrypt(((const unsigned char *) ~header)+offs, ((unsigned char *) ~outBuffer)+offs, &key, true);
162 
163 	encodedHeader = true;
164 	return outBuffer;
165 }
166 
GetEncryptedData()167 String AESEncoderStream::GetEncryptedData()
168 {
169 	if (blocksDone == blocks)
170 		return "";
171 
172 	qword overallBlocks = (qword) (data.GetLength()/AES_BLOCK_SIZE);
173 	int doBlocks = (int) min(overallBlocks, blocks-blocksDone);
174 	if (!doBlocks)
175 		return "";
176 
177 	int doSize = doBlocks*AES_BLOCK_SIZE;
178 	StringBuffer outData(doSize);
179 
180 	AES_cbc_encrypt((const unsigned char *) ~data, (unsigned char *) ~outData, (const unsigned long) doSize, &key, (unsigned char *) ~iv, true);
181 	if (doSize < data.GetLength())
182 		data.Remove(0, doSize);
183 	else
184 		data.Clear();
185 	blocksDone += doBlocks;
186 
187 	if (encodedHeader)
188 		return outData;
189 	else
190 		return (GetHeader()+String(outData));
191 }
192 
193 //----------------------------------------------------------------------------------------------
AESDecoderStream(const String & _key)194 AESDecoderStream::AESDecoderStream(const String &_key) // Deprecated in C++11:  throw (const char *)
195 	: size       (0L)
196 	, sizeDone   (0L)
197 	, iv         (AES_BLOCK_SIZE)
198 	, decodedHeader (false)
199 {
200 	AESInit();
201 
202 	if (_key.GetLength() != 16 && _key.GetLength() != 24 && _key.GetLength() != 32)
203 		throw t_("AESDecoderStream::ctor: Key must be 16, 24 or 32 bytes long");
204 	if (AES_set_decrypt_key((const unsigned char *) ~_key, _key.GetLength() << 3, &key))
205 		throw t_("AESDecoderStream::ctor: Could not setup AES key. OpenSSL problem?");
206 }
207 
AddData(const String & s)208 int AESDecoderStream::AddData(const String &s)
209 {
210 	if (!size)
211 	{
212 		data << s;
213 		int io = data.GetLength();
214 		return s.GetLength();
215 	}
216 
217 	qword sz = size & ~((qword) (AES_BLOCK_SIZE-1));
218 	if (size & (AES_BLOCK_SIZE-1))
219 		sz += AES_BLOCK_SIZE;
220 
221 	qword dl = (qword)data.GetLength();
222 	if (dl >= sz)
223 		return 0;
224 
225 	qword sl = (qword) s.GetLength();
226 	if (dl+sl < sz)
227 		data << s;
228 	else
229 	{
230 		sl = sz - dl;
231 		data << s.Left((int) sl);
232 	}
233 
234 	return (int) sl;
235 }
236 
GetDecryptedData()237 String AESDecoderStream::GetDecryptedData() // Deprecated in C++1:  throw (const char *)
238 {
239 	#pragma pack(push,1)
240 	struct AES_CONTAINER_HEADER
241 	{
242 		dword m1;
243 		dword m2;
244 		Upp::byte  iv[AES_BLOCK_SIZE];
245 		qword size;
246 	} header;
247 	#pragma pack(pop)
248 
249 	if (!decodedHeader)
250 	{
251 		if (data.GetLength() < sizeof(header))
252 			return "";
253 
254 		for (int offs = 0; offs+AES_BLOCK_SIZE <= sizeof(header); offs += AES_BLOCK_SIZE)
255 			AES_ecb_encrypt(((const unsigned char *) ~data)+offs, ((unsigned char *) &header)+offs, &key, false);
256 
257 		if (header.m1+header.m2 != AES_CONTAINER_DWORD_HEADER)
258 			throw t_("Wrong key!");
259 
260 		memcpy(~iv,  &(header.iv[0]), AES_BLOCK_SIZE);
261 		size = header.size;
262 
263 		data.Remove(0, sizeof(header));
264 		decodedHeader = true;
265 	}
266 
267 	dword doSize = data.GetLength();
268 	qword sizeLeft = size-sizeDone;
269 	if (((qword) doSize) > sizeLeft)
270 		doSize = (dword) sizeLeft;
271 	if (!doSize)
272 		return "";
273 
274 	dword extSize = doSize & (~(dword) (AES_BLOCK_SIZE-1));
275 	if (extSize && ((dword) data.GetLength()) >= doSize+AES_BLOCK_SIZE)
276 		doSize += AES_BLOCK_SIZE;
277 
278 	StringBuffer outData(doSize);
279 
280 	AES_cbc_encrypt((const unsigned char *) ~data, (unsigned char *) ~outData, (const unsigned long) doSize, &key, (unsigned char *) ~iv, false);
281 	data.Remove(0, doSize);
282 	sizeDone += doSize;
283 	return outData;
284 }
285 
286 //----------------------------------------------------------------------------------------------
287 const dword AES_CONTAINER_DWORD_HEADER = 0x377FEA9F;
288 
SHA256Bin(const char * key)289 String SHA256Bin(const char *key) {
290 	byte hash32[32];
291 	SHA256(hash32, key);
292 	return String(hash32, 32);
293 }