summaryrefslogtreecommitdiff
path: root/plugins/CryptoPP/src/cpp_svcs.cpp
blob: b99e0fc15e52d0c13835bdc14432a57a2c768ae9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#include "commonheaders.h"

const unsigned char IV[] = "SIMhell@MIRANDA!";

// encrypt string using KeyX, return encoded string as ASCII or NULL
LPSTR __cdecl cpp_encrypt(pCNTX ptr, LPCSTR szPlainMsg)
{
	ptr->error = ERROR_NONE;
	pSIMDATA p = (pSIMDATA)ptr->pdata;

	uint8_t dataflag = 0;
	size_t slen = strlen(szPlainMsg);

	LPSTR szMsg;
	if (ptr->features & FEATURES_GZIP) {
		size_t clen;
		szMsg = (LPSTR)cpp_gzip((uint8_t*)szPlainMsg, slen, clen);
		if (clen >= slen) {
			free(szMsg);
			szMsg = _strdup(szPlainMsg);
		}
		else {
			slen = clen;
			dataflag |= DATA_GZIP;
		}
	}
	else szMsg = _strdup(szPlainMsg);

	string ciphered;

	CBC_Mode<AES>::Encryption enc(p->KeyX, Tiger::DIGESTSIZE, IV);
	StreamTransformationFilter cbcEncryptor(enc, new StringSink(ciphered));

	cbcEncryptor.Put((uint8_t*)szMsg, slen);
	cbcEncryptor.MessageEnd();

	free(szMsg);

	unsigned clen = (unsigned)ciphered.length();
	if (ptr->features & FEATURES_CRC32) {
		uint8_t crc32[CRC32::DIGESTSIZE];
		memset(crc32, 0, sizeof(crc32));
		CRC32().CalculateDigest(crc32, (uint8_t*)ciphered.data(), clen);
		ciphered.insert(0, (LPSTR)&crc32, CRC32::DIGESTSIZE);
		ciphered.insert(0, (LPSTR)&clen, 2);
	}
	if (ptr->features & FEATURES_GZIP)
		ciphered.insert(0, (LPSTR)&dataflag, 1);

	clen = (unsigned)ciphered.length();
	mir_free(ptr->tmp);
	if (ptr->features & FEATURES_BASE64)
		ptr->tmp =  mir_base64_encode(ciphered.data(), clen);
	else {
		char *base16 = base16encode(ciphered.data(), clen);
		ptr->tmp = mir_strdup(base16);
		free(base16);
	}

	return ptr->tmp;
}


// decrypt string using KeyX, return decoded string as ASCII or NULL
LPSTR __cdecl cpp_decrypt(pCNTX ptr, LPCSTR szEncMsg)
{
	ptrA ciphered;

	try {
		ptr->error = ERROR_SEH;
		pSIMDATA p = (pSIMDATA)ptr->pdata;

		size_t clen = strlen(szEncMsg);

		if (ptr->features & FEATURES_BASE64)
			ciphered = (LPSTR)mir_base64_decode(szEncMsg, &clen);
		else
			ciphered = base16decode(szEncMsg, &clen);

		LPSTR bciphered = ciphered;

		uint8_t dataflag = 0;
		if (ptr->features & FEATURES_GZIP) {
			dataflag = *ciphered;
			bciphered++; clen--; // cut GZIP flag
		}
		if (ptr->features & FEATURES_CRC32) {
			int len = *(uint16_t*)bciphered;
			bciphered += 2; clen -= 2; // cut CRC32 length

			if ((int)clen - CRC32::DIGESTSIZE < len) { // mesage not full
#if defined(_DEBUG) || defined(NETLIB_LOG)
				Sent_NetLog("cpp_decrypt: error bad_len");
#endif
				ptr->error = ERROR_BAD_LEN;
				return nullptr;
			}

			uint8_t crc32[CRC32::DIGESTSIZE];
			memset(crc32, 0, sizeof(crc32));

			CRC32().CalculateDigest(crc32, (uint8_t*)(bciphered + CRC32::DIGESTSIZE), len);

			if (memcmp(crc32, bciphered, CRC32::DIGESTSIZE)) { // message is bad crc
#if defined(_DEBUG) || defined(NETLIB_LOG)
				Sent_NetLog("cpp_decrypt: error bad_crc");
#endif
				ptr->error = ERROR_BAD_CRC;
				return nullptr;
			}
			bciphered += CRC32::DIGESTSIZE; // cut CRC32 digest
			clen = len;
		}

		string unciphered;

		CBC_Mode<AES>::Decryption dec(p->KeyX, Tiger::DIGESTSIZE, IV);
		StreamTransformationFilter cbcDecryptor(dec, new StringSink(unciphered));

		cbcDecryptor.Put((uint8_t*)bciphered, clen);
		cbcDecryptor.MessageEnd();

		mir_free(ptr->tmp);

		if (dataflag & DATA_GZIP) {
			size_t clen2 = clen;
			LPSTR res = (LPSTR)cpp_gunzip((uint8_t*)unciphered.data(), unciphered.length(), clen2);
			ptr->tmp = mir_strndup(res, clen2);
			free(res);
		}
		else
			ptr->tmp = mir_strdup(unciphered.c_str());

		ptr->error = ERROR_NONE;
		return ptr->tmp;
	}
	catch (...) {
#if defined(_DEBUG) || defined(NETLIB_LOG)
		Sent_NetLog("cpp_decrypt: error seh");
#endif
		mir_free(ptr->tmp); ptr->tmp = nullptr;
		return nullptr;
	}
}


