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