f010426b291353d811fb00efed68bd73a788ce12
[public/netxms.git] / src / libnetxms / crypto.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003, 2004, 2005, 2006, 2007 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 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 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 #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
64 typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)(void);
65 static 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 };
88 static WORD m_wNoEncryptionFlag = 0;
89 static MUTEX *m_pCryptoMutexList = NULL;
90
91
92 //
93 // Locking callback for CRYPTO library
94 //
95
96 static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
97 {
98 if (nMode & CRYPTO_LOCK)
99 MutexLock(m_pCryptoMutexList[nLock], INFINITE);
100 else
101 MutexUnlock(m_pCryptoMutexList[nLock]);
102 }
103
104
105 //
106 // ID callback for CRYPTO library
107 //
108
109 #ifndef _WIN32
110
111 static 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
125 BOOL 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
153 DWORD LIBNETXMS_EXPORTABLE CSCPGetSupportedCiphers(void)
154 {
155 return m_dwSupportedCiphers;
156 }
157
158
159 //
160 // Encrypt message
161 //
162
163 CSCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE
164 *CSCPEncryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx, CSCP_MESSAGE *pMsg)
165 {
166 #ifdef _WITH_ENCRYPTION
167 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
168 CSCP_ENCRYPTED_PAYLOAD_HEADER header;
169 int nSize;
170 EVP_CIPHER_CTX cipher;
171 DWORD dwMsgSize;
172
173 if (pMsg->wFlags & m_wNoEncryptionFlag)
174 return (CSCP_ENCRYPTED_MESSAGE *)nx_memdup(pMsg, ntohl(pMsg->dwSize));
175
176 if (m_pfCipherList[pCtx->nCipher] == NULL)
177 return NULL; // Unsupported cipher
178
179 EVP_EncryptInit(&cipher, m_pfCipherList[pCtx->nCipher](), pCtx->pSessionKey, pCtx->iv);
180 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->nKeyLen);
181
182 dwMsgSize = ntohl(pMsg->dwSize);
183 pEnMsg = (CSCP_ENCRYPTED_MESSAGE *)malloc(dwMsgSize + CSCP_ENCRYPTION_HEADER_SIZE +
184 EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&cipher)) + 8);
185 pEnMsg->wCode = htons(CMD_ENCRYPTED_MESSAGE);
186 pEnMsg->nReserved = 0;
187
188 header.dwChecksum = htonl(CalculateCRC32((BYTE *)pMsg, dwMsgSize, 0));
189 header.dwReserved = 0;
190 EVP_EncryptUpdate(&cipher, pEnMsg->data, &nSize, (BYTE *)&header, CSCP_EH_ENCRYPTED_BYTES);
191 dwMsgSize = nSize;
192 EVP_EncryptUpdate(&cipher, pEnMsg->data + dwMsgSize, &nSize, (BYTE *)pMsg, ntohl(pMsg->dwSize));
193 dwMsgSize += nSize;
194 EVP_EncryptFinal(&cipher, pEnMsg->data + dwMsgSize, &nSize);
195 dwMsgSize += nSize + CSCP_EH_UNENCRYPTED_BYTES;
196 EVP_CIPHER_CTX_cleanup(&cipher);
197
198 if (dwMsgSize % 8 != 0)
199 {
200 pEnMsg->nPadding = (BYTE)(8 - (dwMsgSize % 8));
201 dwMsgSize += pEnMsg->nPadding;
202 }
203 else
204 {
205 pEnMsg->nPadding = 0;
206 }
207 pEnMsg->dwSize = htonl(dwMsgSize);
208
209 return pEnMsg;
210 #else /* _WITH_ENCRYPTION */
211 return NULL;
212 #endif
213 }
214
215
216 //
217 // Decrypt message
218 //
219
220 BOOL LIBNETXMS_EXPORTABLE CSCPDecryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx,
221 CSCP_ENCRYPTED_MESSAGE *pMsg,
222 BYTE *pDecryptionBuffer)
223 {
224 #ifdef _WITH_ENCRYPTION
225 int nSize;
226 EVP_CIPHER_CTX cipher;
227 DWORD dwChecksum, dwMsgSize;
228 CSCP_MESSAGE *pClearMsg;
229
230 if (m_pfCipherList[pCtx->nCipher] == NULL)
231 return FALSE; // Unsupported cipher
232
233 pMsg->dwSize = ntohl(pMsg->dwSize);
234 EVP_DecryptInit(&cipher, m_pfCipherList[pCtx->nCipher](), pCtx->pSessionKey, pCtx->iv);
235 EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->nKeyLen);
236 EVP_DecryptUpdate(&cipher, pDecryptionBuffer, &nSize, pMsg->data,
237 pMsg->dwSize - CSCP_EH_UNENCRYPTED_BYTES - pMsg->nPadding);
238 EVP_DecryptFinal(&cipher, pDecryptionBuffer + nSize, &nSize);
239 EVP_CIPHER_CTX_cleanup(&cipher);
240
241 pClearMsg = (CSCP_MESSAGE *)(pDecryptionBuffer + CSCP_EH_ENCRYPTED_BYTES);
242 dwMsgSize = ntohl(pClearMsg->dwSize);
243 if (dwMsgSize > pMsg->dwSize)
244 return FALSE; // Message decrypted incorrectly, because it can't be larger than encrypted
245 dwChecksum = CalculateCRC32((BYTE *)pClearMsg, dwMsgSize, 0);
246 if (dwChecksum != ntohl(((CSCP_ENCRYPTED_PAYLOAD_HEADER *)pDecryptionBuffer)->dwChecksum))
247 return FALSE; // Bad checksum
248
249 memcpy(pMsg, pClearMsg, dwMsgSize);
250 return TRUE;
251 #else /* _WITH_ENCRYPTION */
252 return FALSE;
253 #endif
254 }
255
256
257 //
258 // Destroy encryption context
259 //
260
261 void LIBNETXMS_EXPORTABLE DestroyEncryptionContext(CSCP_ENCRYPTION_CONTEXT *pCtx)
262 {
263 if ((pCtx != NULL) && (pCtx != PROXY_ENCRYPTION_CTX))
264 {
265 safe_free(pCtx->pSessionKey);
266 free(pCtx);
267 }
268 }
269
270
271 //
272 // Setup encryption context
273 // Function will determine is it called on initiator or responder side
274 // by message code. Initiator should provide it's private key,
275 // and responder should provide pointer to response message.
276 //
277
278 DWORD LIBNETXMS_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg,
279 CSCP_ENCRYPTION_CONTEXT **ppCtx,
280 CSCPMessage **ppResponse,
281 RSA *pPrivateKey, int nNXCPVersion)
282 {
283 DWORD dwResult = RCC_NOT_IMPLEMENTED;
284
285 #ifdef _WITH_ENCRYPTION
286 if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
287 {
288 DWORD dwCiphers;
289
290 *ppResponse = new CSCPMessage(nNXCPVersion);
291 (*ppResponse)->SetCode(CMD_SESSION_KEY);
292 (*ppResponse)->SetId(pMsg->GetId());
293 (*ppResponse)->DisableEncryption();
294
295 dwCiphers = pMsg->GetVariableLong(VID_SUPPORTED_ENCRYPTION) & m_dwSupportedCiphers;
296 if (dwCiphers == 0)
297 {
298 (*ppResponse)->SetVariable(VID_RCC, RCC_NO_CIPHERS);
299 dwResult = RCC_NO_CIPHERS;
300 }
301 else
302 {
303 BYTE *pBufPos, ucKeyBuffer[KEY_BUFFER_SIZE];
304 RSA *pServerKey;
305 DWORD dwKeySize;
306
307 // Create new context
308 *ppCtx = (CSCP_ENCRYPTION_CONTEXT *)malloc(sizeof(CSCP_ENCRYPTION_CONTEXT));
309
310 // Select cipher
311 if (dwCiphers & CSCP_SUPPORT_AES_256)
312 {
313 (*ppCtx)->nCipher = CSCP_CIPHER_AES_256;
314 (*ppCtx)->nKeyLen = 32;
315 }
316 else if (dwCiphers & CSCP_SUPPORT_BLOWFISH)
317 {
318 (*ppCtx)->nCipher = CSCP_CIPHER_BLOWFISH;
319 (*ppCtx)->nKeyLen = 32;
320 }
321 else if (dwCiphers & CSCP_SUPPORT_IDEA)
322 {
323 (*ppCtx)->nCipher = CSCP_CIPHER_IDEA;
324 (*ppCtx)->nKeyLen = 16;
325 }
326 else if (dwCiphers & CSCP_SUPPORT_3DES)
327 {
328 (*ppCtx)->nCipher = CSCP_CIPHER_3DES;
329 (*ppCtx)->nKeyLen = 24;
330 }
331
332 // Generate key
333 (*ppCtx)->pSessionKey = (BYTE *)malloc((*ppCtx)->nKeyLen);
334 RAND_bytes((*ppCtx)->pSessionKey, (*ppCtx)->nKeyLen);
335 RAND_bytes((*ppCtx)->iv, EVP_MAX_IV_LENGTH);
336
337 // Encrypt key
338 dwKeySize = pMsg->GetVariableBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
339 pBufPos = ucKeyBuffer;
340 pServerKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwKeySize);
341 if (pServerKey != NULL)
342 {
343 (*ppResponse)->SetVariable(VID_RCC, RCC_SUCCESS);
344 dwKeySize = RSA_public_encrypt((*ppCtx)->nKeyLen, (*ppCtx)->pSessionKey,
345 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
346 (*ppResponse)->SetVariable(VID_SESSION_KEY, ucKeyBuffer, dwKeySize);
347 dwKeySize = RSA_public_encrypt(EVP_MAX_IV_LENGTH, (*ppCtx)->iv,
348 ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
349 (*ppResponse)->SetVariable(VID_SESSION_IV, ucKeyBuffer, dwKeySize);
350 (*ppResponse)->SetVariable(VID_CIPHER, (WORD)(*ppCtx)->nCipher);
351 (*ppResponse)->SetVariable(VID_KEY_LENGTH, (WORD)(*ppCtx)->nKeyLen);
352 (*ppResponse)->SetVariable(VID_IV_LENGTH, (WORD)EVP_MAX_IV_LENGTH);
353 RSA_free(pServerKey);
354 dwResult = RCC_SUCCESS;
355 }
356 else
357 {
358 (*ppResponse)->SetVariable(VID_RCC, RCC_INVALID_PUBLIC_KEY);
359 dwResult = RCC_INVALID_PUBLIC_KEY;
360 }
361 }
362 }
363 else if (pMsg->GetCode() == CMD_SESSION_KEY)
364 {
365 dwResult = pMsg->GetVariableLong(VID_RCC);
366 if (dwResult == RCC_SUCCESS)
367 {
368 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
369 DWORD dwKeySize;
370 int nSize, nIVLen;
371
372 // Create new context
373 *ppCtx = (CSCP_ENCRYPTION_CONTEXT *)malloc(sizeof(CSCP_ENCRYPTION_CONTEXT));
374 (*ppCtx)->nCipher = pMsg->GetVariableShort(VID_CIPHER);
375 (*ppCtx)->nKeyLen = pMsg->GetVariableShort(VID_KEY_LENGTH);
376 (*ppCtx)->pSessionKey = (BYTE *)malloc((*ppCtx)->nKeyLen);
377
378 // Decrypt session key
379 dwKeySize = pMsg->GetVariableBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
380 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey,
381 pPrivateKey, RSA_PKCS1_OAEP_PADDING);
382 if (nSize == (*ppCtx)->nKeyLen)
383 {
384 memcpy((*ppCtx)->pSessionKey, ucSessionKey, nSize);
385
386 // Decrypt session IV
387 nIVLen = pMsg->GetVariableShort(VID_IV_LENGTH);
388 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
389 nIVLen = 16;
390 dwKeySize = pMsg->GetVariableBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
391 nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey,
392 pPrivateKey, RSA_PKCS1_OAEP_PADDING);
393 if ((nSize == nIVLen) &&
394 (nIVLen <= EVP_CIPHER_iv_length(m_pfCipherList[(*ppCtx)->nCipher]())))
395 {
396 memcpy((*ppCtx)->iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
397 }
398 else
399 {
400 dwResult = RCC_INVALID_SESSION_KEY;
401 }
402 }
403 else
404 {
405 dwResult = RCC_INVALID_SESSION_KEY;
406 }
407 }
408 }
409
410 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
411 {
412 DestroyEncryptionContext(*ppCtx);
413 *ppCtx = NULL;
414 }
415 #else
416 if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
417 {
418 *ppResponse = new CSCPMessage(nNXCPVersion);
419 (*ppResponse)->SetCode(CMD_SESSION_KEY);
420 (*ppResponse)->SetId(pMsg->GetId());
421 (*ppResponse)->DisableEncryption();
422 (*ppResponse)->SetVariable(VID_RCC, dwResult);
423 }
424 #endif
425
426 return dwResult;
427 }
428
429
430 //
431 // Prepare session key request message
432 //
433
434 void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(CSCPMessage *pMsg, RSA *pServerKey)
435 {
436 #ifdef _WITH_ENCRYPTION
437 int iLen;
438 BYTE *pKeyBuffer, *pBufPos;
439
440 pMsg->SetCode(CMD_REQUEST_SESSION_KEY);
441 pMsg->SetVariable(VID_SUPPORTED_ENCRYPTION, m_dwSupportedCiphers);
442
443 iLen = i2d_RSAPublicKey(pServerKey, NULL);
444 pKeyBuffer = (BYTE *)malloc(iLen);
445 pBufPos = pKeyBuffer;
446 i2d_RSAPublicKey(pServerKey, &pBufPos);
447 pMsg->SetVariable(VID_PUBLIC_KEY, pKeyBuffer, iLen);
448 free(pKeyBuffer);
449 #endif
450 }
451
452
453 //
454 // Load RSA key(s) from file
455 //
456
457 RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
458 {
459 #ifdef _WITH_ENCRYPTION
460 FILE *fp;
461 BYTE *pKeyBuffer, *pBufPos, hash[SHA1_DIGEST_SIZE];
462 DWORD dwLen;
463 RSA *pKey = NULL;
464
465 fp = _tfopen(pszKeyFile, _T("rb"));
466 if (fp != NULL)
467 {
468 if (fread(&dwLen, 1, sizeof(DWORD), fp) == sizeof(DWORD) && dwLen < 10 * 1024)
469 {
470 pKeyBuffer = (BYTE *)malloc(dwLen);
471 pBufPos = pKeyBuffer;
472 if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
473 {
474 BYTE hash2[SHA1_DIGEST_SIZE];
475
476 fread(hash, 1, SHA1_DIGEST_SIZE, fp);
477 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
478 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
479 {
480 pKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwLen);
481 if (pKey != NULL)
482 {
483 if (d2i_RSAPrivateKey(&pKey, (OPENSSL_CONST BYTE **)&pBufPos,
484 dwLen - CAST_FROM_POINTER((pBufPos - pKeyBuffer), DWORD)) == NULL)
485 {
486 RSA_free(pKey);
487 pKey = NULL;
488 }
489 }
490 }
491 }
492 free(pKeyBuffer);
493 }
494 fclose(fp);
495 }
496
497 return pKey;
498 #else
499 return NULL;
500 #endif
501 }
502
503
504 //
505 // Create signature for message using certificate (MS CAPI version)
506 // Paraeters:
507 // pMsg and dwMsgLen - message to sign and it's length
508 // pCert - certificate
509 // pBuffer - output buffer
510 // dwBufSize - buffer size
511 // pdwSigLen - actual signature size
512 //
513
514 #ifdef _WIN32
515
516 BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *pMsg, DWORD dwMsgLen, const CERT_CONTEXT *pCert,
517 BYTE *pBuffer, DWORD dwBufSize, DWORD *pdwSigLen)
518 {
519 BOOL bFreeProv, bRet = FALSE;
520 DWORD i, j, dwLen, dwKeySpec;
521 HCRYPTPROV hProv;
522 HCRYPTHASH hHash;
523 BYTE *pTemp;
524
525 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
526 NULL, &hProv, &dwKeySpec, &bFreeProv))
527 {
528 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
529 {
530 if (CryptHashData(hHash, pMsg, dwMsgLen, 0))
531 {
532 dwLen = dwBufSize;
533 pTemp = (BYTE *)malloc(dwBufSize);;
534 bRet = CryptSignHash(hHash, dwKeySpec, NULL, 0, pTemp, &dwLen);
535 *pdwSigLen = dwLen;
536 // we have to reverse the byte-order in the result from CryptSignHash()
537 for(i = 0, j = dwLen - 1; i < dwLen; i++, j--)
538 pBuffer[i] = pTemp[j];
539 }
540 CryptDestroyHash(hHash);
541 }
542
543 if (bFreeProv)
544 CryptReleaseContext(hProv, 0);
545 }
546 return bRet;
547 }
548
549 #endif
550
551
552 //
553 // Encrypt data block with ICE
554 //
555
556 void LIBNETXMS_EXPORTABLE ICEEncryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
557 {
558 ICE_KEY *ice = ice_key_create(1);
559 ice_key_set(ice, key);
560
561 int stopPos = inLen - (inLen % 8);
562 const BYTE *curr = in;
563 for(int pos = 0; pos < stopPos; pos += 8)
564 ice_key_encrypt(ice, &in[pos], &out[pos]);
565
566 if (stopPos < inLen)
567 {
568 BYTE plainText[8], encrypted[8];
569
570 memcpy(plainText, &in[stopPos], inLen - stopPos);
571 ice_key_encrypt(ice, plainText, encrypted);
572 memcpy(&out[stopPos], encrypted, inLen - stopPos);
573 }
574
575 ice_key_destroy(ice);
576 }
577
578
579 //
580 // Decrypt data block with ICE
581 //
582
583 void LIBNETXMS_EXPORTABLE ICEDecryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
584 {
585 ICE_KEY *ice = ice_key_create(1);
586 ice_key_set(ice, key);
587
588 int stopPos = inLen - (inLen % 8);
589 const BYTE *curr = in;
590 for(int pos = 0; pos < stopPos; pos += 8)
591 ice_key_decrypt(ice, &in[pos], &out[pos]);
592
593 if (stopPos < inLen)
594 {
595 BYTE plainText[8], encrypted[8];
596
597 memcpy(encrypted, &in[stopPos], inLen - stopPos);
598 ice_key_decrypt(ice, encrypted, plainText);
599 memcpy(&out[stopPos], plainText, inLen - stopPos);
600 }
601
602 ice_key_destroy(ice);
603 }