// encode message from ANSI into UTF8 if need
LPSTR __cdecl cpp_encodeA(HANDLE context, LPCSTR msg)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return nullptr;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) { ptr->error = ERROR_NO_KEYX; return nullptr; }

	LPSTR szNewMsg = nullptr;
	LPSTR szOldMsg = (LPSTR)msg;

	if (ptr->features & FEATURES_UTF8) {
		// ansi message: convert to unicode->utf-8 and encrypt.
		int slen = (int)strlen(szOldMsg) + 1;
		LPWSTR wstring = (LPWSTR)alloca(slen*sizeof(wchar_t));
		MultiByteToWideChar(CP_ACP, 0, szOldMsg, -1, wstring, slen*sizeof(wchar_t));
		// encrypt
		szNewMsg = cpp_encrypt(ptr, utf8encode(wstring));
	}
	else {
		// ansi message: encrypt.
		szNewMsg = cpp_encrypt(ptr, szOldMsg);
	}

	return szNewMsg;
}


// encode message from UTF8
LPSTR __cdecl cpp_encodeU(HANDLE context, LPCSTR msg)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return nullptr;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) { ptr->error = ERROR_NO_KEYX; return nullptr; }

	LPSTR szNewMsg = nullptr;
	LPSTR szOldMsg = (LPSTR)msg;

	if (ptr->features & FEATURES_UTF8) {
		// utf8 message: encrypt.
		szNewMsg = cpp_encrypt(ptr, szOldMsg);
	}
	else {
		// utf8 message: convert to ansi and encrypt.
		LPWSTR wstring = utf8decode(szOldMsg);
		int wlen = (int)wcslen(wstring) + 1;
		LPSTR astring = (LPSTR)alloca(wlen);
		WideCharToMultiByte(CP_ACP, 0, (LPWSTR)szOldMsg, -1, astring, wlen, nullptr, nullptr);
		szNewMsg = cpp_encrypt(ptr, astring);
	}

	return szNewMsg;
}

// encode message from UNICODE into UTF8 if need
LPSTR __cdecl cpp_encodeW(HANDLE context, LPWSTR msg)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return nullptr;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) { ptr->error = ERROR_NO_KEYX; return nullptr; }

	LPSTR szNewMsg = nullptr;
	LPSTR szOldMsg = (LPSTR)msg;

	if (ptr->features & FEATURES_UTF8) {
		// unicode message: convert to utf-8 and encrypt.
		szNewMsg = cpp_encrypt(ptr, utf8encode((LPWSTR)szOldMsg));
	}
	else {
		// unicode message: convert to ansi and encrypt.
		int wlen = (int)wcslen((LPWSTR)szOldMsg) + 1;
		LPSTR astring = (LPSTR)alloca(wlen);
		WideCharToMultiByte(CP_ACP, 0, (LPWSTR)szOldMsg, -1, astring, wlen, nullptr, nullptr);
		szNewMsg = cpp_encrypt(ptr, astring);
	}

	return szNewMsg;
}


