Commit | Line | Data |
---|---|---|
5039dede AK |
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" | |
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 | ||
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 | { | |
6d738067 | 468 | if (fread(&dwLen, 1, sizeof(DWORD), fp) == sizeof(DWORD) && dwLen < 10 * 1024) |
5039dede AK |
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 | |
4e2debcc VK |
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 | } |