set SQLite page size on export to 64K to allow maximum possible export file size...
[public/netxms.git] / src / libnetxms / crypto.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
b1e9b6b3 4** Copyright (C) 2003-2012 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 */
5039dede
AK
36static DWORD m_dwSupportedCiphers =
37#ifdef _WITH_ENCRYPTION
38#ifndef OPENSSL_NO_AES
39 CSCP_SUPPORT_AES_256 |
9e9d631e 40 CSCP_SUPPORT_AES_128 |
5039dede
AK
41#endif
42#ifndef OPENSSL_NO_BF
43 CSCP_SUPPORT_BLOWFISH |
44#endif
45#ifndef OPENSSL_NO_IDEA
46 CSCP_SUPPORT_IDEA |
47#endif
48#ifndef OPENSSL_NO_DES
49 CSCP_SUPPORT_3DES |
50#endif
51#endif /* _WITH_ENCRYPTION */
52 0;
53
b1e9b6b3
VK
54/**
55 * Static data
56 */
5039dede
AK
57#ifdef _WITH_ENCRYPTION
58
9e9d631e 59typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
5039dede
AK
60static CIPHER_FUNC m_pfCipherList[NETXMS_MAX_CIPHERS] =
61{
62#ifndef OPENSSL_NO_AES
63 EVP_aes_256_cbc,
64#else
65 NULL,
66#endif
67#ifndef OPENSSL_NO_BF
68 EVP_bf_cbc,
69#else
70 NULL,
71#endif
72#ifndef OPENSSL_NO_IDEA
73 EVP_idea_cbc,
74#else
75 NULL,
76#endif
77#ifndef OPENSSL_NO_DES
9e9d631e
VK
78 EVP_des_ede3_cbc,
79#else
80 NULL,
81#endif
82#ifndef OPENSSL_NO_AES
83 EVP_aes_128_cbc
5039dede
AK
84#else
85 NULL
86#endif
87};
88static WORD m_wNoEncryptionFlag = 0;
89static MUTEX *m_pCryptoMutexList = NULL;
90
b1e9b6b3
VK
91/**
92 * Locking callback for CRYPTO library
93 */
5039dede
AK
94static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
95{
96 if (nMode & CRYPTO_LOCK)
c17f6cbc 97 MutexLock(m_pCryptoMutexList[nLock]);
5039dede
AK
98 else
99 MutexUnlock(m_pCryptoMutexList[nLock]);
100}
101
b1e9b6b3
VK
102/**
103 * ID callback for CRYPTO library
104 */
5039dede
AK
105#ifndef _WIN32
106
9e9d631e 107static unsigned long CryptoIdCallback()
5039dede
AK
108{
109 return (unsigned long)GetCurrentThreadId();
110}
111
112#endif
113
114#endif /* _WITH_ENCRYPTION */
115
b1e9b6b3
VK
116/**
117 * Initialize OpenSSL library
118 */
5039dede
AK
119BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(DWORD dwEnabledCiphers)
120{
121#ifdef _WITH_ENCRYPTION
122 BYTE random[8192];
123 int i;
124
125 CRYPTO_malloc_init();
126 ERR_load_CRYPTO_strings();
127 OpenSSL_add_all_algorithms();
128 RAND_seed(random, 8192);
129 m_dwSupportedCiphers &= dwEnabledCiphers;
130 m_wNoEncryptionFlag = htons(MF_DONT_ENCRYPT);
131 m_pCryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
132 for(i = 0; i < CRYPTO_num_locks(); i++)
133 m_pCryptoMutexList[i] = MutexCreate();
134 CRYPTO_set_locking_callback(CryptoLockingCallback);
135#ifndef _WIN32
136 CRYPTO_set_id_callback(CryptoIdCallback);
137#endif /* _WIN32 */
138#endif /* _WITH_ENCRYPTION */
139 return TRUE;
140}
141
b1e9b6b3
VK
142/**
143 * Get supported ciphers
144 */
9e9d631e 145DWORD LIBNETXMS_EXPORTABLE CSCPGetSupportedCiphers()
5039dede
AK
146{
147 return m_dwSupportedCiphers;
148}
149
b1e9b6b3
VK
150/**
151 * Encrypt message
152 */
98abc9f1 153CSCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *CSCPEncryptMessage(NXCPEncryptionContext *pCtx, CSCP_MESSAGE *pMsg)
5039dede
AK
154{
155#ifdef _WITH_ENCRYPTION
156 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
157 CSCP_ENCRYPTED_PAYLOAD_HEADER header;
158 int nSize;
159 EVP_CIPHER_CTX cipher;
160 DWORD dwMsgSize;
161
162 if (pMsg->wFlags & m_wNoEncryptionFlag)
163 return (CSCP_ENCRYPTED_MESSAGE *)nx_memdup(pMsg, ntohl(pMsg->dwSize));
164
98abc9f1 165 if (m_pfCipherList[pCtx->getCipher()] == NULL)
5039dede
AK
166 return NULL; // Unsupported cipher
167
98abc9f1
VK
168 EVP_EncryptInit(&cipher, m_pfCipherList[pCtx->getCipher()](), pCtx->getSessionKey(), pCtx->getIV());
169 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->getKeyLength());
5039dede
AK
170
171 dwMsgSize = ntohl(pMsg->dwSize);
172 pEnMsg = (CSCP_ENCRYPTED_MESSAGE *)malloc(dwMsgSize + CSCP_ENCRYPTION_HEADER_SIZE +
173 EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&cipher)) + 8);
174 pEnMsg->wCode = htons(CMD_ENCRYPTED_MESSAGE);
175 pEnMsg->nReserved = 0;
176
177 header.dwChecksum = htonl(CalculateCRC32((BYTE *)pMsg, dwMsgSize, 0));
178 header.dwReserved = 0;
179 EVP_EncryptUpdate(&cipher, pEnMsg->data, &nSize, (BYTE *)&header, CSCP_EH_ENCRYPTED_BYTES);
180 dwMsgSize = nSize;
181 EVP_EncryptUpdate(&cipher, pEnMsg->data + dwMsgSize, &nSize, (BYTE *)pMsg, ntohl(pMsg->dwSize));
182 dwMsgSize += nSize;
183 EVP_EncryptFinal(&cipher, pEnMsg->data + dwMsgSize, &nSize);
184 dwMsgSize += nSize + CSCP_EH_UNENCRYPTED_BYTES;
185 EVP_CIPHER_CTX_cleanup(&cipher);
186
187 if (dwMsgSize % 8 != 0)
188 {
189 pEnMsg->nPadding = (BYTE)(8 - (dwMsgSize % 8));
190 dwMsgSize += pEnMsg->nPadding;
191 }
192 else
193 {
194 pEnMsg->nPadding = 0;
195 }
196 pEnMsg->dwSize = htonl(dwMsgSize);
197
198 return pEnMsg;
199#else /* _WITH_ENCRYPTION */
200 return NULL;
201#endif
202}
203
204
205//
206// Decrypt message
207//
208
98abc9f1 209BOOL LIBNETXMS_EXPORTABLE CSCPDecryptMessage(NXCPEncryptionContext *pCtx,
5039dede
AK
210 CSCP_ENCRYPTED_MESSAGE *pMsg,
211 BYTE *pDecryptionBuffer)
212{
213#ifdef _WITH_ENCRYPTION
214 int nSize;
215 EVP_CIPHER_CTX cipher;
216 DWORD dwChecksum, dwMsgSize;
217 CSCP_MESSAGE *pClearMsg;
218
98abc9f1 219 if (m_pfCipherList[pCtx->getCipher()] == NULL)
5039dede
AK
220 return FALSE; // Unsupported cipher
221
222 pMsg->dwSize = ntohl(pMsg->dwSize);
98abc9f1
VK
223 EVP_DecryptInit(&cipher, m_pfCipherList[pCtx->getCipher()](), pCtx->getSessionKey(), pCtx->getIV());
224 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->getKeyLength());
5039dede
AK
225 EVP_DecryptUpdate(&cipher, pDecryptionBuffer, &nSize, pMsg->data,
226 pMsg->dwSize - CSCP_EH_UNENCRYPTED_BYTES - pMsg->nPadding);
227 EVP_DecryptFinal(&cipher, pDecryptionBuffer + nSize, &nSize);
228 EVP_CIPHER_CTX_cleanup(&cipher);
229
230 pClearMsg = (CSCP_MESSAGE *)(pDecryptionBuffer + CSCP_EH_ENCRYPTED_BYTES);
231 dwMsgSize = ntohl(pClearMsg->dwSize);
232 if (dwMsgSize > pMsg->dwSize)
233 return FALSE; // Message decrypted incorrectly, because it can't be larger than encrypted
234 dwChecksum = CalculateCRC32((BYTE *)pClearMsg, dwMsgSize, 0);
235 if (dwChecksum != ntohl(((CSCP_ENCRYPTED_PAYLOAD_HEADER *)pDecryptionBuffer)->dwChecksum))
236 return FALSE; // Bad checksum
237
238 memcpy(pMsg, pClearMsg, dwMsgSize);
239 return TRUE;
240#else /* _WITH_ENCRYPTION */
241 return FALSE;
242#endif
243}
244
b1e9b6b3
VK
245/**
246 * Setup encryption context
247 * Function will determine is it called on initiator or responder side
248 * by message code. Initiator should provide it's private key,
249 * and responder should provide pointer to response message.
250 */
5039dede 251DWORD LIBNETXMS_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg,
98abc9f1 252 NXCPEncryptionContext **ppCtx,
5039dede
AK
253 CSCPMessage **ppResponse,
254 RSA *pPrivateKey, int nNXCPVersion)
255{
256 DWORD dwResult = RCC_NOT_IMPLEMENTED;
257
98abc9f1 258 *ppCtx = NULL;
5039dede
AK
259#ifdef _WITH_ENCRYPTION
260 if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
261 {
262 DWORD dwCiphers;
263
264 *ppResponse = new CSCPMessage(nNXCPVersion);
265 (*ppResponse)->SetCode(CMD_SESSION_KEY);
266 (*ppResponse)->SetId(pMsg->GetId());
267 (*ppResponse)->DisableEncryption();
268
269 dwCiphers = pMsg->GetVariableLong(VID_SUPPORTED_ENCRYPTION) & m_dwSupportedCiphers;
270 if (dwCiphers == 0)
271 {
272 (*ppResponse)->SetVariable(VID_RCC, RCC_NO_CIPHERS);
273 dwResult = RCC_NO_CIPHERS;
274 }
275 else
276 {
98abc9f1
VK
277 BYTE *pBufPos, ucKeyBuffer[KEY_BUFFER_SIZE];
278 RSA *pServerKey;
279 DWORD dwKeySize;
5039dede 280
98abc9f1 281 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
5039dede
AK
282
283 // Encrypt key
284 dwKeySize = pMsg->GetVariableBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
285 pBufPos = ucKeyBuffer;
286 pServerKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwKeySize);
287 if (pServerKey != NULL)
288 {
289 (*ppResponse)->SetVariable(VID_RCC, RCC_SUCCESS);
98abc9f1 290 dwKeySize = RSA_public_encrypt((*ppCtx)->getKeyLength(), (*ppCtx)->getSessionKey(),
5039dede
AK
291 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
292 (*ppResponse)->SetVariable(VID_SESSION_KEY, ucKeyBuffer, dwKeySize);
98abc9f1 293 dwKeySize = RSA_public_encrypt(EVP_MAX_IV_LENGTH, (*ppCtx)->getIV(),
5039dede
AK
294 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
295 (*ppResponse)->SetVariable(VID_SESSION_IV, ucKeyBuffer, dwKeySize);
98abc9f1
VK
296 (*ppResponse)->SetVariable(VID_CIPHER, (WORD)(*ppCtx)->getCipher());
297 (*ppResponse)->SetVariable(VID_KEY_LENGTH, (WORD)(*ppCtx)->getKeyLength());
5039dede
AK
298 (*ppResponse)->SetVariable(VID_IV_LENGTH, (WORD)EVP_MAX_IV_LENGTH);
299 RSA_free(pServerKey);
300 dwResult = RCC_SUCCESS;
301 }
302 else
303 {
304 (*ppResponse)->SetVariable(VID_RCC, RCC_INVALID_PUBLIC_KEY);
305 dwResult = RCC_INVALID_PUBLIC_KEY;
306 }
307 }
308 }
309 else if (pMsg->GetCode() == CMD_SESSION_KEY)
310 {
311 dwResult = pMsg->GetVariableLong(VID_RCC);
312 if (dwResult == RCC_SUCCESS)
313 {
98abc9f1
VK
314 *ppCtx = NXCPEncryptionContext::create(pMsg, pPrivateKey);
315 if (*ppCtx == NULL)
316 {
317 dwResult = RCC_INVALID_SESSION_KEY;
318 }
5039dede
AK
319 }
320 }
321
322 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
323 {
98abc9f1 324 delete *ppCtx;
5039dede
AK
325 *ppCtx = NULL;
326 }
327#else
328 if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
329 {
330 *ppResponse = new CSCPMessage(nNXCPVersion);
331 (*ppResponse)->SetCode(CMD_SESSION_KEY);
332 (*ppResponse)->SetId(pMsg->GetId());
333 (*ppResponse)->DisableEncryption();
334 (*ppResponse)->SetVariable(VID_RCC, dwResult);
335 }
336#endif
337
338 return dwResult;
339}
340
b1e9b6b3
VK
341/**
342 * Prepare session key request message
343 */
9e9d631e 344void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(CSCPMessage *pMsg, RSA *pServerKey, bool useX509Format)
5039dede
AK
345{
346#ifdef _WITH_ENCRYPTION
347 int iLen;
348 BYTE *pKeyBuffer, *pBufPos;
349
350 pMsg->SetCode(CMD_REQUEST_SESSION_KEY);
351 pMsg->SetVariable(VID_SUPPORTED_ENCRYPTION, m_dwSupportedCiphers);
352
9e9d631e
VK
353 if (useX509Format)
354 {
355 iLen = i2d_RSA_PUBKEY(pServerKey, NULL);
356 pKeyBuffer = (BYTE *)malloc(iLen);
357 pBufPos = pKeyBuffer;
358 i2d_RSA_PUBKEY(pServerKey, &pBufPos);
359 }
360 else
361 {
362 iLen = i2d_RSAPublicKey(pServerKey, NULL);
363 pKeyBuffer = (BYTE *)malloc(iLen);
364 pBufPos = pKeyBuffer;
365 i2d_RSAPublicKey(pServerKey, &pBufPos);
366 }
367 pMsg->SetVariable(VID_PUBLIC_KEY, pKeyBuffer, iLen);
5039dede
AK
368 free(pKeyBuffer);
369#endif
370}
371
372
373//
374// Load RSA key(s) from file
375//
376
377RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
378{
379#ifdef _WITH_ENCRYPTION
380 FILE *fp;
381 BYTE *pKeyBuffer, *pBufPos, hash[SHA1_DIGEST_SIZE];
382 DWORD dwLen;
383 RSA *pKey = NULL;
384
385 fp = _tfopen(pszKeyFile, _T("rb"));
386 if (fp != NULL)
387 {
6d738067 388 if (fread(&dwLen, 1, sizeof(DWORD), fp) == sizeof(DWORD) && dwLen < 10 * 1024)
5039dede
AK
389 {
390 pKeyBuffer = (BYTE *)malloc(dwLen);
391 pBufPos = pKeyBuffer;
392 if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
393 {
394 BYTE hash2[SHA1_DIGEST_SIZE];
395
396 fread(hash, 1, SHA1_DIGEST_SIZE, fp);
397 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
398 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
399 {
400 pKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwLen);
401 if (pKey != NULL)
402 {
403 if (d2i_RSAPrivateKey(&pKey, (OPENSSL_CONST BYTE **)&pBufPos,
404 dwLen - CAST_FROM_POINTER((pBufPos - pKeyBuffer), DWORD)) == NULL)
405 {
406 RSA_free(pKey);
407 pKey = NULL;
408 }
409 }
410 }
411 }
412 free(pKeyBuffer);
413 }
414 fclose(fp);
415 }
416
417 return pKey;
418#else
419 return NULL;
420#endif
421}
422
423
424//
425// Create signature for message using certificate (MS CAPI version)
426// Paraeters:
427// pMsg and dwMsgLen - message to sign and it's length
428// pCert - certificate
429// pBuffer - output buffer
430// dwBufSize - buffer size
431// pdwSigLen - actual signature size
432//
433
434#ifdef _WIN32
435
436BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *pMsg, DWORD dwMsgLen, const CERT_CONTEXT *pCert,
437 BYTE *pBuffer, DWORD dwBufSize, DWORD *pdwSigLen)
438{
439 BOOL bFreeProv, bRet = FALSE;
440 DWORD i, j, dwLen, dwKeySpec;
441 HCRYPTPROV hProv;
442 HCRYPTHASH hHash;
443 BYTE *pTemp;
444
445 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
446 NULL, &hProv, &dwKeySpec, &bFreeProv))
447 {
448 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
449 {
450 if (CryptHashData(hHash, pMsg, dwMsgLen, 0))
451 {
452 dwLen = dwBufSize;
453 pTemp = (BYTE *)malloc(dwBufSize);;
454 bRet = CryptSignHash(hHash, dwKeySpec, NULL, 0, pTemp, &dwLen);
455 *pdwSigLen = dwLen;
456 // we have to reverse the byte-order in the result from CryptSignHash()
457 for(i = 0, j = dwLen - 1; i < dwLen; i++, j--)
458 pBuffer[i] = pTemp[j];
459 }
460 CryptDestroyHash(hHash);
461 }
462
463 if (bFreeProv)
464 CryptReleaseContext(hProv, 0);
465 }
466 return bRet;
467}
468
469#endif
4e2debcc
VK
470
471
472//
473// Encrypt data block with ICE
474//
475
476void LIBNETXMS_EXPORTABLE ICEEncryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
477{
478 ICE_KEY *ice = ice_key_create(1);
479 ice_key_set(ice, key);
480
481 int stopPos = inLen - (inLen % 8);
482 const BYTE *curr = in;
483 for(int pos = 0; pos < stopPos; pos += 8)
484 ice_key_encrypt(ice, &in[pos], &out[pos]);
485
486 if (stopPos < inLen)
487 {
488 BYTE plainText[8], encrypted[8];
489
490 memcpy(plainText, &in[stopPos], inLen - stopPos);
491 ice_key_encrypt(ice, plainText, encrypted);
492 memcpy(&out[stopPos], encrypted, inLen - stopPos);
493 }
494
495 ice_key_destroy(ice);
496}
497
498
499//
500// Decrypt data block with ICE
501//
502
503void LIBNETXMS_EXPORTABLE ICEDecryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
504{
505 ICE_KEY *ice = ice_key_create(1);
506 ice_key_set(ice, key);
507
508 int stopPos = inLen - (inLen % 8);
509 const BYTE *curr = in;
510 for(int pos = 0; pos < stopPos; pos += 8)
511 ice_key_decrypt(ice, &in[pos], &out[pos]);
512
513 if (stopPos < inLen)
514 {
515 BYTE plainText[8], encrypted[8];
516
517 memcpy(encrypted, &in[stopPos], inLen - stopPos);
518 ice_key_decrypt(ice, encrypted, plainText);
519 memcpy(&out[stopPos], plainText, inLen - stopPos);
520 }
521
522 ice_key_destroy(ice);
523}
98abc9f1
VK
524
525
526//
527// Encryption context constructor
528//
529
530NXCPEncryptionContext::NXCPEncryptionContext()
531{
532 m_sessionKey = NULL;
533}
534
535
536//
537// Encryption context destructor
538//
539
540NXCPEncryptionContext::~NXCPEncryptionContext()
541{
542 safe_free(m_sessionKey);
543}
544
545
546//
547// Create encryption context from CMD_SESSION_KEY NXCP message
548//
549
550NXCPEncryptionContext *NXCPEncryptionContext::create(CSCPMessage *msg, RSA *privateKey)
551{
e4cba530 552#ifdef _WITH_ENCRYPTION
98abc9f1
VK
553 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
554 DWORD dwKeySize;
555 int nSize, nIVLen;
556 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
557
558 ctx->m_cipher = msg->GetVariableShort(VID_CIPHER);
559 ctx->m_keyLength = msg->GetVariableShort(VID_KEY_LENGTH);
560 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
561
562 // Decrypt session key
563 dwKeySize = msg->GetVariableBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
564 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
565 if (nSize == ctx->m_keyLength)
566 {
567 memcpy(ctx->m_sessionKey, ucSessionKey, nSize);
568
569 // Decrypt session IV
570 nIVLen = msg->GetVariableShort(VID_IV_LENGTH);
571 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
572 nIVLen = 16;
573 dwKeySize = msg->GetVariableBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
574 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
575 if ((nSize == nIVLen) &&
576 (nIVLen <= EVP_CIPHER_iv_length(m_pfCipherList[ctx->m_cipher]())))
577 {
578 memcpy(ctx->m_iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
579 }
580 else
581 {
582 delete_and_null(ctx);
583 }
584 }
585 else
586 {
587 delete_and_null(ctx);
588 }
589 return ctx;
e4cba530
VK
590#else
591 return new NXCPEncryptionContext;
592#endif
98abc9f1
VK
593}
594
595
596//
597// Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
598//
599
600NXCPEncryptionContext *NXCPEncryptionContext::create(DWORD ciphers)
601{
602 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
603
e4cba530 604#ifdef _WITH_ENCRYPTION
98abc9f1
VK
605 // Select cipher
606 if (ciphers & CSCP_SUPPORT_AES_256)
607 {
608 ctx->m_cipher = CSCP_CIPHER_AES_256;
609 ctx->m_keyLength = 32;
610 }
611 else if (ciphers & CSCP_SUPPORT_BLOWFISH)
612 {
613 ctx->m_cipher = CSCP_CIPHER_BLOWFISH;
614 ctx->m_keyLength = 32;
615 }
9e9d631e
VK
616 else if (ciphers & CSCP_SUPPORT_AES_128)
617 {
618 ctx->m_cipher = CSCP_CIPHER_AES_128;
619 ctx->m_keyLength = 16;
620 }
98abc9f1
VK
621 else if (ciphers & CSCP_SUPPORT_IDEA)
622 {
623 ctx->m_cipher = CSCP_CIPHER_IDEA;
624 ctx->m_keyLength = 16;
625 }
626 else if (ciphers & CSCP_SUPPORT_3DES)
627 {
628 ctx->m_cipher = CSCP_CIPHER_3DES;
629 ctx->m_keyLength = 24;
630 }
631
632 // Generate key
633 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
634 RAND_bytes(ctx->m_sessionKey, ctx->m_keyLength);
635 RAND_bytes(ctx->m_iv, EVP_MAX_IV_LENGTH);
e4cba530 636#endif
98abc9f1
VK
637
638 return ctx;
639}