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