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