additional debug; file download completion called for aborted agent-to-client clientf...
[public/netxms.git] / src / libnetxms / crypto.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
e5390fb5 4** Copyright (C) 2003-2015 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
68f384ea
VK
7** it under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
68f384ea 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: crypto.cpp
21**
22**/
23
24#include "libnetxms.h"
4e2debcc 25#include "ice.h"
9c3bf7f4 26#include <nxcpapi.h>
5039dede 27
b1e9b6b3
VK
28/**
29 * Constants
30 */
5039dede
AK
31#define KEY_BUFFER_SIZE 4096
32
b1e9b6b3
VK
33/**
34 * Supported ciphers. By default, we support all ciphers compiled
35 * into OpenSSL library.
36 */
e5390fb5 37static UINT32 s_supportedCiphers =
5039dede
AK
38#ifdef _WITH_ENCRYPTION
39#ifndef OPENSSL_NO_AES
43a6f3ca
VK
40 NXCP_SUPPORT_AES_256 |
41 NXCP_SUPPORT_AES_128 |
5039dede
AK
42#endif
43#ifndef OPENSSL_NO_BF
43a6f3ca
VK
44 NXCP_SUPPORT_BLOWFISH_256 |
45 NXCP_SUPPORT_BLOWFISH_128 |
5039dede
AK
46#endif
47#ifndef OPENSSL_NO_IDEA
43a6f3ca 48 NXCP_SUPPORT_IDEA |
5039dede
AK
49#endif
50#ifndef OPENSSL_NO_DES
43a6f3ca 51 NXCP_SUPPORT_3DES |
5039dede
AK
52#endif
53#endif /* _WITH_ENCRYPTION */
54 0;
55
b1e9b6b3
VK
56/**
57 * Static data
58 */
c1099678 59static WORD s_noEncryptionFlag = 0;
9c3bf7f4 60static const TCHAR *s_cipherNames[NETXMS_MAX_CIPHERS] = { _T("AES-256"), _T("Blowfish-256"), _T("IDEA"), _T("3DES"), _T("AES-128"), _T("Blowfish-128") };
e4e091f0 61
9c3bf7f4 62#if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
5039dede 63
bb586165 64extern "C" typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
6468147c 65static CIPHER_FUNC s_ciphers[NETXMS_MAX_CIPHERS] =
5039dede
AK
66{
67#ifndef OPENSSL_NO_AES
68 EVP_aes_256_cbc,
69#else
70 NULL,
71#endif
72#ifndef OPENSSL_NO_BF
73 EVP_bf_cbc,
74#else
75 NULL,
76#endif
77#ifndef OPENSSL_NO_IDEA
78 EVP_idea_cbc,
79#else
80 NULL,
81#endif
82#ifndef OPENSSL_NO_DES
9e9d631e
VK
83 EVP_des_ede3_cbc,
84#else
85 NULL,
86#endif
87#ifndef OPENSSL_NO_AES
d772d0dd
VK
88 EVP_aes_128_cbc,
89#else
90 NULL,
91#endif
92#ifndef OPENSSL_NO_BF
93 EVP_bf_cbc
5039dede
AK
94#else
95 NULL
96#endif
97};
6468147c 98static MUTEX *s_cryptoMutexList = NULL;
5039dede 99
b1e9b6b3
VK
100/**
101 * Locking callback for CRYPTO library
102 */
bb586165
VK
103#if defined(__SUNPRO_CC)
104extern "C"
105#endif
5039dede
AK
106static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
107{
108 if (nMode & CRYPTO_LOCK)
6468147c 109 MutexLock(s_cryptoMutexList[nLock]);
5039dede 110 else
6468147c 111 MutexUnlock(s_cryptoMutexList[nLock]);
5039dede
AK
112}
113
b1e9b6b3
VK
114/**
115 * ID callback for CRYPTO library
116 */
5039dede
AK
117#ifndef _WIN32
118
bb586165
VK
119#if defined(__SUNPRO_CC)
120extern "C"
121#endif
9e9d631e 122static unsigned long CryptoIdCallback()
5039dede
AK
123{
124 return (unsigned long)GetCurrentThreadId();
125}
126
127#endif
128
9c3bf7f4
VK
129/**
130 * Create RSA key from binary representation
131 */
cce82c3a 132RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
9c3bf7f4
VK
133{
134 const BYTE *bp = data;
135 RSA *key = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&bp, (int)size);
136 if ((key != NULL) && withPrivate)
137 {
138 if (d2i_RSAPrivateKey(&key, (OPENSSL_CONST BYTE **)&bp, (int)(size - CAST_FROM_POINTER((bp - data), size_t))) == NULL)
139 {
140 RSA_free(key);
141 key = NULL;
142 }
143 }
144 return key;
145}
146
147/**
148 * Destroy RSA key
149 */
cce82c3a 150void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
9c3bf7f4
VK
151{
152 RSA_free(key);
153}
154
5039dede
AK
155#endif /* _WITH_ENCRYPTION */
156
9c3bf7f4
VK
157#if defined(_WITH_ENCRYPTION) && WITH_COMMONCRYPTO
158
159/**
160 * Create RSA key from binary representation
161 */
cce82c3a 162RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
9c3bf7f4
VK
163{
164 SecKeyCreateWithData(keyData, keyAttr);
165 return NULL;
166}
167
168/**
169 * Destroy RSA key
170 */
cce82c3a 171void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
9c3bf7f4
VK
172{
173 free(key);
174}
175
176#endif
177
b1e9b6b3
VK
178/**
179 * Initialize OpenSSL library
180 */
2df047f4 181bool LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
5039dede 182{
c1099678 183 s_noEncryptionFlag = htons(MF_DONT_ENCRYPT);
6468147c 184
9c3bf7f4 185#if _WITH_ENCRYPTION && WITH_OPENSSL
5039dede
AK
186 BYTE random[8192];
187 int i;
188
189 CRYPTO_malloc_init();
190 ERR_load_CRYPTO_strings();
191 OpenSSL_add_all_algorithms();
192 RAND_seed(random, 8192);
6468147c 193 s_cryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
5039dede 194 for(i = 0; i < CRYPTO_num_locks(); i++)
6468147c 195 s_cryptoMutexList[i] = MutexCreate();
5039dede
AK
196 CRYPTO_set_locking_callback(CryptoLockingCallback);
197#ifndef _WIN32
198 CRYPTO_set_id_callback(CryptoIdCallback);
199#endif /* _WIN32 */
6468147c
VK
200
201 // validate supported ciphers
2df047f4 202 nxlog_debug(1, _T("Validating ciphers"));
e5390fb5 203 s_supportedCiphers &= dwEnabledCiphers;
6468147c
VK
204 UINT32 cipherBit = 1;
205 for(i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
206 {
e5390fb5 207 if ((s_supportedCiphers & cipherBit) == 0)
ae8e3292 208 {
2df047f4 209 nxlog_debug(1, _T(" %s disabled (config)"), s_cipherNames[i]);
6468147c 210 continue;
ae8e3292 211 }
6468147c
VK
212 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
213 if (ctx != NULL)
214 {
215 delete ctx;
2df047f4 216 nxlog_debug(1, _T(" %s enabled"), s_cipherNames[i]);
6468147c
VK
217 }
218 else
219 {
e5390fb5 220 s_supportedCiphers &= ~cipherBit;
2df047f4 221 nxlog_debug(1, _T(" %s disabled (validation failed)"), s_cipherNames[i]);
6468147c
VK
222 }
223 }
224
2df047f4 225 nxlog_debug(1, _T("Crypto library initialized"));
9c3bf7f4
VK
226#elif _WITH_ENCRYPTION && WITH_COMMONCRYPTO
227 nxlog_debug(1, _T("Crypto library initialized"));
6468147c 228#else
2df047f4 229 nxlog_debug(1, _T("Crypto library will not be initialized because libnetxms was built without encryption support"));
5039dede 230#endif /* _WITH_ENCRYPTION */
bf6fb6c3 231 return true;
5039dede
AK
232}
233
b1e9b6b3
VK
234/**
235 * Get supported ciphers
236 */
e5390fb5 237UINT32 LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphers()
5039dede 238{
e5390fb5
VK
239 return s_supportedCiphers;
240}
241
242/**
243 * Get supported ciphers as text
244 */
245String LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphersAsText()
246{
247 String s;
070f2993 248#ifdef _WITH_ENCRYPTION
e5390fb5
VK
249 UINT32 cipherBit = 1;
250 for(int i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
251 {
252 if ((s_supportedCiphers & cipherBit) == 0)
253 {
254 continue;
255 }
256 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
257 if (ctx != NULL)
258 {
259 delete ctx;
260 if (s.length() > 0)
261 s.append(_T(", "));
262 s.append(s_cipherNames[i]);
263 }
264 }
070f2993 265#endif
e5390fb5 266 return s;
5039dede
AK
267}
268
b1e9b6b3
VK
269/**
270 * Encrypt message
271 */
b368969c 272NXCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *NXCPEncryptMessage(NXCPEncryptionContext *pCtx, NXCP_MESSAGE *msg)
5039dede 273{
b368969c 274 return (pCtx != NULL) ? pCtx->encryptMessage(msg) : NULL;
5039dede
AK
275}
276
7aad6641
VK
277/**
278 * Decrypt message
279 */
bf6fb6c3 280bool LIBNETXMS_EXPORTABLE NXCPDecryptMessage(NXCPEncryptionContext *pCtx, NXCP_ENCRYPTED_MESSAGE *msg, BYTE *pDecryptionBuffer)
5039dede 281{
bf6fb6c3 282 return (pCtx != NULL) ? pCtx->decryptMessage(msg, pDecryptionBuffer) : false;
5039dede
AK
283}
284
b1e9b6b3
VK
285/**
286 * Setup encryption context
287 * Function will determine is it called on initiator or responder side
288 * by message code. Initiator should provide it's private key,
289 * and responder should provide pointer to response message.
290 */
b368969c 291UINT32 LIBNETXMS_EXPORTABLE SetupEncryptionContext(NXCPMessage *msg,
98abc9f1 292 NXCPEncryptionContext **ppCtx,
b368969c 293 NXCPMessage **ppResponse,
5039dede
AK
294 RSA *pPrivateKey, int nNXCPVersion)
295{
967893bb 296 UINT32 dwResult = RCC_NOT_IMPLEMENTED;
5039dede 297
98abc9f1 298 *ppCtx = NULL;
5039dede 299#ifdef _WITH_ENCRYPTION
b368969c 300 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 301 {
967893bb 302 UINT32 dwCiphers;
5039dede 303
b368969c
VK
304 *ppResponse = new NXCPMessage(nNXCPVersion);
305 (*ppResponse)->setCode(CMD_SESSION_KEY);
306 (*ppResponse)->setId(msg->getId());
4af351c7 307 (*ppResponse)->disableEncryption();
5039dede 308
e5390fb5 309 dwCiphers = msg->getFieldAsUInt32(VID_SUPPORTED_ENCRYPTION) & s_supportedCiphers;
5039dede
AK
310 if (dwCiphers == 0)
311 {
b368969c 312 (*ppResponse)->setField(VID_RCC, RCC_NO_CIPHERS);
5039dede
AK
313 dwResult = RCC_NO_CIPHERS;
314 }
315 else
316 {
3c15eedb 317 BYTE ucKeyBuffer[KEY_BUFFER_SIZE];
98abc9f1 318 RSA *pServerKey;
5039dede 319
98abc9f1 320 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
0df15d50 321 if (*ppCtx != NULL)
5039dede 322 {
0df15d50 323 // Encrypt key
9c3bf7f4
VK
324 size_t size = msg->getFieldAsBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
325 pServerKey = RSAKeyFromData(ucKeyBuffer, size, false);
0df15d50
VK
326 if (pServerKey != NULL)
327 {
328 (*ppResponse)->setField(VID_RCC, RCC_SUCCESS);
329
330 size = RSA_public_encrypt((*ppCtx)->getKeyLength(), (*ppCtx)->getSessionKey(), ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
331 (*ppResponse)->setField(VID_SESSION_KEY, ucKeyBuffer, (UINT32)size);
332 (*ppResponse)->setField(VID_KEY_LENGTH, (WORD)(*ppCtx)->getKeyLength());
333
334 int ivLength = EVP_CIPHER_iv_length(s_ciphers[(*ppCtx)->getCipher()]());
335 if ((ivLength <= 0) || (ivLength > EVP_MAX_IV_LENGTH))
336 ivLength = EVP_MAX_IV_LENGTH;
337 size = RSA_public_encrypt(ivLength, (*ppCtx)->getIV(), ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
338 (*ppResponse)->setField(VID_SESSION_IV, ucKeyBuffer, (UINT32)size);
339 (*ppResponse)->setField(VID_IV_LENGTH, (WORD)ivLength);
eae8c74c 340
0df15d50
VK
341 (*ppResponse)->setField(VID_CIPHER, (WORD)(*ppCtx)->getCipher());
342 RSA_free(pServerKey);
343 dwResult = RCC_SUCCESS;
344 }
345 else
346 {
347 (*ppResponse)->setField(VID_RCC, RCC_INVALID_PUBLIC_KEY);
348 dwResult = RCC_INVALID_PUBLIC_KEY;
349 }
5039dede
AK
350 }
351 else
352 {
0df15d50
VK
353 (*ppResponse)->setField(VID_RCC, RCC_ENCRYPTION_ERROR);
354 dwResult = RCC_ENCRYPTION_ERROR;
5039dede
AK
355 }
356 }
357 }
b368969c 358 else if (msg->getCode() == CMD_SESSION_KEY)
5039dede 359 {
b368969c 360 dwResult = msg->getFieldAsUInt32(VID_RCC);
5039dede
AK
361 if (dwResult == RCC_SUCCESS)
362 {
b368969c 363 *ppCtx = NXCPEncryptionContext::create(msg, pPrivateKey);
98abc9f1
VK
364 if (*ppCtx == NULL)
365 {
366 dwResult = RCC_INVALID_SESSION_KEY;
367 }
5039dede
AK
368 }
369 }
370
371 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
372 {
98abc9f1 373 delete *ppCtx;
5039dede
AK
374 *ppCtx = NULL;
375 }
376#else
b368969c 377 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 378 {
b368969c 379 *ppResponse = new NXCPMessage(nNXCPVersion);
070f2993
VK
380 (*ppResponse)->setCode(CMD_SESSION_KEY);
381 (*ppResponse)->setId(msg->getId());
26de9040 382 (*ppResponse)->disableEncryption();
b368969c 383 (*ppResponse)->setField(VID_RCC, dwResult);
5039dede
AK
384 }
385#endif
386
387 return dwResult;
388}
389
b1e9b6b3
VK
390/**
391 * Prepare session key request message
392 */
b368969c 393void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(NXCPMessage *msg, RSA *pServerKey, bool useX509Format)
5039dede
AK
394{
395#ifdef _WITH_ENCRYPTION
396 int iLen;
397 BYTE *pKeyBuffer, *pBufPos;
398
b368969c 399 msg->setCode(CMD_REQUEST_SESSION_KEY);
e5390fb5 400 msg->setField(VID_SUPPORTED_ENCRYPTION, s_supportedCiphers);
5039dede 401
9e9d631e
VK
402 if (useX509Format)
403 {
404 iLen = i2d_RSA_PUBKEY(pServerKey, NULL);
405 pKeyBuffer = (BYTE *)malloc(iLen);
406 pBufPos = pKeyBuffer;
407 i2d_RSA_PUBKEY(pServerKey, &pBufPos);
408 }
409 else
410 {
411 iLen = i2d_RSAPublicKey(pServerKey, NULL);
412 pKeyBuffer = (BYTE *)malloc(iLen);
413 pBufPos = pKeyBuffer;
414 i2d_RSAPublicKey(pServerKey, &pBufPos);
415 }
b368969c 416 msg->setField(VID_PUBLIC_KEY, pKeyBuffer, iLen);
5039dede
AK
417 free(pKeyBuffer);
418#endif
419}
420
7aad6641
VK
421/**
422 * Load RSA key(s) from file
423 */
5039dede
AK
424RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
425{
426#ifdef _WITH_ENCRYPTION
5039dede 427 RSA *pKey = NULL;
9c3bf7f4 428 FILE *fp = _tfopen(pszKeyFile, _T("rb"));
5039dede
AK
429 if (fp != NULL)
430 {
9c3bf7f4 431 UINT32 dwLen;
967893bb 432 if (fread(&dwLen, 1, sizeof(UINT32), fp) == sizeof(UINT32) && dwLen < 10 * 1024)
5039dede 433 {
9c3bf7f4 434 BYTE *pKeyBuffer = (BYTE *)malloc(dwLen);
5039dede
AK
435 if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
436 {
9c3bf7f4 437 BYTE hash[SHA1_DIGEST_SIZE];
7aad6641 438 if (fread(hash, 1, SHA1_DIGEST_SIZE, fp) == SHA1_DIGEST_SIZE)
5039dede 439 {
9c3bf7f4 440 BYTE hash2[SHA1_DIGEST_SIZE];
7aad6641
VK
441 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
442 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
5039dede 443 {
9c3bf7f4 444 pKey = RSAKeyFromData(pKeyBuffer, dwLen, true);
5039dede
AK
445 }
446 }
447 }
448 free(pKeyBuffer);
449 }
450 fclose(fp);
451 }
5039dede
AK
452 return pKey;
453#else
454 return NULL;
455#endif
456}
457
7aad6641
VK
458/**
459 * Create signature for message using certificate (MS CAPI version)
460 * Paraeters:
b368969c 461 * msg and dwMsgLen - message to sign and it's length
7aad6641
VK
462 * pCert - certificate
463 * pBuffer - output buffer
464 * dwBufSize - buffer size
465 * pdwSigLen - actual signature size
466 */
5039dede
AK
467#ifdef _WIN32
468
b368969c 469BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *msg, UINT32 dwMsgLen, const CERT_CONTEXT *pCert,
967893bb 470 BYTE *pBuffer, UINT32 dwBufSize, UINT32 *pdwSigLen)
5039dede
AK
471{
472 BOOL bFreeProv, bRet = FALSE;
473 DWORD i, j, dwLen, dwKeySpec;
474 HCRYPTPROV hProv;
475 HCRYPTHASH hHash;
476 BYTE *pTemp;
477
6468147c 478 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeProv))
5039dede
AK
479 {
480 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
481 {
b368969c 482 if (CryptHashData(hHash, msg, dwMsgLen, 0))
5039dede
AK
483 {
484 dwLen = dwBufSize;
485 pTemp = (BYTE *)malloc(dwBufSize);;
486 bRet = CryptSignHash(hHash, dwKeySpec, NULL, 0, pTemp, &dwLen);
487 *pdwSigLen = dwLen;
488 // we have to reverse the byte-order in the result from CryptSignHash()
489 for(i = 0, j = dwLen - 1; i < dwLen; i++, j--)
490 pBuffer[i] = pTemp[j];
491 }
492 CryptDestroyHash(hHash);
493 }
494
495 if (bFreeProv)
496 CryptReleaseContext(hProv, 0);
497 }
498 return bRet;
499}
500
501#endif
4e2debcc 502
7aad6641
VK
503/**
504 * Encrypt data block with ICE
505 */
4e2debcc
VK
506void LIBNETXMS_EXPORTABLE ICEEncryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
507{
508 ICE_KEY *ice = ice_key_create(1);
509 ice_key_set(ice, key);
510
511 int stopPos = inLen - (inLen % 8);
4e2debcc
VK
512 for(int pos = 0; pos < stopPos; pos += 8)
513 ice_key_encrypt(ice, &in[pos], &out[pos]);
514
515 if (stopPos < inLen)
516 {
517 BYTE plainText[8], encrypted[8];
518
519 memcpy(plainText, &in[stopPos], inLen - stopPos);
520 ice_key_encrypt(ice, plainText, encrypted);
521 memcpy(&out[stopPos], encrypted, inLen - stopPos);
522 }
523
524 ice_key_destroy(ice);
525}
526
7aad6641
VK
527/**
528 * Decrypt data block with ICE
529 */
4e2debcc
VK
530void LIBNETXMS_EXPORTABLE ICEDecryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
531{
532 ICE_KEY *ice = ice_key_create(1);
533 ice_key_set(ice, key);
534
535 int stopPos = inLen - (inLen % 8);
4e2debcc
VK
536 for(int pos = 0; pos < stopPos; pos += 8)
537 ice_key_decrypt(ice, &in[pos], &out[pos]);
538
539 if (stopPos < inLen)
540 {
541 BYTE plainText[8], encrypted[8];
542
543 memcpy(encrypted, &in[stopPos], inLen - stopPos);
544 ice_key_decrypt(ice, encrypted, plainText);
545 memcpy(&out[stopPos], plainText, inLen - stopPos);
546 }
547
548 ice_key_destroy(ice);
549}
98abc9f1 550
7aad6641
VK
551/**
552 * Encryption context constructor
553 */
98abc9f1
VK
554NXCPEncryptionContext::NXCPEncryptionContext()
555{
e4e091f0 556 m_sessionKey = NULL;
2e78b160
VK
557 m_keyLength = 0;
558 m_cipher = -1;
e4e091f0 559#ifdef _WITH_ENCRYPTION
e6336a90
VK
560 EVP_CIPHER_CTX_init(&m_encryptor);
561 EVP_CIPHER_CTX_init(&m_decryptor);
db05c2af 562 m_encryptorLock = MutexCreate();
e4e091f0 563#endif
98abc9f1
VK
564}
565
7aad6641
VK
566/**
567 * Encryption context destructor
568 */
98abc9f1
VK
569NXCPEncryptionContext::~NXCPEncryptionContext()
570{
4effa0fb 571 free(m_sessionKey);
e4e091f0 572#ifdef _WITH_ENCRYPTION
e6336a90
VK
573 EVP_CIPHER_CTX_cleanup(&m_encryptor);
574 EVP_CIPHER_CTX_cleanup(&m_decryptor);
db05c2af 575 MutexDestroy(m_encryptorLock);
e4e091f0 576#endif
98abc9f1
VK
577}
578
7aad6641
VK
579/**
580 * Create encryption context from CMD_SESSION_KEY NXCP message
581 */
b368969c 582NXCPEncryptionContext *NXCPEncryptionContext::create(NXCPMessage *msg, RSA *privateKey)
98abc9f1 583{
e4cba530 584#ifdef _WITH_ENCRYPTION
98abc9f1 585 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
967893bb 586 UINT32 dwKeySize;
98abc9f1
VK
587 int nSize, nIVLen;
588 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
589
b368969c 590 int cipher = (int)msg->getFieldAsUInt16(VID_CIPHER);
e6336a90 591 if (ctx->initCipher(cipher))
98abc9f1 592 {
b368969c 593 if (ctx->m_keyLength == (int)msg->getFieldAsUInt16(VID_KEY_LENGTH))
98abc9f1 594 {
e6336a90
VK
595 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
596
597 // Decrypt session key
b368969c 598 dwKeySize = msg->getFieldAsBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
e6336a90
VK
599 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
600 if (nSize == ctx->m_keyLength)
601 {
602 memcpy(ctx->m_sessionKey, ucSessionKey, nSize);
603
604 // Decrypt session IV
b368969c 605 nIVLen = msg->getFieldAsUInt16(VID_IV_LENGTH);
e6336a90
VK
606 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
607 nIVLen = 16;
b368969c 608 dwKeySize = msg->getFieldAsBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
e6336a90
VK
609 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
610 if ((nSize == nIVLen) &&
6468147c 611 (nIVLen <= EVP_CIPHER_iv_length(s_ciphers[ctx->m_cipher]())))
e6336a90
VK
612 {
613 memcpy(ctx->m_iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
614 }
615 else
616 {
2df047f4 617 nxlog_debug(6, _T("NXCPEncryptionContext::create: IV decryption failed"));
e6336a90
VK
618 delete_and_null(ctx);
619 }
620 }
621 else
622 {
2df047f4 623 nxlog_debug(6, _T("NXCPEncryptionContext::create: session key decryption failed"));
e6336a90
VK
624 delete_and_null(ctx);
625 }
98abc9f1
VK
626 }
627 else
628 {
2df047f4 629 nxlog_debug(6, _T("NXCPEncryptionContext::create: key length mismatch (remote: %d local: %d)"), (int)msg->getFieldAsUInt16(VID_KEY_LENGTH), ctx->m_keyLength);
98abc9f1
VK
630 delete_and_null(ctx);
631 }
632 }
633 else
634 {
2df047f4 635 nxlog_debug(6, _T("NXCPEncryptionContext::create: initCipher(%d) call failed"), cipher);
98abc9f1
VK
636 delete_and_null(ctx);
637 }
638 return ctx;
e4cba530
VK
639#else
640 return new NXCPEncryptionContext;
641#endif
98abc9f1
VK
642}
643
e6336a90
VK
644/**
645 * Initialize cipher
646 */
647bool NXCPEncryptionContext::initCipher(int cipher)
648{
649#ifdef _WITH_ENCRYPTION
6468147c 650 if (s_ciphers[cipher] == NULL)
e6336a90
VK
651 return false; // Unsupported cipher
652
6468147c 653 if (!EVP_EncryptInit_ex(&m_encryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90 654 return false;
6468147c 655 if (!EVP_DecryptInit_ex(&m_decryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90
VK
656 return false;
657
658 switch(cipher)
659 {
43a6f3ca 660 case NXCP_CIPHER_AES_256:
e6336a90
VK
661 m_keyLength = 32;
662 break;
43a6f3ca 663 case NXCP_CIPHER_AES_128:
e6336a90
VK
664 m_keyLength = 16;
665 break;
43a6f3ca 666 case NXCP_CIPHER_BLOWFISH_256:
e6336a90
VK
667 m_keyLength = 32;
668 break;
43a6f3ca 669 case NXCP_CIPHER_BLOWFISH_128:
e6336a90
VK
670 m_keyLength = 16;
671 break;
43a6f3ca 672 case NXCP_CIPHER_IDEA:
e6336a90
VK
673 m_keyLength = 16;
674 break;
43a6f3ca 675 case NXCP_CIPHER_3DES:
e6336a90
VK
676 m_keyLength = 24;
677 break;
678 default:
679 return false;
680 }
681
682 if (!EVP_CIPHER_CTX_set_key_length(&m_encryptor, m_keyLength) || !EVP_CIPHER_CTX_set_key_length(&m_decryptor, m_keyLength))
683 return false;
684
6468147c
VK
685 // This check is needed because at least some OpenSSL versions return no error
686 // from EVP_CIPHER_CTX_set_key_length but still not change key length
687 if ((EVP_CIPHER_CTX_key_length(&m_encryptor) != m_keyLength) || (EVP_CIPHER_CTX_key_length(&m_decryptor) != m_keyLength))
688 return false;
689
e6336a90
VK
690 m_cipher = cipher;
691 return true;
692#else
693 return false;
694#endif
695}
696
7aad6641
VK
697/**
698 * Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
699 */
967893bb 700NXCPEncryptionContext *NXCPEncryptionContext::create(UINT32 ciphers)
98abc9f1
VK
701{
702 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
703
e4cba530 704#ifdef _WITH_ENCRYPTION
98abc9f1 705 // Select cipher
e6336a90
VK
706 bool selected = false;
707
43a6f3ca 708 if (ciphers & NXCP_SUPPORT_AES_256)
98abc9f1 709 {
43a6f3ca 710 selected = ctx->initCipher(NXCP_CIPHER_AES_256);
98abc9f1 711 }
e6336a90 712
43a6f3ca 713 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_256))
98abc9f1 714 {
43a6f3ca 715 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_256);
98abc9f1 716 }
e6336a90 717
43a6f3ca 718 if (!selected && (ciphers & NXCP_SUPPORT_AES_128))
9e9d631e 719 {
43a6f3ca 720 selected = ctx->initCipher(NXCP_CIPHER_AES_128);
9e9d631e 721 }
e6336a90 722
43a6f3ca 723 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_128))
d772d0dd 724 {
43a6f3ca 725 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_128);
d772d0dd 726 }
e6336a90 727
43a6f3ca 728 if (!selected && (ciphers & NXCP_SUPPORT_IDEA))
98abc9f1 729 {
43a6f3ca 730 selected = ctx->initCipher(NXCP_CIPHER_IDEA);
98abc9f1 731 }
e6336a90 732
43a6f3ca 733 if (!selected && (ciphers & NXCP_SUPPORT_3DES))
98abc9f1 734 {
43a6f3ca 735 selected = ctx->initCipher(NXCP_CIPHER_3DES);
e6336a90
VK
736 }
737
738 if (!selected)
739 {
740 delete ctx;
741 return NULL;
98abc9f1
VK
742 }
743
744 // Generate key
745 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
746 RAND_bytes(ctx->m_sessionKey, ctx->m_keyLength);
747 RAND_bytes(ctx->m_iv, EVP_MAX_IV_LENGTH);
e4cba530 748#endif
98abc9f1
VK
749
750 return ctx;
751}
e6336a90
VK
752
753/**
754 * Encrypt message
755 */
b368969c 756NXCP_ENCRYPTED_MESSAGE *NXCPEncryptionContext::encryptMessage(NXCP_MESSAGE *msg)
e6336a90 757{
b368969c
VK
758 if (msg->flags & s_noEncryptionFlag)
759 return (NXCP_ENCRYPTED_MESSAGE *)nx_memdup(msg, ntohl(msg->size));
e6336a90
VK
760
761#ifdef _WITH_ENCRYPTION
db05c2af
VK
762 MutexLock(m_encryptorLock);
763
e6336a90 764 if (!EVP_EncryptInit_ex(&m_encryptor, NULL, NULL, m_sessionKey, m_iv))
db05c2af
VK
765 {
766 MutexUnlock(m_encryptorLock);
e6336a90 767 return NULL;
db05c2af 768 }
e6336a90 769
b368969c 770 UINT32 msgSize = ntohl(msg->size);
6be0a20b
VK
771 NXCP_ENCRYPTED_MESSAGE *emsg =
772 (NXCP_ENCRYPTED_MESSAGE *)malloc(msgSize + NXCP_ENCRYPTION_HEADER_SIZE + EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&m_encryptor)) + 8);
b368969c
VK
773 emsg->code = htons(CMD_ENCRYPTED_MESSAGE);
774 emsg->reserved = 0;
e6336a90 775
6be0a20b 776 NXCP_ENCRYPTED_PAYLOAD_HEADER header;
e6336a90
VK
777 header.dwChecksum = htonl(CalculateCRC32((BYTE *)msg, msgSize, 0));
778 header.dwReserved = 0;
779
780 int dataSize;
6be0a20b 781 EVP_EncryptUpdate(&m_encryptor, emsg->data, &dataSize, (BYTE *)&header, NXCP_EH_ENCRYPTED_BYTES);
e6336a90 782 msgSize = dataSize;
b368969c 783 EVP_EncryptUpdate(&m_encryptor, emsg->data + msgSize, &dataSize, (BYTE *)msg, ntohl(msg->size));
e6336a90
VK
784 msgSize += dataSize;
785 EVP_EncryptFinal_ex(&m_encryptor, emsg->data + msgSize, &dataSize);
6be0a20b 786 msgSize += dataSize + NXCP_EH_UNENCRYPTED_BYTES;
e6336a90 787
db05c2af
VK
788 MutexUnlock(m_encryptorLock);
789
e6336a90
VK
790 if (msgSize % 8 != 0)
791 {
b368969c
VK
792 emsg->padding = (BYTE)(8 - (msgSize % 8));
793 msgSize += emsg->padding;
e6336a90
VK
794 }
795 else
796 {
b368969c 797 emsg->padding = 0;
e6336a90 798 }
b368969c 799 emsg->size = htonl(msgSize);
e6336a90
VK
800
801 return emsg;
802#else /* _WITH_ENCRYPTION */
803 return NULL;
804#endif
805}
806
807/**
808 * Decrypt message
809 */
6be0a20b 810bool NXCPEncryptionContext::decryptMessage(NXCP_ENCRYPTED_MESSAGE *msg, BYTE *decryptionBuffer)
e6336a90
VK
811{
812#ifdef _WITH_ENCRYPTION
813 if (!EVP_DecryptInit_ex(&m_decryptor, NULL, NULL, m_sessionKey, m_iv))
814 return false;
815
b368969c 816 msg->size = ntohl(msg->size);
e6336a90
VK
817 int dataSize;
818 EVP_DecryptUpdate(&m_decryptor, decryptionBuffer, &dataSize, msg->data,
b368969c 819 msg->size - NXCP_EH_UNENCRYPTED_BYTES - msg->padding);
e6336a90
VK
820 EVP_DecryptFinal(&m_decryptor, decryptionBuffer + dataSize, &dataSize);
821
b368969c
VK
822 NXCP_MESSAGE *clearMsg = (NXCP_MESSAGE *)(decryptionBuffer + NXCP_EH_ENCRYPTED_BYTES);
823 UINT32 msgSize = ntohl(clearMsg->size);
824 if (msgSize > msg->size)
e6336a90
VK
825 return false; // Message decrypted incorrectly, because it can't be larger than encrypted
826 UINT32 crc32 = CalculateCRC32((BYTE *)clearMsg, msgSize, 0);
6be0a20b 827 if (crc32 != ntohl(((NXCP_ENCRYPTED_PAYLOAD_HEADER *)decryptionBuffer)->dwChecksum))
e6336a90
VK
828 return false; // Bad checksum
829
830 memcpy(msg, clearMsg, msgSize);
831 return true;
832#else /* _WITH_ENCRYPTION */
833 return false;
834#endif
835}
981d246a
VK
836
837/**
838 * Generate random bytes
839 */
840void LIBNETXMS_EXPORTABLE GenerateRandomBytes(BYTE *buffer, size_t size)
841{
842#ifdef _WITH_ENCRYPTION
843 RAND_bytes(buffer, (int)size);
844#else
845 srand((unsigned int)time(NULL));
846 for(size_t i = 0; i < size; i++)
847 buffer[i] = (BYTE)(rand() % 256);
848#endif
849}