// decode message from UTF8 if need, return ANSIzUCS2z
LPSTR __cdecl cpp_decode(HANDLE context, LPCSTR szEncMsg)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return nullptr;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) { ptr->error = ERROR_NO_KEYX; return nullptr; }

	LPSTR szNewMsg = nullptr;
	LPSTR szOldMsg = cpp_decrypt(ptr, szEncMsg);

	if (szOldMsg) {
		if (ptr->features & FEATURES_UTF8) {
			// utf8 message: convert to unicode -> ansii
			LPWSTR wstring = utf8decode(szOldMsg);
			int wlen = (int)wcslen(wstring) + 1;
			szNewMsg = (LPSTR)mir_alloc(wlen*(sizeof(wchar_t)+2));			// work.zy@gmail.com
			WideCharToMultiByte(CP_ACP, 0, wstring, -1, szNewMsg, wlen, nullptr, nullptr);
			memcpy(szNewMsg + strlen(szNewMsg) + 1, wstring, wlen*sizeof(wchar_t));	// work.zy@gmail.com
		}
		else {
			// ansi message: convert to unicode
			int slen = (int)strlen(szOldMsg) + 1;
			szNewMsg = (LPSTR)mir_alloc(slen*(sizeof(wchar_t)+1));
			memcpy(szNewMsg, szOldMsg, slen);
			wchar_t* wstring = (LPWSTR)alloca(slen*sizeof(wchar_t));
			MultiByteToWideChar(CP_ACP, 0, szOldMsg, -1, wstring, slen*sizeof(wchar_t));
			memcpy(szNewMsg + slen, wstring, slen*sizeof(wchar_t));
		}
	}
	mir_free(ptr->tmp);
	return ptr->tmp = szNewMsg;
}

// decode message return UTF8z
LPSTR __cdecl cpp_decodeU(HANDLE context, LPCSTR szEncMsg)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr)
		return nullptr;
	mir_free(ptr->tmp);
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) { ptr->error = ERROR_NO_KEYX; return nullptr; }

	LPSTR szNewMsg = nullptr;
	LPSTR szOldMsg = cpp_decrypt(ptr, szEncMsg);

	if (szOldMsg) {
		if (ptr->features & FEATURES_UTF8) {
			// utf8 message: copy
			szNewMsg = mir_strdup(szOldMsg);
		}
		else {
			// ansi message: convert to utf8
			int slen = (int)strlen(szOldMsg) + 1;
			LPWSTR wstring = (LPWSTR)alloca(slen*sizeof(wchar_t));
			MultiByteToWideChar(CP_ACP, 0, szOldMsg, -1, wstring, slen*sizeof(wchar_t));
			szNewMsg = mir_strdup(utf8encode(wstring));
		}
	}
	return ptr->tmp = szNewMsg;
}

int __cdecl cpp_encrypt_file(HANDLE context, LPCSTR file_in, LPCSTR file_out)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return 0;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) return 0;

	try {
		CBC_Mode<AES>::Encryption enc(p->KeyX, Tiger::DIGESTSIZE, IV);
		FileSource *f = new FileSource(file_in, true, new StreamTransformationFilter(enc, new FileSink(file_out)));
		delete f;
	}
	catch (...) {
		return 0;
	}
	return 1;
}

int __cdecl cpp_decrypt_file(HANDLE context, LPCSTR file_in, LPCSTR file_out)
{
	pCNTX ptr = get_context_on_id(context);
	if (!ptr) return 0;
	cpp_alloc_pdata(ptr); pSIMDATA p = (pSIMDATA)ptr->pdata;
	if (!p->KeyX) return 0;

	try {
		CBC_Mode<AES>::Decryption dec(p->KeyX, Tiger::DIGESTSIZE, IV);
		FileSource *f = new FileSource(file_in, true, new StreamTransformationFilter(dec, new FileSink(file_out)));
		delete f;
	}
	catch (...) {
		return 0;
	}
	return 1;
}