fixed incorrect sprintf format usage; fixed access to uninitialized memory in DB...
[public/netxms.git] / src / libnetxms / crypto.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
198745dd 4** Copyright (C) 2003-2017 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};
5929b1d7
VK
98
99#if OPENSSL_VERSION_NUMBER < 0x10100000L
6468147c 100static MUTEX *s_cryptoMutexList = NULL;
5039dede 101
b1e9b6b3
VK
102/**
103 * Locking callback for CRYPTO library
104 */
bb586165
VK
105#if defined(__SUNPRO_CC)
106extern "C"
107#endif
5039dede
AK
108static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
109{
110 if (nMode & CRYPTO_LOCK)
6468147c 111 MutexLock(s_cryptoMutexList[nLock]);
5039dede 112 else
6468147c 113 MutexUnlock(s_cryptoMutexList[nLock]);
5039dede
AK
114}
115
5929b1d7
VK
116#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
117
b1e9b6b3
VK
118/**
119 * ID callback for CRYPTO library
120 */
5039dede
AK
121#ifndef _WIN32
122
bb586165
VK
123#if defined(__SUNPRO_CC)
124extern "C"
125#endif
9e9d631e 126static unsigned long CryptoIdCallback()
5039dede
AK
127{
128 return (unsigned long)GetCurrentThreadId();
129}
130
131#endif
132
9c3bf7f4
VK
133/**
134 * Create RSA key from binary representation
135 */
cce82c3a 136RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
9c3bf7f4
VK
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 */
cce82c3a 154void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
9c3bf7f4
VK
155{
156 RSA_free(key);
157}
158
5039dede
AK
159#endif /* _WITH_ENCRYPTION */
160
9c3bf7f4
VK
161#if defined(_WITH_ENCRYPTION) && WITH_COMMONCRYPTO
162
163/**
164 * Create RSA key from binary representation
165 */
cce82c3a 166RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
9c3bf7f4
VK
167{
168 SecKeyCreateWithData(keyData, keyAttr);
169 return NULL;
170}
171
172/**
173 * Destroy RSA key
174 */
cce82c3a 175void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
9c3bf7f4
VK
176{
177 free(key);
178}
179
180#endif
181
b1e9b6b3
VK
182/**
183 * Initialize OpenSSL library
184 */
2df047f4 185bool LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
5039dede 186{
c1099678 187 s_noEncryptionFlag = htons(MF_DONT_ENCRYPT);
6468147c 188
9c3bf7f4 189#if _WITH_ENCRYPTION && WITH_OPENSSL
5039dede
AK
190 BYTE random[8192];
191 int i;
192
9c144154 193#if OPENSSL_VERSION_NUMBER < 0x10100000L
5039dede 194 CRYPTO_malloc_init();
5929b1d7 195 OpenSSL_add_all_algorithms();
9c144154 196#endif
5929b1d7 197
5039dede 198 ERR_load_CRYPTO_strings();
5039dede 199 RAND_seed(random, 8192);
5929b1d7
VK
200
201#if OPENSSL_VERSION_NUMBER < 0x10100000L
6468147c 202 s_cryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
5039dede 203 for(i = 0; i < CRYPTO_num_locks(); i++)
6468147c 204 s_cryptoMutexList[i] = MutexCreate();
5039dede 205 CRYPTO_set_locking_callback(CryptoLockingCallback);
5929b1d7
VK
206#endif
207
5039dede
AK
208#ifndef _WIN32
209 CRYPTO_set_id_callback(CryptoIdCallback);
210#endif /* _WIN32 */
6468147c
VK
211
212 // validate supported ciphers
2df047f4 213 nxlog_debug(1, _T("Validating ciphers"));
e5390fb5 214 s_supportedCiphers &= dwEnabledCiphers;
6468147c
VK
215 UINT32 cipherBit = 1;
216 for(i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
217 {
e5390fb5 218 if ((s_supportedCiphers & cipherBit) == 0)
ae8e3292 219 {
2df047f4 220 nxlog_debug(1, _T(" %s disabled (config)"), s_cipherNames[i]);
6468147c 221 continue;
ae8e3292 222 }
6468147c
VK
223 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
224 if (ctx != NULL)
225 {
226 delete ctx;
2df047f4 227 nxlog_debug(1, _T(" %s enabled"), s_cipherNames[i]);
6468147c
VK
228 }
229 else
230 {
e5390fb5 231 s_supportedCiphers &= ~cipherBit;
2df047f4 232 nxlog_debug(1, _T(" %s disabled (validation failed)"), s_cipherNames[i]);
6468147c
VK
233 }
234 }
235
2df047f4 236 nxlog_debug(1, _T("Crypto library initialized"));
9c3bf7f4
VK
237#elif _WITH_ENCRYPTION && WITH_COMMONCRYPTO
238 nxlog_debug(1, _T("Crypto library initialized"));
6468147c 239#else
2df047f4 240 nxlog_debug(1, _T("Crypto library will not be initialized because libnetxms was built without encryption support"));
5039dede 241#endif /* _WITH_ENCRYPTION */
bf6fb6c3 242 return true;
5039dede
AK
243}
244
b1e9b6b3
VK
245/**
246 * Get supported ciphers
247 */
e5390fb5 248UINT32 LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphers()
5039dede 249{
e5390fb5
VK
250 return s_supportedCiphers;
251}
252
253/**
254 * Get supported ciphers as text
255 */
256String LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphersAsText()
257{
258 String s;
070f2993 259#ifdef _WITH_ENCRYPTION
e5390fb5
VK
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 }
070f2993 276#endif
e5390fb5 277 return s;
5039dede
AK
278}
279
b1e9b6b3
VK
280/**
281 * Encrypt message
282 */
b368969c 283NXCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *NXCPEncryptMessage(NXCPEncryptionContext *pCtx, NXCP_MESSAGE *msg)
5039dede 284{
b368969c 285 return (pCtx != NULL) ? pCtx->encryptMessage(msg) : NULL;
5039dede
AK
286}
287
7aad6641
VK
288/**
289 * Decrypt message
290 */
bf6fb6c3 291bool LIBNETXMS_EXPORTABLE NXCPDecryptMessage(NXCPEncryptionContext *pCtx, NXCP_ENCRYPTED_MESSAGE *msg, BYTE *pDecryptionBuffer)
5039dede 292{
bf6fb6c3 293 return (pCtx != NULL) ? pCtx->decryptMessage(msg, pDecryptionBuffer) : false;
5039dede
AK
294}
295
b1e9b6b3
VK
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 */
b368969c 302UINT32 LIBNETXMS_EXPORTABLE SetupEncryptionContext(NXCPMessage *msg,
98abc9f1 303 NXCPEncryptionContext **ppCtx,
b368969c 304 NXCPMessage **ppResponse,
5039dede
AK
305 RSA *pPrivateKey, int nNXCPVersion)
306{
967893bb 307 UINT32 dwResult = RCC_NOT_IMPLEMENTED;
5039dede 308
98abc9f1 309 *ppCtx = NULL;
5039dede 310#ifdef _WITH_ENCRYPTION
b368969c 311 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 312 {
967893bb 313 UINT32 dwCiphers;
5039dede 314
b368969c
VK
315 *ppResponse = new NXCPMessage(nNXCPVersion);
316 (*ppResponse)->setCode(CMD_SESSION_KEY);
317 (*ppResponse)->setId(msg->getId());
4af351c7 318 (*ppResponse)->disableEncryption();
5039dede 319
e5390fb5 320 dwCiphers = msg->getFieldAsUInt32(VID_SUPPORTED_ENCRYPTION) & s_supportedCiphers;
5039dede
AK
321 if (dwCiphers == 0)
322 {
b368969c 323 (*ppResponse)->setField(VID_RCC, RCC_NO_CIPHERS);
5039dede
AK
324 dwResult = RCC_NO_CIPHERS;
325 }
326 else
327 {
3c15eedb 328 BYTE ucKeyBuffer[KEY_BUFFER_SIZE];
98abc9f1 329 RSA *pServerKey;
5039dede 330
98abc9f1 331 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
0df15d50 332 if (*ppCtx != NULL)
5039dede 333 {
0df15d50 334 // Encrypt key
9c3bf7f4
VK
335 size_t size = msg->getFieldAsBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
336 pServerKey = RSAKeyFromData(ucKeyBuffer, size, false);
0df15d50
VK
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);
eae8c74c 351
0df15d50
VK
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 }
5039dede
AK
361 }
362 else
363 {
0df15d50
VK
364 (*ppResponse)->setField(VID_RCC, RCC_ENCRYPTION_ERROR);
365 dwResult = RCC_ENCRYPTION_ERROR;
5039dede
AK
366 }
367 }
368 }
b368969c 369 else if (msg->getCode() == CMD_SESSION_KEY)
5039dede 370 {
b368969c 371 dwResult = msg->getFieldAsUInt32(VID_RCC);
5039dede
AK
372 if (dwResult == RCC_SUCCESS)
373 {
b368969c 374 *ppCtx = NXCPEncryptionContext::create(msg, pPrivateKey);
98abc9f1
VK
375 if (*ppCtx == NULL)
376 {
377 dwResult = RCC_INVALID_SESSION_KEY;
378 }
5039dede
AK
379 }
380 }
381
382 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
383 {
98abc9f1 384 delete *ppCtx;
5039dede
AK
385 *ppCtx = NULL;
386 }
387#else
b368969c 388 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
5039dede 389 {
b368969c 390 *ppResponse = new NXCPMessage(nNXCPVersion);
070f2993
VK
391 (*ppResponse)->setCode(CMD_SESSION_KEY);
392 (*ppResponse)->setId(msg->getId());
26de9040 393 (*ppResponse)->disableEncryption();
b368969c 394 (*ppResponse)->setField(VID_RCC, dwResult);
5039dede
AK
395 }
396#endif
397
398 return dwResult;
399}
400
b1e9b6b3
VK
401/**
402 * Prepare session key request message
403 */
b368969c 404void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(NXCPMessage *msg, RSA *pServerKey, bool useX509Format)
5039dede
AK
405{
406#ifdef _WITH_ENCRYPTION
407 int iLen;
408 BYTE *pKeyBuffer, *pBufPos;
409
b368969c 410 msg->setCode(CMD_REQUEST_SESSION_KEY);
e5390fb5 411 msg->setField(VID_SUPPORTED_ENCRYPTION, s_supportedCiphers);
5039dede 412
9e9d631e
VK
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 }
b368969c 427 msg->setField(VID_PUBLIC_KEY, pKeyBuffer, iLen);
5039dede
AK
428 free(pKeyBuffer);
429#endif
430}
431
7aad6641
VK
432/**
433 * Load RSA key(s) from file
434 */
5039dede
AK
435RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
436{
437#ifdef _WITH_ENCRYPTION
5039dede 438 RSA *pKey = NULL;
9c3bf7f4 439 FILE *fp = _tfopen(pszKeyFile, _T("rb"));
5039dede
AK
440 if (fp != NULL)
441 {
9c3bf7f4 442 UINT32 dwLen;
967893bb 443 if (fread(&dwLen, 1, sizeof(UINT32), fp) == sizeof(UINT32) && dwLen < 10 * 1024)
5039dede 444 {
9c3bf7f4 445 BYTE *pKeyBuffer = (BYTE *)malloc(dwLen);
5039dede
AK
446 if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
447 {
9c3bf7f4 448 BYTE hash[SHA1_DIGEST_SIZE];
7aad6641 449 if (fread(hash, 1, SHA1_DIGEST_SIZE, fp) == SHA1_DIGEST_SIZE)
5039dede 450 {
9c3bf7f4 451 BYTE hash2[SHA1_DIGEST_SIZE];
7aad6641
VK
452 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
453 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
5039dede 454 {
9c3bf7f4 455 pKey = RSAKeyFromData(pKeyBuffer, dwLen, true);
5039dede
AK
456 }
457 }
458 }
459 free(pKeyBuffer);
460 }
461 fclose(fp);
462 }
5039dede
AK
463 return pKey;
464#else
465 return NULL;
466#endif
467}
468
7aad6641
VK
469/**
470 * Create signature for message using certificate (MS CAPI version)
471 * Paraeters:
b368969c 472 * msg and dwMsgLen - message to sign and it's length
7aad6641
VK
473 * pCert - certificate
474 * pBuffer - output buffer
475 * dwBufSize - buffer size
476 * pdwSigLen - actual signature size
477 */
5039dede
AK
478#ifdef _WIN32
479
b368969c 480BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *msg, UINT32 dwMsgLen, const CERT_CONTEXT *pCert,
967893bb 481 BYTE *pBuffer, UINT32 dwBufSize, UINT32 *pdwSigLen)
5039dede
AK
482{
483 BOOL bFreeProv, bRet = FALSE;
484 DWORD i, j, dwLen, dwKeySpec;
485 HCRYPTPROV hProv;
486 HCRYPTHASH hHash;
487 BYTE *pTemp;
488
6468147c 489 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeProv))
5039dede
AK
490 {
491 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
492 {
b368969c 493 if (CryptHashData(hHash, msg, dwMsgLen, 0))
5039dede
AK
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
4e2debcc 513
7aad6641
VK
514/**
515 * Encrypt data block with ICE
516 */
4e2debcc
VK
517void 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);
4e2debcc
VK
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
7aad6641
VK
538/**
539 * Decrypt data block with ICE
540 */
4e2debcc
VK
541void 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);
4e2debcc
VK
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}
98abc9f1 561
7aad6641
VK
562/**
563 * Encryption context constructor
564 */
98abc9f1
VK
565NXCPEncryptionContext::NXCPEncryptionContext()
566{
e4e091f0 567 m_sessionKey = NULL;
2e78b160
VK
568 m_keyLength = 0;
569 m_cipher = -1;
e4e091f0 570#ifdef _WITH_ENCRYPTION
9c144154
VK
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
db05c2af 580 m_encryptorLock = MutexCreate();
e4e091f0 581#endif
98abc9f1
VK
582}
583
7aad6641
VK
584/**
585 * Encryption context destructor
586 */
98abc9f1
VK
587NXCPEncryptionContext::~NXCPEncryptionContext()
588{
4effa0fb 589 free(m_sessionKey);
e4e091f0 590#ifdef _WITH_ENCRYPTION
9c144154
VK
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
db05c2af 600 MutexDestroy(m_encryptorLock);
e4e091f0 601#endif
98abc9f1
VK
602}
603
7aad6641
VK
604/**
605 * Create encryption context from CMD_SESSION_KEY NXCP message
606 */
b368969c 607NXCPEncryptionContext *NXCPEncryptionContext::create(NXCPMessage *msg, RSA *privateKey)
98abc9f1 608{
e4cba530 609#ifdef _WITH_ENCRYPTION
98abc9f1 610 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
b9792835 611 int nSize;
98abc9f1
VK
612 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
613
b368969c 614 int cipher = (int)msg->getFieldAsUInt16(VID_CIPHER);
e6336a90 615 if (ctx->initCipher(cipher))
98abc9f1 616 {
b368969c 617 if (ctx->m_keyLength == (int)msg->getFieldAsUInt16(VID_KEY_LENGTH))
98abc9f1 618 {
e6336a90
VK
619 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
620
621 // Decrypt session key
f5fb7a0f
VK
622 int keySize = (int)msg->getFieldAsBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
623 nSize = RSA_private_decrypt(keySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
e6336a90
VK
624 if (nSize == ctx->m_keyLength)
625 {
626 memcpy(ctx->m_sessionKey, ucSessionKey, nSize);
627
628 // Decrypt session IV
b9792835 629 int nIVLen = msg->getFieldAsUInt16(VID_IV_LENGTH);
e6336a90
VK
630 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
631 nIVLen = 16;
f5fb7a0f
VK
632 keySize = (int)msg->getFieldAsBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
633 nSize = RSA_private_decrypt(keySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
e6336a90 634 if ((nSize == nIVLen) &&
6468147c 635 (nIVLen <= EVP_CIPHER_iv_length(s_ciphers[ctx->m_cipher]())))
e6336a90 636 {
b9792835 637 memcpy(ctx->m_iv, ucSessionKey, std::min(EVP_MAX_IV_LENGTH, nIVLen));
e6336a90
VK
638 }
639 else
640 {
2df047f4 641 nxlog_debug(6, _T("NXCPEncryptionContext::create: IV decryption failed"));
e6336a90
VK
642 delete_and_null(ctx);
643 }
644 }
645 else
646 {
2df047f4 647 nxlog_debug(6, _T("NXCPEncryptionContext::create: session key decryption failed"));
e6336a90
VK
648 delete_and_null(ctx);
649 }
98abc9f1
VK
650 }
651 else
652 {
2df047f4 653 nxlog_debug(6, _T("NXCPEncryptionContext::create: key length mismatch (remote: %d local: %d)"), (int)msg->getFieldAsUInt16(VID_KEY_LENGTH), ctx->m_keyLength);
98abc9f1
VK
654 delete_and_null(ctx);
655 }
656 }
657 else
658 {
2df047f4 659 nxlog_debug(6, _T("NXCPEncryptionContext::create: initCipher(%d) call failed"), cipher);
98abc9f1
VK
660 delete_and_null(ctx);
661 }
662 return ctx;
e4cba530
VK
663#else
664 return new NXCPEncryptionContext;
665#endif
98abc9f1
VK
666}
667
7aad6641 668/**
e6336a90
VK
669 * Initialize cipher
670 */
671bool NXCPEncryptionContext::initCipher(int cipher)
672{
673#ifdef _WITH_ENCRYPTION
6468147c 674 if (s_ciphers[cipher] == NULL)
e6336a90
VK
675 return false; // Unsupported cipher
676
9c144154 677 if (!EVP_EncryptInit_ex(m_encryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90 678 return false;
9c144154 679 if (!EVP_DecryptInit_ex(m_decryptor, s_ciphers[cipher](), NULL, NULL, NULL))
e6336a90
VK
680 return false;
681
682 switch(cipher)
683 {
43a6f3ca 684 case NXCP_CIPHER_AES_256:
e6336a90
VK
685 m_keyLength = 32;
686 break;
43a6f3ca 687 case NXCP_CIPHER_AES_128:
e6336a90
VK
688 m_keyLength = 16;
689 break;
43a6f3ca 690 case NXCP_CIPHER_BLOWFISH_256:
e6336a90
VK
691 m_keyLength = 32;
692 break;
43a6f3ca 693 case NXCP_CIPHER_BLOWFISH_128:
e6336a90
VK
694 m_keyLength = 16;
695 break;
43a6f3ca 696 case NXCP_CIPHER_IDEA:
e6336a90
VK
697 m_keyLength = 16;
698 break;
43a6f3ca 699 case NXCP_CIPHER_3DES:
e6336a90
VK
700 m_keyLength = 24;
701 break;
702 default:
703 return false;
704 }
705
9c144154 706 if (!EVP_CIPHER_CTX_set_key_length(m_encryptor, m_keyLength) || !EVP_CIPHER_CTX_set_key_length(m_decryptor, m_keyLength))
e6336a90
VK
707 return false;
708
6468147c
VK
709 // This check is needed because at least some OpenSSL versions return no error
710 // from EVP_CIPHER_CTX_set_key_length but still not change key length
9c144154 711 if ((EVP_CIPHER_CTX_key_length(m_encryptor) != m_keyLength) || (EVP_CIPHER_CTX_key_length(m_decryptor) != m_keyLength))
6468147c
VK
712 return false;
713
e6336a90
VK
714 m_cipher = cipher;
715 return true;
716#else
717 return false;
718#endif
719}
720
721/**
7aad6641
VK
722 * Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
723 */
967893bb 724NXCPEncryptionContext *NXCPEncryptionContext::create(UINT32 ciphers)
98abc9f1
VK
725{
726 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
727
e4cba530 728#ifdef _WITH_ENCRYPTION
98abc9f1 729 // Select cipher
e6336a90
VK
730 bool selected = false;
731
43a6f3ca 732 if (ciphers & NXCP_SUPPORT_AES_256)
98abc9f1 733 {
43a6f3ca 734 selected = ctx->initCipher(NXCP_CIPHER_AES_256);
98abc9f1 735 }
e6336a90 736
43a6f3ca 737 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_256))
98abc9f1 738 {
43a6f3ca 739 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_256);
98abc9f1 740 }
e6336a90 741
43a6f3ca 742 if (!selected && (ciphers & NXCP_SUPPORT_AES_128))
9e9d631e 743 {
43a6f3ca 744 selected = ctx->initCipher(NXCP_CIPHER_AES_128);
9e9d631e 745 }
e6336a90 746
43a6f3ca 747 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_128))
d772d0dd 748 {
43a6f3ca 749 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_128);
d772d0dd 750 }
e6336a90 751
43a6f3ca 752 if (!selected && (ciphers & NXCP_SUPPORT_IDEA))
98abc9f1 753 {
43a6f3ca 754 selected = ctx->initCipher(NXCP_CIPHER_IDEA);
98abc9f1 755 }
e6336a90 756
43a6f3ca 757 if (!selected && (ciphers & NXCP_SUPPORT_3DES))
98abc9f1 758 {
43a6f3ca 759 selected = ctx->initCipher(NXCP_CIPHER_3DES);
e6336a90
VK
760 }
761
762 if (!selected)
763 {
764 delete ctx;
765 return NULL;
98abc9f1
VK
766 }
767
768 // Generate key
769 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
770 RAND_bytes(ctx->m_sessionKey, ctx->m_keyLength);
771 RAND_bytes(ctx->m_iv, EVP_MAX_IV_LENGTH);
e4cba530 772#endif
98abc9f1
VK
773
774 return ctx;
775}
e6336a90
VK
776
777/**
778 * Encrypt message
779 */
b368969c 780NXCP_ENCRYPTED_MESSAGE *NXCPEncryptionContext::encryptMessage(NXCP_MESSAGE *msg)
e6336a90 781{
b368969c
VK
782 if (msg->flags & s_noEncryptionFlag)
783 return (NXCP_ENCRYPTED_MESSAGE *)nx_memdup(msg, ntohl(msg->size));
e6336a90
VK
784
785#ifdef _WITH_ENCRYPTION
db05c2af
VK
786 MutexLock(m_encryptorLock);
787
9c144154 788 if (!EVP_EncryptInit_ex(m_encryptor, NULL, NULL, m_sessionKey, m_iv))
db05c2af
VK
789 {
790 MutexUnlock(m_encryptorLock);
e6336a90 791 return NULL;
db05c2af 792 }
e6336a90 793
b368969c 794 UINT32 msgSize = ntohl(msg->size);
6be0a20b 795 NXCP_ENCRYPTED_MESSAGE *emsg =
9c144154 796 (NXCP_ENCRYPTED_MESSAGE *)malloc(msgSize + NXCP_ENCRYPTION_HEADER_SIZE + EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(m_encryptor)) + 8);
b368969c
VK
797 emsg->code = htons(CMD_ENCRYPTED_MESSAGE);
798 emsg->reserved = 0;
e6336a90 799
6be0a20b 800 NXCP_ENCRYPTED_PAYLOAD_HEADER header;
e6336a90
VK
801 header.dwChecksum = htonl(CalculateCRC32((BYTE *)msg, msgSize, 0));
802 header.dwReserved = 0;
803
804 int dataSize;
9c144154 805 EVP_EncryptUpdate(m_encryptor, emsg->data, &dataSize, (BYTE *)&header, NXCP_EH_ENCRYPTED_BYTES);
e6336a90 806 msgSize = dataSize;
9c144154 807 EVP_EncryptUpdate(m_encryptor, emsg->data + msgSize, &dataSize, (BYTE *)msg, ntohl(msg->size));
e6336a90 808 msgSize += dataSize;
9c144154 809 EVP_EncryptFinal_ex(m_encryptor, emsg->data + msgSize, &dataSize);
6be0a20b 810 msgSize += dataSize + NXCP_EH_UNENCRYPTED_BYTES;
e6336a90 811
db05c2af
VK
812 MutexUnlock(m_encryptorLock);
813
e6336a90
VK
814 if (msgSize % 8 != 0)
815 {
b368969c
VK
816 emsg->padding = (BYTE)(8 - (msgSize % 8));
817 msgSize += emsg->padding;
e6336a90
VK
818 }
819 else
820 {
b368969c 821 emsg->padding = 0;
e6336a90 822 }
b368969c 823 emsg->size = htonl(msgSize);
e6336a90
VK
824
825 return emsg;
826#else /* _WITH_ENCRYPTION */
827 return NULL;
828#endif
829}
830
831/**
832 * Decrypt message
833 */
6be0a20b 834bool NXCPEncryptionContext::decryptMessage(NXCP_ENCRYPTED_MESSAGE *msg, BYTE *decryptionBuffer)
e6336a90
VK
835{
836#ifdef _WITH_ENCRYPTION
9c144154 837 if (!EVP_DecryptInit_ex(m_decryptor, NULL, NULL, m_sessionKey, m_iv))
e6336a90
VK
838 return false;
839
b368969c 840 msg->size = ntohl(msg->size);
e6336a90 841 int dataSize;
9c144154 842 EVP_DecryptUpdate(m_decryptor, decryptionBuffer, &dataSize, msg->data,
b368969c 843 msg->size - NXCP_EH_UNENCRYPTED_BYTES - msg->padding);
9c144154 844 EVP_DecryptFinal(m_decryptor, decryptionBuffer + dataSize, &dataSize);
e6336a90 845
b368969c
VK
846 NXCP_MESSAGE *clearMsg = (NXCP_MESSAGE *)(decryptionBuffer + NXCP_EH_ENCRYPTED_BYTES);
847 UINT32 msgSize = ntohl(clearMsg->size);
848 if (msgSize > msg->size)
e6336a90
VK
849 return false; // Message decrypted incorrectly, because it can't be larger than encrypted
850 UINT32 crc32 = CalculateCRC32((BYTE *)clearMsg, msgSize, 0);
6be0a20b 851 if (crc32 != ntohl(((NXCP_ENCRYPTED_PAYLOAD_HEADER *)decryptionBuffer)->dwChecksum))
e6336a90
VK
852 return false; // Bad checksum
853
854 memcpy(msg, clearMsg, msgSize);
855 return true;
856#else /* _WITH_ENCRYPTION */
857 return false;
858#endif
859}
981d246a
VK
860
861/**
862 * Generate random bytes
863 */
864void LIBNETXMS_EXPORTABLE GenerateRandomBytes(BYTE *buffer, size_t size)
865{
866#ifdef _WITH_ENCRYPTION
867 RAND_bytes(buffer, (int)size);
868#else
869 srand((unsigned int)time(NULL));
870 for(size_t i = 0; i < size; i++)
871 buffer[i] = (BYTE)(rand() % 256);
872#endif
873}
7f9ff8a5
VK
874
875/**
876 * Log OpenSSL error stack
877 */
878void LIBNETXMS_EXPORTABLE LogOpenSSLErrorStack(int level)
879{
880#if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
881 nxlog_debug(level, _T("OpenSSL error stack:"));
882 long err;
883 char buffer[128];
884 while((err = ERR_get_error()) != 0)
885 nxlog_debug(level, _T(" %hs"), ERR_error_string(err, buffer));
886#endif
887}