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 }