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