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