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