fc0d408d959c04451e8759577949d997f0b191ba
[public/netxms.git] / src / libnetxms / crypto.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
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
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 **
16 ** You should have received a copy of the GNU Lesser General Public License
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"
25 #include "ice.h"
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
40 static DWORD m_dwSupportedCiphers =
41 #ifdef _WITH_ENCRYPTION
42 #ifndef OPENSSL_NO_AES
43 CSCP_SUPPORT_AES_256 |
44 CSCP_SUPPORT_AES_128 |
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
65 typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
66 static 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
84 EVP_des_ede3_cbc,
85 #else
86 NULL,
87 #endif
88 #ifndef OPENSSL_NO_AES
89 EVP_aes_128_cbc
90 #else
91 NULL
92 #endif
93 };
94 static WORD m_wNoEncryptionFlag = 0;
95 static MUTEX *m_pCryptoMutexList = NULL;
96
97
98 //
99 // Locking callback for CRYPTO library
100 //
101
102 static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
103 {
104 if (nMode & CRYPTO_LOCK)
105 MutexLock(m_pCryptoMutexList[nLock]);
106 else
107 MutexUnlock(m_pCryptoMutexList[nLock]);
108 }
109
110
111 //
112 // ID callback for CRYPTO library
113 //
114
115 #ifndef _WIN32
116
117 static unsigned long CryptoIdCallback()
118 {
119 return (unsigned long)GetCurrentThreadId();
120 }
121
122 #endif
123
124 #endif /* _WITH_ENCRYPTION */
125
126
127 //
128 // Initialize OpenSSL library
129 //
130
131 BOOL 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
159 DWORD LIBNETXMS_EXPORTABLE CSCPGetSupportedCiphers()
160 {
161 return m_dwSupportedCiphers;
162 }
163
164
165 //
166 // Encrypt message
167 //
168
169 CSCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *CSCPEncryptMessage(NXCPEncryptionContext *pCtx, CSCP_MESSAGE *pMsg)
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
181 if (m_pfCipherList[pCtx->getCipher()] == NULL)
182 return NULL; // Unsupported cipher
183
184 EVP_EncryptInit(&cipher, m_pfCipherList[pCtx->getCipher()](), pCtx->getSessionKey(), pCtx->getIV());
185 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->getKeyLength());
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
225 BOOL LIBNETXMS_EXPORTABLE CSCPDecryptMessage(NXCPEncryptionContext *pCtx,
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
235 if (m_pfCipherList[pCtx->getCipher()] == NULL)
236 return FALSE; // Unsupported cipher
237
238 pMsg->dwSize = ntohl(pMsg->dwSize);
239 EVP_DecryptInit(&cipher, m_pfCipherList[pCtx->getCipher()](), pCtx->getSessionKey(), pCtx->getIV());
240 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->getKeyLength());
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
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
269 DWORD LIBNETXMS_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg,
270 NXCPEncryptionContext **ppCtx,
271 CSCPMessage **ppResponse,
272 RSA *pPrivateKey, int nNXCPVersion)
273 {
274 DWORD dwResult = RCC_NOT_IMPLEMENTED;
275
276 *ppCtx = NULL;
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 {
295 BYTE *pBufPos, ucKeyBuffer[KEY_BUFFER_SIZE];
296 RSA *pServerKey;
297 DWORD dwKeySize;
298
299 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
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);
308 dwKeySize = RSA_public_encrypt((*ppCtx)->getKeyLength(), (*ppCtx)->getSessionKey(),
309 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
310 (*ppResponse)->SetVariable(VID_SESSION_KEY, ucKeyBuffer, dwKeySize);
311 dwKeySize = RSA_public_encrypt(EVP_MAX_IV_LENGTH, (*ppCtx)->getIV(),
312 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
313 (*ppResponse)->SetVariable(VID_SESSION_IV, ucKeyBuffer, dwKeySize);
314 (*ppResponse)->SetVariable(VID_CIPHER, (WORD)(*ppCtx)->getCipher());
315 (*ppResponse)->SetVariable(VID_KEY_LENGTH, (WORD)(*ppCtx)->getKeyLength());
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 {
332 *ppCtx = NXCPEncryptionContext::create(pMsg, pPrivateKey);
333 if (*ppCtx == NULL)
334 {
335 dwResult = RCC_INVALID_SESSION_KEY;
336 }
337 }
338 }
339
340 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
341 {
342 delete *ppCtx;
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
364 void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(CSCPMessage *pMsg, RSA *pServerKey, bool useX509Format)
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
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);
388 free(pKeyBuffer);
389 #endif
390 }
391
392
393 //
394 // Load RSA key(s) from file
395 //
396
397 RSA 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 {
408 if (fread(&dwLen, 1, sizeof(DWORD), fp) == sizeof(DWORD) && dwLen < 10 * 1024)
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
456 BOOL 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
490
491
492 //
493 // Encrypt data block with ICE
494 //
495
496 void 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
523 void 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 }
544
545
546 //
547 // Encryption context constructor
548 //
549
550 NXCPEncryptionContext::NXCPEncryptionContext()
551 {
552 m_sessionKey = NULL;
553 }
554
555
556 //
557 // Encryption context destructor
558 //
559
560 NXCPEncryptionContext::~NXCPEncryptionContext()
561 {
562 safe_free(m_sessionKey);
563 }
564
565
566 //
567 // Create encryption context from CMD_SESSION_KEY NXCP message
568 //
569
570 NXCPEncryptionContext *NXCPEncryptionContext::create(CSCPMessage *msg, RSA *privateKey)
571 {
572 #ifdef _WITH_ENCRYPTION
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;
610 #else
611 return new NXCPEncryptionContext;
612 #endif
613 }
614
615
616 //
617 // Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
618 //
619
620 NXCPEncryptionContext *NXCPEncryptionContext::create(DWORD ciphers)
621 {
622 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
623
624 #ifdef _WITH_ENCRYPTION
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 }
636 else if (ciphers & CSCP_SUPPORT_AES_128)
637 {
638 ctx->m_cipher = CSCP_CIPHER_AES_128;
639 ctx->m_keyLength = 16;
640 }
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);
656 #endif
657
658 return ctx;
659 }