removed direct references to libssl in makefiles (because it is added by configure...
[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"
5039dede 26
b1e9b6b3
VK
27/**
28 * Constants
29 */
5039dede
AK
30#define KEY_BUFFER_SIZE 4096
31
b1e9b6b3
VK
32/**
33 * Supported ciphers. By default, we support all ciphers compiled
34 * into OpenSSL library.
35 */
e5390fb5 36static UINT32 s_supportedCiphers =
5039dede
AK
37#ifdef _WITH_ENCRYPTION
38#ifndef OPENSSL_NO_AES
43a6f3ca
VK
39 NXCP_SUPPORT_AES_256 |
40 NXCP_SUPPORT_AES_128 |
5039dede
AK
41#endif
42#ifndef OPENSSL_NO_BF
43a6f3ca
VK
43 NXCP_SUPPORT_BLOWFISH_256 |
44 NXCP_SUPPORT_BLOWFISH_128 |
5039dede
AK
45#endif
46#ifndef OPENSSL_NO_IDEA
43a6f3ca 47 NXCP_SUPPORT_IDEA |
5039dede
AK
48#endif
49#ifndef OPENSSL_NO_DES
43a6f3ca 50 NXCP_SUPPORT_3DES |
5039dede
AK
51#endif
52#endif /* _WITH_ENCRYPTION */
53 0;
54
b1e9b6b3
VK
55/**
56 * Static data
57 */
c1099678 58static WORD s_noEncryptionFlag = 0;
e4e091f0 59
5039dede
AK
60#ifdef _WITH_ENCRYPTION
61
bb586165 62extern "C" typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
6468147c 63static CIPHER_FUNC s_ciphers[NETXMS_MAX_CIPHERS] =
5039dede
AK
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
9e9d631e
VK
81 EVP_des_ede3_cbc,
82#else
83 NULL,
84#endif
85#ifndef OPENSSL_NO_AES
d772d0dd
VK
86 EVP_aes_128_cbc,
87#else
88 NULL,
89#endif
90#ifndef OPENSSL_NO_BF
91 EVP_bf_cbc
5039dede
AK
92#else
93 NULL
94#endif
95};
6468147c 96static const TCHAR *s_cipherNames[NETXMS_MAX_CIPHERS] = { _T("AES-256"), _T("Blowfish-256"), _T("IDEA"), _T("3DES"), _T("AES-128"), _T("Blowfish-128") };
6468147c 97static MUTEX *s_cryptoMutexList = NULL;
5039dede 98
b1e9b6b3
VK
99/**
100 * Locking callback for CRYPTO library
101 */
bb586165
VK
102#if defined(__SUNPRO_CC)
103extern "C"
104#endif
5039dede
AK
105static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
106{
107 if (nMode & CRYPTO_LOCK)
6468147c 108 MutexLock(s_cryptoMutexList[nLock]);
5039dede 109 else
6468147c 110 MutexUnlock(s_cryptoMutexList[nLock]);
5039dede
AK
111}
112
b1e9b6b3
VK
113/**
114 * ID callback for CRYPTO library
115 */
5039dede
AK
116#ifndef _WIN32
117
bb586165
VK
118#if defined(__SUNPRO_CC)
119extern "C"
120#endif
9e9d631e 121static unsigned long CryptoIdCallback()
5039dede
AK
122{
123 return (unsigned long)GetCurrentThreadId();
124}
125
126#endif
127
128#endif /* _WITH_ENCRYPTION */
129
b1e9b6b3
VK
130/**
131 * Initialize OpenSSL library
132 */
2df047f4 133bool LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
5039dede 134{
c1099678 135 s_noEncryptionFlag = htons(MF_DONT_ENCRYPT);
6468147c 136
5039dede
AK
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);
6468147c 145 s_cryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
5039dede 146 for(i = 0; i < CRYPTO_num_locks(); i++)
6468147c 147 s_cryptoMutexList[i] = MutexCreate();
5039dede
AK
148 CRYPTO_set_locking_callback(CryptoLockingCallback);
149#ifndef _WIN32
150 CRYPTO_set_id_callback(CryptoIdCallback);
151#endif /* _WIN32 */
6468147c
VK
152
153 // validate supported ciphers
2df047f4 154 nxlog_debug(1, _T("Validating ciphers"));
e5390fb5 155 s_supportedCiphers &= dwEnabledCiphers;
6468147c
VK
156 UINT32 cipherBit = 1;
157 for(i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
158 {
e5390fb5 159 if ((s_supportedCiphers & cipherBit) == 0)
ae8e3292 160 {
2df047f4 161 nxlog_debug(1, _T(" %s disabled (config)"), s_cipherNames[i]);
6468147c 162 continue;
ae8e3292 163 }
6468147c
VK
164 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
165 if (ctx != NULL)
166 {
167 delete ctx;
2df047f4 168 nxlog_debug(1, _T(" %s enabled"), s_cipherNames[i]);
6468147c
VK
169 }
170 else
171 {
e5390fb5 172 s_supportedCiphers &= ~cipherBit;
2df047f4 173 nxlog_debug(1, _T(" %s disabled (validation failed)"), s_cipherNames[i]);
6468147c
VK
174 }
175 }
176
2df047f4 177 nxlog_debug(1, _T("Crypto library initialized"));
6468147c
VK
178
179#else
2df047f4 180 nxlog_debug(1, _T("Crypto library will not be initialized because libnetxms was built without encryption support"));
5039dede 181#endif /* _WITH_ENCRYPTION */
bf6fb6c3 182 return true;
5039dede
AK
183}
184
b1e9b6b3
VK
185/**
186 * Get supported ciphers
187 */
e5390fb5 188UINT32 LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphers()
5039dede 189{
e5390fb5
VK
190 return s_supportedCiphers;
191}
192
193/**
194 * Get supported ciphers as text
195 */
196String LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphersAsText()
197{
198 String s;
070f2993 199#ifdef _WITH_ENCRYPTION
e5390fb5
VK
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 }
070f2993 216#endif
e5390fb5 217 return s;
5039dede
AK
218}
219
b1e9b6b3
VK
220/**
221 * Encrypt message
222 */
b368969c 223NXCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *NXCPEncryptMessage(NXCPEncryptionContext *pCtx, NXCP_MESSAGE *msg)
5039dede 224{
b368969c 225 return (pCtx != NULL) ? pCtx->encryptMessage(msg) : NULL;
5039dede
AK
226}
227
7aad6641
VK
228/**
229 * Decrypt message
230 */
bf6fb6c3 231bool LIBNETXMS_EXPORTABLE NXCPDecryptMessage(NXCPEncryptionContext *pCtx, NXCP_ENCRYPTED_MESSAGE *msg, BYTE *pDecryptionBuffer)
5039dede 232{
bf6fb6c3 233 return (pCtx != NULL) ? pCtx->decryptMessage(msg, pDecryptionBuffer) : false;
5039dede
AK
234}
235
b1e9b6b3
VK
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 */
b368969c 242UINT32 LIBNETXMS_EXPORTABLE SetupEncryptionContext(NXCPMessage *msg,
98abc9f1 243 NXCPEncryptionContext **ppCtx,
b368969c 244 NXCPMessage **ppResponse,
5039dede
AK
245 RSA *pPrivateKey, int nNXCPVersion)
246{
967893bb 247 UINT32 dwResult = RCC_NOT_IMPLEMENTED;
5039dede 248
98abc9f1 249 *ppCtx = NULL;
5039dede 250#ifdef _WITH_ENCRYPTION
b368969c 251 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 252 {
967893bb 253 UINT32 dwCiphers;
5039dede 254
b368969c
VK
255 *ppResponse = new NXCPMessage(nNXCPVersion);
256 (*ppResponse)->setCode(CMD_SESSION_KEY);
257 (*ppResponse)->setId(msg->getId());
4af351c7 258 (*ppResponse)->disableEncryption();
5039dede 259
e5390fb5 260 dwCiphers = msg->getFieldAsUInt32(VID_SUPPORTED_ENCRYPTION) & s_supportedCiphers;
5039dede
AK
261 if (dwCiphers == 0)
262 {
b368969c 263 (*ppResponse)->setField(VID_RCC, RCC_NO_CIPHERS);
5039dede
AK
264 dwResult = RCC_NO_CIPHERS;
265 }
266 else
267 {
98abc9f1
VK
268 BYTE *pBufPos, ucKeyBuffer[KEY_BUFFER_SIZE];
269 RSA *pServerKey;
5039dede 270
98abc9f1 271 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
0df15d50 272 if (*ppCtx != NULL)
5039dede 273 {
0df15d50
VK
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);
eae8c74c 292
0df15d50
VK
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 }
5039dede
AK
302 }
303 else
304 {
0df15d50
VK
305 (*ppResponse)->setField(VID_RCC, RCC_ENCRYPTION_ERROR);
306 dwResult = RCC_ENCRYPTION_ERROR;
5039dede
AK
307 }
308 }
309 }
b368969c 310 else if (msg->getCode() == CMD_SESSION_KEY)
5039dede 311 {
b368969c 312 dwResult = msg->getFieldAsUInt32(VID_RCC);
5039dede
AK
313 if (dwResult == RCC_SUCCESS)
314 {
b368969c 315 *ppCtx = NXCPEncryptionContext::create(msg, pPrivateKey);
98abc9f1
VK
316 if (*ppCtx == NULL)
317 {
318 dwResult = RCC_INVALID_SESSION_KEY;
319 }
5039dede
AK
320 }
321 }
322
323 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
324 {
98abc9f1 325 delete *ppCtx;
5039dede
AK
326 *ppCtx = NULL;
327 }
328#else
b368969c 329 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 330 {
b368969c 331 *ppResponse = new NXCPMessage(nNXCPVersion);
070f2993
VK
332 (*ppResponse)->setCode(CMD_SESSION_KEY);
333 (*ppResponse)->setId(msg->getId());
26de9040 334 (*ppResponse)->disableEncryption();
b368969c 335 (*ppResponse)->setField(VID_RCC, dwResult);
5039dede
AK
336 }
337#endif
338
339 return dwResult;
340}
341
b1e9b6b3
VK
342/**
343 * Prepare session key request message
344 */
b368969c 345void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(NXCPMessage *msg, RSA *pServerKey, bool useX509Format)
5039dede
AK
346{
347#ifdef _WITH_ENCRYPTION
348 int iLen;
349 BYTE *pKeyBuffer, *pBufPos;
350
b368969c 351 msg->setCode(CMD_REQUEST_SESSION_KEY);
e5390fb5 352 msg->setField(VID_SUPPORTED_ENCRYPTION, s_supportedCiphers);
5039dede 353
9e9d631e
VK
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 }
b368969c 368 msg->setField(VID_PUBLIC_KEY, pKeyBuffer, iLen);
5039dede
AK
369 free(pKeyBuffer);
370#endif
371}
372
7aad6641
VK
373/**
374 * Load RSA key(s) from file
375 */
5039dede
AK
376RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
377{
378#ifdef _WITH_ENCRYPTION
379 FILE *fp;
380 BYTE *pKeyBuffer, *pBufPos, hash[SHA1_DIGEST_SIZE];
967893bb 381 UINT32 dwLen;
5039dede
AK
382 RSA *pKey = NULL;
383
384 fp = _tfopen(pszKeyFile, _T("rb"));
385 if (fp != NULL)
386 {
967893bb 387 if (fread(&dwLen, 1, sizeof(UINT32), fp) == sizeof(UINT32) && dwLen < 10 * 1024)
5039dede
AK
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
7aad6641 395 if (fread(hash, 1, SHA1_DIGEST_SIZE, fp) == SHA1_DIGEST_SIZE)
5039dede 396 {
7aad6641
VK
397 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
398 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
5039dede 399 {
7aad6641
VK
400 pKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwLen);
401 if (pKey != NULL)
5039dede 402 {
7aad6641 403 if (d2i_RSAPrivateKey(&pKey, (OPENSSL_CONST BYTE **)&pBufPos,
967893bb 404 dwLen - CAST_FROM_POINTER((pBufPos - pKeyBuffer), UINT32)) == NULL)
7aad6641
VK
405 {
406 RSA_free(pKey);
407 pKey = NULL;
408 }
5039dede
AK
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
7aad6641
VK
424/**
425 * Create signature for message using certificate (MS CAPI version)
426 * Paraeters:
b368969c 427 * msg and dwMsgLen - message to sign and it's length
7aad6641
VK
428 * pCert - certificate
429 * pBuffer - output buffer
430 * dwBufSize - buffer size
431 * pdwSigLen - actual signature size
432 */
5039dede
AK
433#ifdef _WIN32
434
b368969c 435BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *msg, UINT32 dwMsgLen, const CERT_CONTEXT *pCert,
967893bb 436 BYTE *pBuffer, UINT32 dwBufSize, UINT32 *pdwSigLen)
5039dede
AK
437{
438 BOOL bFreeProv, bRet = FALSE;
439 DWORD i, j, dwLen, dwKeySpec;
440 HCRYPTPROV hProv;
441 HCRYPTHASH hHash;
442 BYTE *pTemp;
443
6468147c 444 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeProv))
5039dede
AK
445 {
446 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
447 {
b368969c 448 if (CryptHashData(hHash, msg, dwMsgLen, 0))
5039dede
AK
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
4e2debcc 468
7aad6641
VK
469/**
470 * Encrypt data block with ICE
471 */
4e2debcc
VK
472void 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);
4e2debcc
VK
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
7aad6641
VK
493/**
494 * Decrypt data block with ICE
495 */
4e2debcc
VK
496void 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);
4e2debcc
VK
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}
98abc9f1 516
7aad6641
VK
517/**
518 * Encryption context constructor
519 */
98abc9f1
VK
520NXCPEncryptionContext::NXCPEncryptionContext()
521{
e4e091f0 522 m_sessionKey = NULL;
2e78b160
VK
523 m_keyLength = 0;
524 m_cipher = -1;
e4e091f0 525#ifdef _WITH_ENCRYPTION
e6336a90
VK
526 EVP_CIPHER_CTX_init(&m_encryptor);
527 EVP_CIPHER_CTX_init(&m_decryptor);
db05c2af 528 m_encryptorLock = MutexCreate();
e4e091f0 529#endif
98abc9f1
VK
530}
531
7aad6641
VK
532/**
533 * Encryption context destructor
534 */
98abc9f1
VK
535NXCPEncryptionContext::~NXCPEncryptionContext()
536{
4effa0fb 537 free(m_sessionKey);
e4e091f0 538#ifdef _WITH_ENCRYPTION
e6336a90
VK
539 EVP_CIPHER_CTX_cleanup(&m_encryptor);
540 EVP_CIPHER_CTX_cleanup(&m_decryptor);
db05c2af 541 MutexDestroy(m_encryptorLock);
e4e091f0 542#endif
98abc9f1
VK
543}
544
7aad6641
VK
545/**
546 * Create encryption context from CMD_SESSION_KEY NXCP message
547 */
b368969c 548NXCPEncryptionContext *NXCPEncryptionContext::create(NXCPMessage *msg, RSA *privateKey)
98abc9f1 549{
e4cba530 550#ifdef _WITH_ENCRYPTION
98abc9f1 551 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
967893bb 552 UINT32 dwKeySize;
98abc9f1
VK
553 int nSize, nIVLen;
554 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
555
b368969c 556 int cipher = (int)msg->getFieldAsUInt16(VID_CIPHER);
e6336a90 557 if (ctx->initCipher(cipher))
98abc9f1 558 {
b368969c 559 if (ctx->m_keyLength == (int)msg->getFieldAsUInt16(VID_KEY_LENGTH))
98abc9f1 560 {
e6336a90
VK
561 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
562
563 // Decrypt session key
b368969c 564 dwKeySize = msg->getFieldAsBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
e6336a90
VK
565 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
566 if (nSize == ctx->m_keyLength)
567 {
568 memcpy(ctx->m_sessionKey, ucSessionKey, nSize);
569
570 // Decrypt session IV
b368969c 571 nIVLen = msg->getFieldAsUInt16(VID_IV_LENGTH);
e6336a90
VK
572 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
573 nIVLen = 16;
b368969c 574 dwKeySize = msg->getFieldAsBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
e6336a90
VK
575 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
576 if ((nSize == nIVLen) &&
6468147c 577 (nIVLen <= EVP_CIPHER_iv_length(s_ciphers[ctx->m_cipher]())))
e6336a90
VK
578 {
579 memcpy(ctx->m_iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
580 }
581 else
582 {
2df047f4 583 nxlog_debug(6, _T("NXCPEncryptionContext::create: IV decryption failed"));
e6336a90
VK
584 delete_and_null(ctx);
585 }
586 }
587 else
588 {
2df047f4 589 nxlog_debug(6, _T("NXCPEncryptionContext::create: session key decryption failed"));
e6336a90
VK
590 delete_and_null(ctx);
591 }
98abc9f1
VK
592 }
593 else
594 {
2df047f4 595 nxlog_debug(6, _T("NXCPEncryptionContext::create: key length mismatch (remote: %d local: %d)"), (int)msg->getFieldAsUInt16(VID_KEY_LENGTH), ctx->m_keyLength);
98abc9f1
VK
596 delete_and_null(ctx);
597 }
598 }
599 else
600 {
2df047f4 601 nxlog_debug(6, _T("NXCPEncryptionContext::create: initCipher(%d) call failed"), cipher);
98abc9f1
VK
602 delete_and_null(ctx);
603 }
604 return ctx;
e4cba530
VK
605#else
606 return new NXCPEncryptionContext;
607#endif
98abc9f1
VK
608}
609
e6336a90
VK
610/**
611 * Initialize cipher
612 */
613bool NXCPEncryptionContext::initCipher(int cipher)
614{
615#ifdef _WITH_ENCRYPTION
6468147c 616 if (s_ciphers[cipher] == NULL)
e6336a90
VK
617 return false; // Unsupported cipher
618
6468147c 619 if (!EVP_EncryptInit_ex(&m_encryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90 620 return false;
6468147c 621 if (!EVP_DecryptInit_ex(&m_decryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90
VK
622 return false;
623
624 switch(cipher)
625 {
43a6f3ca 626 case NXCP_CIPHER_AES_256:
e6336a90
VK
627 m_keyLength = 32;
628 break;
43a6f3ca 629 case NXCP_CIPHER_AES_128:
e6336a90
VK
630 m_keyLength = 16;
631 break;
43a6f3ca 632 case NXCP_CIPHER_BLOWFISH_256:
e6336a90
VK
633 m_keyLength = 32;
634 break;
43a6f3ca 635 case NXCP_CIPHER_BLOWFISH_128:
e6336a90
VK
636 m_keyLength = 16;
637 break;
43a6f3ca 638 case NXCP_CIPHER_IDEA:
e6336a90
VK
639 m_keyLength = 16;
640 break;
43a6f3ca 641 case NXCP_CIPHER_3DES:
e6336a90
VK
642 m_keyLength = 24;
643 break;
644 default:
645 return false;
646 }
647
648 if (!EVP_CIPHER_CTX_set_key_length(&m_encryptor, m_keyLength) || !EVP_CIPHER_CTX_set_key_length(&m_decryptor, m_keyLength))
649 return false;
650
6468147c
VK
651 // This check is needed because at least some OpenSSL versions return no error
652 // from EVP_CIPHER_CTX_set_key_length but still not change key length
653 if ((EVP_CIPHER_CTX_key_length(&m_encryptor) != m_keyLength) || (EVP_CIPHER_CTX_key_length(&m_decryptor) != m_keyLength))
654 return false;
655
e6336a90
VK
656 m_cipher = cipher;
657 return true;
658#else
659 return false;
660#endif
661}
662
7aad6641
VK
663/**
664 * Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
665 */
967893bb 666NXCPEncryptionContext *NXCPEncryptionContext::create(UINT32 ciphers)
98abc9f1
VK
667{
668 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
669
e4cba530 670#ifdef _WITH_ENCRYPTION
98abc9f1 671 // Select cipher
e6336a90
VK
672 bool selected = false;
673
43a6f3ca 674 if (ciphers & NXCP_SUPPORT_AES_256)
98abc9f1 675 {
43a6f3ca 676 selected = ctx->initCipher(NXCP_CIPHER_AES_256);
98abc9f1 677 }
e6336a90 678
43a6f3ca 679 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_256))
98abc9f1 680 {
43a6f3ca 681 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_256);
98abc9f1 682 }
e6336a90 683
43a6f3ca 684 if (!selected && (ciphers & NXCP_SUPPORT_AES_128))
9e9d631e 685 {
43a6f3ca 686 selected = ctx->initCipher(NXCP_CIPHER_AES_128);
9e9d631e 687 }
e6336a90 688
43a6f3ca 689 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_128))
d772d0dd 690 {
43a6f3ca 691 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_128);
d772d0dd 692 }
e6336a90 693
43a6f3ca 694 if (!selected && (ciphers & NXCP_SUPPORT_IDEA))
98abc9f1 695 {
43a6f3ca 696 selected = ctx->initCipher(NXCP_CIPHER_IDEA);
98abc9f1 697 }
e6336a90 698
43a6f3ca 699 if (!selected && (ciphers & NXCP_SUPPORT_3DES))
98abc9f1 700 {
43a6f3ca 701 selected = ctx->initCipher(NXCP_CIPHER_3DES);
e6336a90
VK
702 }
703
704 if (!selected)
705 {
706 delete ctx;
707 return NULL;
98abc9f1
VK
708 }
709
710 // Generate key
711 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
712 RAND_bytes(ctx->m_sessionKey, ctx->m_keyLength);
713 RAND_bytes(ctx->m_iv, EVP_MAX_IV_LENGTH);
e4cba530 714#endif
98abc9f1
VK
715
716 return ctx;
717}
e6336a90
VK
718
719/**
720 * Encrypt message
721 */
b368969c 722NXCP_ENCRYPTED_MESSAGE *NXCPEncryptionContext::encryptMessage(NXCP_MESSAGE *msg)
e6336a90 723{
b368969c
VK
724 if (msg->flags & s_noEncryptionFlag)
725 return (NXCP_ENCRYPTED_MESSAGE *)nx_memdup(msg, ntohl(msg->size));
e6336a90
VK
726
727#ifdef _WITH_ENCRYPTION
db05c2af
VK
728 MutexLock(m_encryptorLock);
729
e6336a90 730 if (!EVP_EncryptInit_ex(&m_encryptor, NULL, NULL, m_sessionKey, m_iv))
db05c2af
VK
731 {
732 MutexUnlock(m_encryptorLock);
e6336a90 733 return NULL;
db05c2af 734 }
e6336a90 735
b368969c 736 UINT32 msgSize = ntohl(msg->size);
6be0a20b
VK
737 NXCP_ENCRYPTED_MESSAGE *emsg =
738 (NXCP_ENCRYPTED_MESSAGE *)malloc(msgSize + NXCP_ENCRYPTION_HEADER_SIZE + EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&m_encryptor)) + 8);
b368969c
VK
739 emsg->code = htons(CMD_ENCRYPTED_MESSAGE);
740 emsg->reserved = 0;
e6336a90 741
6be0a20b 742 NXCP_ENCRYPTED_PAYLOAD_HEADER header;
e6336a90
VK
743 header.dwChecksum = htonl(CalculateCRC32((BYTE *)msg, msgSize, 0));
744 header.dwReserved = 0;
745
746 int dataSize;
6be0a20b 747 EVP_EncryptUpdate(&m_encryptor, emsg->data, &dataSize, (BYTE *)&header, NXCP_EH_ENCRYPTED_BYTES);
e6336a90 748 msgSize = dataSize;
b368969c 749 EVP_EncryptUpdate(&m_encryptor, emsg->data + msgSize, &dataSize, (BYTE *)msg, ntohl(msg->size));
e6336a90
VK
750 msgSize += dataSize;
751 EVP_EncryptFinal_ex(&m_encryptor, emsg->data + msgSize, &dataSize);
6be0a20b 752 msgSize += dataSize + NXCP_EH_UNENCRYPTED_BYTES;
e6336a90 753
db05c2af
VK
754 MutexUnlock(m_encryptorLock);
755
e6336a90
VK
756 if (msgSize % 8 != 0)
757 {
b368969c
VK
758 emsg->padding = (BYTE)(8 - (msgSize % 8));
759 msgSize += emsg->padding;
e6336a90
VK
760 }
761 else
762 {
b368969c 763 emsg->padding = 0;
e6336a90 764 }
b368969c 765 emsg->size = htonl(msgSize);
e6336a90
VK
766
767 return emsg;
768#else /* _WITH_ENCRYPTION */
769 return NULL;
770#endif
771}
772
773/**
774 * Decrypt message
775 */
6be0a20b 776bool NXCPEncryptionContext::decryptMessage(NXCP_ENCRYPTED_MESSAGE *msg, BYTE *decryptionBuffer)
e6336a90
VK
777{
778#ifdef _WITH_ENCRYPTION
779 if (!EVP_DecryptInit_ex(&m_decryptor, NULL, NULL, m_sessionKey, m_iv))
780 return false;
781
b368969c 782 msg->size = ntohl(msg->size);
e6336a90
VK
783 int dataSize;
784 EVP_DecryptUpdate(&m_decryptor, decryptionBuffer, &dataSize, msg->data,
b368969c 785 msg->size - NXCP_EH_UNENCRYPTED_BYTES - msg->padding);
e6336a90
VK
786 EVP_DecryptFinal(&m_decryptor, decryptionBuffer + dataSize, &dataSize);
787
b368969c
VK
788 NXCP_MESSAGE *clearMsg = (NXCP_MESSAGE *)(decryptionBuffer + NXCP_EH_ENCRYPTED_BYTES);
789 UINT32 msgSize = ntohl(clearMsg->size);
790 if (msgSize > msg->size)
e6336a90
VK
791 return false; // Message decrypted incorrectly, because it can't be larger than encrypted
792 UINT32 crc32 = CalculateCRC32((BYTE *)clearMsg, msgSize, 0);
6be0a20b 793 if (crc32 != ntohl(((NXCP_ENCRYPTED_PAYLOAD_HEADER *)decryptionBuffer)->dwChecksum))
e6336a90
VK
794 return false; // Bad checksum
795
796 memcpy(msg, clearMsg, msgSize);
797 return true;
798#else /* _WITH_ENCRYPTION */
799 return false;
800#endif
801}
981d246a
VK
802
803/**
804 * Generate random bytes
805 */
806void LIBNETXMS_EXPORTABLE GenerateRandomBytes(BYTE *buffer, size_t size)
807{
808#ifdef _WITH_ENCRYPTION
809 RAND_bytes(buffer, (int)size);
810#else
811 srand((unsigned int)time(NULL));
812 for(size_t i = 0; i < size; i++)
813 buffer[i] = (BYTE)(rand() % 256);
814#endif
815}