/src/libxslt/libexslt/crypto.c
Line | Count | Source |
1 | | #define IN_LIBEXSLT |
2 | | #include "libexslt/libexslt.h" |
3 | | |
4 | | #include <libxml/tree.h> |
5 | | #include <libxml/xpath.h> |
6 | | #include <libxml/xpathInternals.h> |
7 | | #include <libxml/parser.h> |
8 | | #include <libxml/encoding.h> |
9 | | #include <libxml/uri.h> |
10 | | #include <libxml/threads.h> |
11 | | |
12 | | #include <libxslt/xsltutils.h> |
13 | | #include <libxslt/xsltInternals.h> |
14 | | #include <libxslt/extensions.h> |
15 | | |
16 | | #include "exslt.h" |
17 | | |
18 | | #ifdef EXSLT_CRYPTO_ENABLED |
19 | | |
20 | | #define HASH_DIGEST_LENGTH 32 |
21 | | #define MD5_DIGEST_LENGTH 16 |
22 | | #define SHA1_DIGEST_LENGTH 20 |
23 | | |
24 | | /* gcrypt rc4 can do 256 bit keys, but cryptoapi limit |
25 | | seems to be 128 for the default provider */ |
26 | 8.66k | #define RC4_KEY_LENGTH 128 |
27 | | |
28 | | /* The following routines have been declared static - this should be |
29 | | reviewed to consider whether we want to expose them to the API |
30 | | exsltCryptoBin2Hex |
31 | | exsltCryptoHex2Bin |
32 | | exsltCryptoGcryptInit |
33 | | exsltCryptoGcryptHash |
34 | | exsltCryptoGcryptRc4Encrypt |
35 | | exsltCryptoGcryptRC4Decrypt |
36 | | */ |
37 | | |
38 | | /** |
39 | | * exsltCryptoBin2Hex: |
40 | | * @bin: binary blob to convert |
41 | | * @binlen: length of binary blob |
42 | | * @hex: buffer to store hex version of blob |
43 | | * @hexlen: length of buffer to store hex version of blob |
44 | | * |
45 | | * Helper function which encodes a binary blob as hex. |
46 | | */ |
47 | | static void |
48 | | exsltCryptoBin2Hex (const unsigned char *bin, int binlen, |
49 | 2.23k | unsigned char *hex, int hexlen) { |
50 | 2.23k | static const char bin2hex[] = { '0', '1', '2', '3', |
51 | 2.23k | '4', '5', '6', '7', |
52 | 2.23k | '8', '9', 'a', 'b', |
53 | 2.23k | 'c', 'd', 'e', 'f' |
54 | 2.23k | }; |
55 | | |
56 | 2.23k | unsigned char lo, hi; |
57 | 2.23k | int i, pos; |
58 | 44.7k | for (i = 0, pos = 0; (i < binlen && pos < hexlen); i++) { |
59 | 42.5k | lo = bin[i] & 0xf; |
60 | 42.5k | hi = bin[i] >> 4; |
61 | 42.5k | hex[pos++] = bin2hex[hi]; |
62 | 42.5k | hex[pos++] = bin2hex[lo]; |
63 | 42.5k | } |
64 | | |
65 | 2.23k | hex[pos] = '\0'; |
66 | 2.23k | } |
67 | | |
68 | | /** |
69 | | * exsltCryptoHex2Bin: |
70 | | * @hex: hex version of blob to convert |
71 | | * @hexlen: length of hex buffer |
72 | | * @bin: destination binary buffer |
73 | | * @binlen: length of binary buffer |
74 | | * |
75 | | * Helper function which decodes a hex blob to binary |
76 | | */ |
77 | | static int |
78 | | exsltCryptoHex2Bin (const unsigned char *hex, int hexlen, |
79 | 1.95k | unsigned char *bin, int binlen) { |
80 | 1.95k | int i = 0, j = 0; |
81 | 1.95k | unsigned char lo, hi, result, tmp; |
82 | | |
83 | 17.6k | while (i < hexlen && j < binlen) { |
84 | 15.7k | hi = lo = 0; |
85 | | |
86 | 15.7k | tmp = hex[i++]; |
87 | 15.7k | if (tmp >= '0' && tmp <= '9') |
88 | 5.08k | hi = tmp - '0'; |
89 | 10.6k | else if (tmp >= 'a' && tmp <= 'f') |
90 | 3.89k | hi = 10 + (tmp - 'a'); |
91 | | |
92 | 15.7k | tmp = hex[i++]; |
93 | 15.7k | if (tmp >= '0' && tmp <= '9') |
94 | 4.65k | lo = tmp - '0'; |
95 | 11.0k | else if (tmp >= 'a' && tmp <= 'f') |
96 | 3.47k | lo = 10 + (tmp - 'a'); |
97 | | |
98 | 15.7k | result = hi << 4; |
99 | 15.7k | result += lo; |
100 | 15.7k | bin[j++] = result; |
101 | 15.7k | } |
102 | | |
103 | 1.95k | return j; |
104 | 1.95k | } |
105 | | |
106 | | #if defined(_WIN32) |
107 | | |
108 | | #define HAVE_CRYPTO |
109 | | #define PLATFORM_HASH exsltCryptoCryptoApiHash |
110 | | #define PLATFORM_RC4_ENCRYPT exsltCryptoCryptoApiRc4Encrypt |
111 | | #define PLATFORM_RC4_DECRYPT exsltCryptoCryptoApiRc4Decrypt |
112 | | #define PLATFORM_MD4 CALG_MD4 |
113 | | #define PLATFORM_MD5 CALG_MD5 |
114 | | #define PLATFORM_SHA1 CALG_SHA1 |
115 | | |
116 | | #include <windows.h> |
117 | | #include <wincrypt.h> |
118 | | #ifdef _MSC_VER |
119 | | #pragma comment(lib, "advapi32.lib") |
120 | | #endif |
121 | | |
122 | | static void |
123 | | exsltCryptoCryptoApiReportError (xmlXPathParserContextPtr ctxt, |
124 | | int line) { |
125 | | char *lpMsgBuf; |
126 | | DWORD dw = GetLastError (); |
127 | | |
128 | | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
129 | | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, |
130 | | MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), |
131 | | (LPSTR)&lpMsgBuf, 0, NULL); |
132 | | |
133 | | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, |
134 | | "exslt:crypto error (line %d). %s", line, |
135 | | lpMsgBuf); |
136 | | LocalFree (lpMsgBuf); |
137 | | } |
138 | | |
139 | | static HCRYPTHASH |
140 | | exsltCryptoCryptoApiCreateHash (xmlXPathParserContextPtr ctxt, |
141 | | HCRYPTPROV hCryptProv, ALG_ID algorithm, |
142 | | const unsigned char *msg, unsigned int msglen, |
143 | | char *dest, unsigned int destlen) |
144 | | { |
145 | | HCRYPTHASH hHash = 0; |
146 | | DWORD dwHashLen = destlen; |
147 | | |
148 | | if (!CryptCreateHash (hCryptProv, algorithm, 0, 0, &hHash)) { |
149 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
150 | | return 0; |
151 | | } |
152 | | |
153 | | if (!CryptHashData (hHash, msg, msglen, 0)) { |
154 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
155 | | goto fail; |
156 | | } |
157 | | |
158 | | if (!CryptGetHashParam (hHash, HP_HASHVAL, (BYTE *) dest, &dwHashLen, 0)) { |
159 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
160 | | goto fail; |
161 | | } |
162 | | |
163 | | fail: |
164 | | return hHash; |
165 | | } |
166 | | |
167 | | /** |
168 | | * exsltCryptoCryptoApiHash: |
169 | | * @ctxt: an XPath parser context |
170 | | * @algorithm: hashing algorithm to use |
171 | | * @msg: text to be hashed |
172 | | * @msglen: length of text to be hashed |
173 | | * @dest: buffer to place hash result |
174 | | * |
175 | | * Helper function which hashes a message using MD4, MD5, or SHA1. |
176 | | * Uses Win32 CryptoAPI. |
177 | | */ |
178 | | static void |
179 | | exsltCryptoCryptoApiHash (xmlXPathParserContextPtr ctxt, |
180 | | ALG_ID algorithm, const char *msg, |
181 | | unsigned long msglen, |
182 | | char dest[HASH_DIGEST_LENGTH]) { |
183 | | HCRYPTPROV hCryptProv; |
184 | | HCRYPTHASH hHash; |
185 | | |
186 | | if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, |
187 | | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { |
188 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
189 | | return; |
190 | | } |
191 | | |
192 | | hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, |
193 | | algorithm, (unsigned char *) msg, |
194 | | msglen, dest, HASH_DIGEST_LENGTH); |
195 | | if (0 != hHash) { |
196 | | CryptDestroyHash (hHash); |
197 | | } |
198 | | |
199 | | CryptReleaseContext (hCryptProv, 0); |
200 | | } |
201 | | |
202 | | static void |
203 | | exsltCryptoCryptoApiRc4Encrypt (xmlXPathParserContextPtr ctxt, |
204 | | const unsigned char *key, |
205 | | const unsigned char *msg, int msglen, |
206 | | unsigned char *dest, int destlen) { |
207 | | HCRYPTPROV hCryptProv; |
208 | | HCRYPTKEY hKey; |
209 | | HCRYPTHASH hHash; |
210 | | DWORD dwDataLen; |
211 | | char hash[HASH_DIGEST_LENGTH]; |
212 | | |
213 | | if (msglen > destlen) { |
214 | | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
215 | | NULL, |
216 | | "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); |
217 | | return; |
218 | | } |
219 | | |
220 | | if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, |
221 | | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { |
222 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
223 | | return; |
224 | | } |
225 | | |
226 | | hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, |
227 | | CALG_SHA1, key, |
228 | | RC4_KEY_LENGTH, hash, |
229 | | HASH_DIGEST_LENGTH); |
230 | | |
231 | | if (!CryptDeriveKey |
232 | | (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { |
233 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
234 | | goto fail; |
235 | | } |
236 | | /* Now encrypt data. */ |
237 | | dwDataLen = msglen; |
238 | | memcpy (dest, msg, msglen); |
239 | | if (!CryptEncrypt (hKey, 0, TRUE, 0, dest, &dwDataLen, msglen)) { |
240 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
241 | | goto fail; |
242 | | } |
243 | | |
244 | | fail: |
245 | | if (0 != hHash) { |
246 | | CryptDestroyHash (hHash); |
247 | | } |
248 | | |
249 | | CryptDestroyKey (hKey); |
250 | | CryptReleaseContext (hCryptProv, 0); |
251 | | } |
252 | | |
253 | | static void |
254 | | exsltCryptoCryptoApiRc4Decrypt (xmlXPathParserContextPtr ctxt, |
255 | | const unsigned char *key, |
256 | | const unsigned char *msg, int msglen, |
257 | | unsigned char *dest, int destlen) { |
258 | | HCRYPTPROV hCryptProv; |
259 | | HCRYPTKEY hKey; |
260 | | HCRYPTHASH hHash; |
261 | | DWORD dwDataLen; |
262 | | char hash[HASH_DIGEST_LENGTH]; |
263 | | |
264 | | if (msglen > destlen) { |
265 | | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
266 | | NULL, |
267 | | "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); |
268 | | return; |
269 | | } |
270 | | |
271 | | if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, |
272 | | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { |
273 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
274 | | return; |
275 | | } |
276 | | |
277 | | hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, |
278 | | CALG_SHA1, key, |
279 | | RC4_KEY_LENGTH, hash, |
280 | | HASH_DIGEST_LENGTH); |
281 | | |
282 | | if (!CryptDeriveKey |
283 | | (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { |
284 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
285 | | goto fail; |
286 | | } |
287 | | /* Now encrypt data. */ |
288 | | dwDataLen = msglen; |
289 | | memcpy (dest, msg, msglen); |
290 | | if (!CryptDecrypt (hKey, 0, TRUE, 0, dest, &dwDataLen)) { |
291 | | exsltCryptoCryptoApiReportError (ctxt, __LINE__); |
292 | | goto fail; |
293 | | } |
294 | | |
295 | | fail: |
296 | | if (0 != hHash) { |
297 | | CryptDestroyHash (hHash); |
298 | | } |
299 | | |
300 | | CryptDestroyKey (hKey); |
301 | | CryptReleaseContext (hCryptProv, 0); |
302 | | } |
303 | | |
304 | | #endif /* defined(_WIN32) */ |
305 | | |
306 | | #if defined(HAVE_GCRYPT) |
307 | | |
308 | | #define HAVE_CRYPTO |
309 | 2.20k | #define PLATFORM_HASH exsltCryptoGcryptHash |
310 | 34 | #define PLATFORM_RC4_ENCRYPT exsltCryptoGcryptRc4Encrypt |
311 | 1.95k | #define PLATFORM_RC4_DECRYPT exsltCryptoGcryptRc4Decrypt |
312 | 1.50k | #define PLATFORM_MD4 GCRY_MD_MD4 |
313 | 146 | #define PLATFORM_MD5 GCRY_MD_MD5 |
314 | 554 | #define PLATFORM_SHA1 GCRY_MD_SHA1 |
315 | | |
316 | | #ifdef HAVE_SYS_TYPES_H |
317 | | # include <sys/types.h> |
318 | | #endif |
319 | | |
320 | | #ifdef HAVE_SYS_SELECT_H |
321 | | #include <sys/select.h> /* needed by gcrypt.h 4 Jul 04 */ |
322 | | #endif |
323 | | #include <gcrypt.h> |
324 | | |
325 | | static void |
326 | 4.19k | exsltCryptoGcryptInit (void) { |
327 | 4.19k | static int gcrypt_init; |
328 | 4.19k | xmlLockLibrary (); |
329 | | |
330 | 4.19k | if (!gcrypt_init) { |
331 | | /* The function `gcry_check_version' must be called before any other |
332 | | function in the library, because it initializes the thread support |
333 | | subsystem in Libgcrypt. To achieve this in all generality, it is |
334 | | necessary to synchronize the call to this function with all other calls |
335 | | to functions in the library, using the synchronization mechanisms |
336 | | available in your thread library. (from gcrypt.info) |
337 | | */ |
338 | 2 | gcry_check_version (GCRYPT_VERSION); |
339 | 2 | gcrypt_init = 1; |
340 | 2 | } |
341 | | |
342 | 4.19k | xmlUnlockLibrary (); |
343 | 4.19k | } |
344 | | |
345 | | /** |
346 | | * exsltCryptoGcryptHash: |
347 | | * @ctxt: an XPath parser context |
348 | | * @algorithm: hashing algorithm to use |
349 | | * @msg: text to be hashed |
350 | | * @msglen: length of text to be hashed |
351 | | * @dest: buffer to place hash result |
352 | | * |
353 | | * Helper function which hashes a message using MD4, MD5, or SHA1. |
354 | | * using gcrypt |
355 | | */ |
356 | | static void |
357 | | exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED, |
358 | | /* changed the enum to int */ |
359 | | int algorithm, const char *msg, |
360 | | unsigned long msglen, |
361 | 2.20k | char dest[HASH_DIGEST_LENGTH]) { |
362 | 2.20k | exsltCryptoGcryptInit (); |
363 | 2.20k | gcry_md_hash_buffer (algorithm, dest, msg, msglen); |
364 | 2.20k | } |
365 | | |
366 | | static void |
367 | | exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt, |
368 | | const unsigned char *key, |
369 | | const unsigned char *msg, int msglen, |
370 | 34 | unsigned char *dest, int destlen) { |
371 | 34 | gcry_cipher_hd_t cipher; |
372 | 34 | gcry_error_t rc = 0; |
373 | | |
374 | 34 | exsltCryptoGcryptInit (); |
375 | | |
376 | 34 | rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, |
377 | 34 | GCRY_CIPHER_MODE_STREAM, 0); |
378 | 34 | if (rc) { |
379 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
380 | 0 | NULL, |
381 | 0 | "exslt:crypto internal error %s (gcry_cipher_open)\n", |
382 | 0 | gcry_strerror (rc)); |
383 | 0 | } |
384 | | |
385 | 34 | rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); |
386 | 34 | if (rc) { |
387 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
388 | 0 | NULL, |
389 | 0 | "exslt:crypto internal error %s (gcry_cipher_setkey)\n", |
390 | 0 | gcry_strerror (rc)); |
391 | 0 | } |
392 | | |
393 | 34 | rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen, |
394 | 34 | (const unsigned char *) msg, msglen); |
395 | 34 | if (rc) { |
396 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
397 | 0 | NULL, |
398 | 0 | "exslt:crypto internal error %s (gcry_cipher_encrypt)\n", |
399 | 0 | gcry_strerror (rc)); |
400 | 0 | } |
401 | | |
402 | 34 | gcry_cipher_close (cipher); |
403 | 34 | } |
404 | | |
405 | | static void |
406 | | exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt, |
407 | | const unsigned char *key, |
408 | | const unsigned char *msg, int msglen, |
409 | 1.95k | unsigned char *dest, int destlen) { |
410 | 1.95k | gcry_cipher_hd_t cipher; |
411 | 1.95k | gcry_error_t rc = 0; |
412 | | |
413 | 1.95k | exsltCryptoGcryptInit (); |
414 | | |
415 | 1.95k | rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, |
416 | 1.95k | GCRY_CIPHER_MODE_STREAM, 0); |
417 | 1.95k | if (rc) { |
418 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
419 | 0 | NULL, |
420 | 0 | "exslt:crypto internal error %s (gcry_cipher_open)\n", |
421 | 0 | gcry_strerror (rc)); |
422 | 0 | } |
423 | | |
424 | 1.95k | rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); |
425 | 1.95k | if (rc) { |
426 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
427 | 0 | NULL, |
428 | 0 | "exslt:crypto internal error %s (gcry_cipher_setkey)\n", |
429 | 0 | gcry_strerror (rc)); |
430 | 0 | } |
431 | | |
432 | 1.95k | rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen, |
433 | 1.95k | (const unsigned char *) msg, msglen); |
434 | 1.95k | if (rc) { |
435 | 0 | xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, |
436 | 0 | NULL, |
437 | 0 | "exslt:crypto internal error %s (gcry_cipher_decrypt)\n", |
438 | 0 | gcry_strerror (rc)); |
439 | 0 | } |
440 | | |
441 | 1.95k | gcry_cipher_close (cipher); |
442 | 1.95k | } |
443 | | |
444 | | #endif /* defined(HAVE_GCRYPT) */ |
445 | | |
446 | | #if defined(HAVE_CRYPTO) |
447 | | |
448 | | /** |
449 | | * exsltCryptoPopString: |
450 | | * @ctxt: an XPath parser context |
451 | | * @nargs: the number of arguments |
452 | | * |
453 | | * Helper function which checks for and returns first string argument and its |
454 | | * length in bytes. |
455 | | */ |
456 | | static int |
457 | | exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs, |
458 | 3.55k | xmlChar ** str) { |
459 | | |
460 | 3.55k | int str_len = 0; |
461 | | |
462 | 3.55k | if ((nargs < 1) || (nargs > 2)) { |
463 | 3 | xmlXPathSetArityError (ctxt); |
464 | 3 | return 0; |
465 | 3 | } |
466 | | |
467 | 3.55k | *str = xmlXPathPopString (ctxt); |
468 | 3.55k | str_len = xmlStrlen (*str); |
469 | | |
470 | 3.55k | if (str_len == 0) { |
471 | 1.34k | xmlXPathReturnEmptyString (ctxt); |
472 | 1.34k | xmlFree (*str); |
473 | 1.34k | return 0; |
474 | 1.34k | } |
475 | | |
476 | 2.20k | return str_len; |
477 | 3.55k | } |
478 | | |
479 | | /** |
480 | | * exsltCryptoMd4Function: |
481 | | * @ctxt: an XPath parser context |
482 | | * @nargs: the number of arguments |
483 | | * |
484 | | * computes the md4 hash of a string and returns as hex |
485 | | */ |
486 | | static void |
487 | 2.28k | exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) { |
488 | | |
489 | 2.28k | int str_len = 0; |
490 | 2.28k | xmlChar *str = NULL, *ret = NULL; |
491 | 2.28k | unsigned char hash[HASH_DIGEST_LENGTH]; |
492 | 2.28k | unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; |
493 | | |
494 | 2.28k | str_len = exsltCryptoPopString (ctxt, nargs, &str); |
495 | 2.28k | if (str_len == 0) |
496 | 785 | return; |
497 | | |
498 | 1.50k | PLATFORM_HASH (ctxt, PLATFORM_MD4, (const char *) str, str_len, |
499 | 1.50k | (char *) hash); |
500 | 1.50k | exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); |
501 | | |
502 | 1.50k | ret = xmlStrdup ((xmlChar *) hex); |
503 | 1.50k | xmlXPathReturnString (ctxt, ret); |
504 | | |
505 | 1.50k | if (str != NULL) |
506 | 1.50k | xmlFree (str); |
507 | 1.50k | } |
508 | | |
509 | | /** |
510 | | * exsltCryptoMd5Function: |
511 | | * @ctxt: an XPath parser context |
512 | | * @nargs: the number of arguments |
513 | | * |
514 | | * computes the md5 hash of a string and returns as hex |
515 | | */ |
516 | | static void |
517 | 383 | exsltCryptoMd5Function (xmlXPathParserContextPtr ctxt, int nargs) { |
518 | | |
519 | 383 | int str_len = 0; |
520 | 383 | xmlChar *str = NULL, *ret = NULL; |
521 | 383 | unsigned char hash[HASH_DIGEST_LENGTH]; |
522 | 383 | unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; |
523 | | |
524 | 383 | str_len = exsltCryptoPopString (ctxt, nargs, &str); |
525 | 383 | if (str_len == 0) |
526 | 237 | return; |
527 | | |
528 | 146 | PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len, |
529 | 146 | (char *) hash); |
530 | 146 | exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); |
531 | | |
532 | 146 | ret = xmlStrdup ((xmlChar *) hex); |
533 | 146 | xmlXPathReturnString (ctxt, ret); |
534 | | |
535 | 146 | if (str != NULL) |
536 | 146 | xmlFree (str); |
537 | 146 | } |
538 | | |
539 | | /** |
540 | | * exsltCryptoSha1Function: |
541 | | * @ctxt: an XPath parser context |
542 | | * @nargs: the number of arguments |
543 | | * |
544 | | * computes the sha1 hash of a string and returns as hex |
545 | | */ |
546 | | static void |
547 | 884 | exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) { |
548 | | |
549 | 884 | int str_len = 0; |
550 | 884 | xmlChar *str = NULL, *ret = NULL; |
551 | 884 | unsigned char hash[HASH_DIGEST_LENGTH]; |
552 | 884 | unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1]; |
553 | | |
554 | 884 | str_len = exsltCryptoPopString (ctxt, nargs, &str); |
555 | 884 | if (str_len == 0) |
556 | 330 | return; |
557 | | |
558 | 554 | PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len, |
559 | 554 | (char *) hash); |
560 | 554 | exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); |
561 | | |
562 | 554 | ret = xmlStrdup ((xmlChar *) hex); |
563 | 554 | xmlXPathReturnString (ctxt, ret); |
564 | | |
565 | 554 | if (str != NULL) |
566 | 554 | xmlFree (str); |
567 | 554 | } |
568 | | |
569 | | /** |
570 | | * exsltCryptoRc4EncryptFunction: |
571 | | * @ctxt: an XPath parser context |
572 | | * @nargs: the number of arguments |
573 | | * |
574 | | * computes the sha1 hash of a string and returns as hex |
575 | | */ |
576 | | static void |
577 | 285 | exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
578 | | |
579 | 285 | int key_len = 0; |
580 | 285 | int str_len = 0, bin_len = 0, hex_len = 0; |
581 | 285 | xmlChar *key = NULL, *str = NULL, *padkey = NULL; |
582 | 285 | xmlChar *bin = NULL, *hex = NULL; |
583 | 285 | xsltTransformContextPtr tctxt = NULL; |
584 | | |
585 | 285 | if (nargs != 2) { |
586 | 1 | xmlXPathSetArityError (ctxt); |
587 | 1 | return; |
588 | 1 | } |
589 | 284 | tctxt = xsltXPathGetTransformContext(ctxt); |
590 | | |
591 | 284 | str = xmlXPathPopString (ctxt); |
592 | 284 | str_len = xmlStrlen (str); |
593 | | |
594 | 284 | if (str_len == 0) { |
595 | 2 | xmlXPathReturnEmptyString (ctxt); |
596 | 2 | xmlFree (str); |
597 | 2 | return; |
598 | 2 | } |
599 | | |
600 | 282 | key = xmlXPathPopString (ctxt); |
601 | 282 | key_len = xmlStrlen (key); |
602 | | |
603 | 282 | if (key_len == 0) { |
604 | 21 | xmlXPathReturnEmptyString (ctxt); |
605 | 21 | xmlFree (key); |
606 | 21 | xmlFree (str); |
607 | 21 | return; |
608 | 21 | } |
609 | | |
610 | 261 | padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); |
611 | 261 | if (padkey == NULL) { |
612 | 1 | xsltTransformError(tctxt, NULL, tctxt->inst, |
613 | 1 | "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); |
614 | 1 | tctxt->state = XSLT_STATE_STOPPED; |
615 | 1 | xmlXPathReturnEmptyString (ctxt); |
616 | 1 | goto done; |
617 | 1 | } |
618 | 260 | memset(padkey, 0, RC4_KEY_LENGTH + 1); |
619 | | |
620 | 260 | if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) { |
621 | 225 | xsltTransformError(tctxt, NULL, tctxt->inst, |
622 | 225 | "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); |
623 | 225 | tctxt->state = XSLT_STATE_STOPPED; |
624 | 225 | xmlXPathReturnEmptyString (ctxt); |
625 | 225 | goto done; |
626 | 225 | } |
627 | 35 | memcpy (padkey, key, key_len); |
628 | | |
629 | | /* encrypt it */ |
630 | 35 | bin_len = str_len; |
631 | 35 | bin = xmlStrdup (str); |
632 | 35 | if (bin == NULL) { |
633 | 1 | xsltTransformError(tctxt, NULL, tctxt->inst, |
634 | 1 | "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); |
635 | 1 | tctxt->state = XSLT_STATE_STOPPED; |
636 | 1 | xmlXPathReturnEmptyString (ctxt); |
637 | 1 | goto done; |
638 | 1 | } |
639 | 34 | PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len); |
640 | | |
641 | | /* encode it */ |
642 | 34 | hex_len = str_len * 2 + 1; |
643 | 34 | hex = xmlMallocAtomic (hex_len); |
644 | 34 | if (hex == NULL) { |
645 | 1 | xsltTransformError(tctxt, NULL, tctxt->inst, |
646 | 1 | "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); |
647 | 1 | tctxt->state = XSLT_STATE_STOPPED; |
648 | 1 | xmlXPathReturnEmptyString (ctxt); |
649 | 1 | goto done; |
650 | 1 | } |
651 | | |
652 | 33 | exsltCryptoBin2Hex (bin, str_len, hex, hex_len); |
653 | 33 | xmlXPathReturnString (ctxt, hex); |
654 | | |
655 | 261 | done: |
656 | 261 | if (key != NULL) |
657 | 261 | xmlFree (key); |
658 | 261 | if (str != NULL) |
659 | 261 | xmlFree (str); |
660 | 261 | if (padkey != NULL) |
661 | 260 | xmlFree (padkey); |
662 | 261 | if (bin != NULL) |
663 | 34 | xmlFree (bin); |
664 | 261 | } |
665 | | |
666 | | /** |
667 | | * exsltCryptoRc4DecryptFunction: |
668 | | * @ctxt: an XPath parser context |
669 | | * @nargs: the number of arguments |
670 | | * |
671 | | * computes the sha1 hash of a string and returns as hex |
672 | | */ |
673 | | static void |
674 | 3.18k | exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
675 | | |
676 | 3.18k | int key_len = 0; |
677 | 3.18k | int str_len = 0, bin_len = 0, ret_len = 0; |
678 | 3.18k | xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin = |
679 | 3.18k | NULL, *ret = NULL; |
680 | 3.18k | xsltTransformContextPtr tctxt = NULL; |
681 | | |
682 | 3.18k | if (nargs != 2) { |
683 | 103 | xmlXPathSetArityError (ctxt); |
684 | 103 | return; |
685 | 103 | } |
686 | 3.08k | tctxt = xsltXPathGetTransformContext(ctxt); |
687 | | |
688 | 3.08k | str = xmlXPathPopString (ctxt); |
689 | 3.08k | str_len = xmlStrlen (str); |
690 | | |
691 | 3.08k | if (str_len == 0) { |
692 | 413 | xmlXPathReturnEmptyString (ctxt); |
693 | 413 | xmlFree (str); |
694 | 413 | return; |
695 | 413 | } |
696 | | |
697 | 2.66k | key = xmlXPathPopString (ctxt); |
698 | 2.66k | key_len = xmlStrlen (key); |
699 | | |
700 | 2.66k | if (key_len == 0) { |
701 | 704 | xmlXPathReturnEmptyString (ctxt); |
702 | 704 | xmlFree (key); |
703 | 704 | xmlFree (str); |
704 | 704 | return; |
705 | 704 | } |
706 | | |
707 | 1.96k | padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); |
708 | 1.96k | if (padkey == NULL) { |
709 | 2 | xsltTransformError(tctxt, NULL, tctxt->inst, |
710 | 2 | "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); |
711 | 2 | tctxt->state = XSLT_STATE_STOPPED; |
712 | 2 | xmlXPathReturnEmptyString (ctxt); |
713 | 2 | goto done; |
714 | 2 | } |
715 | 1.96k | memset(padkey, 0, RC4_KEY_LENGTH + 1); |
716 | 1.96k | if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) { |
717 | 1 | xsltTransformError(tctxt, NULL, tctxt->inst, |
718 | 1 | "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); |
719 | 1 | tctxt->state = XSLT_STATE_STOPPED; |
720 | 1 | xmlXPathReturnEmptyString (ctxt); |
721 | 1 | goto done; |
722 | 1 | } |
723 | 1.96k | memcpy (padkey, key, key_len); |
724 | | |
725 | | /* decode hex to binary */ |
726 | 1.96k | bin_len = str_len; |
727 | 1.96k | bin = xmlMallocAtomic (bin_len); |
728 | 1.96k | if (bin == NULL) { |
729 | 2 | xsltTransformError(tctxt, NULL, tctxt->inst, |
730 | 2 | "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); |
731 | 2 | tctxt->state = XSLT_STATE_STOPPED; |
732 | 2 | xmlXPathReturnEmptyString (ctxt); |
733 | 2 | goto done; |
734 | 2 | } |
735 | 1.95k | ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len); |
736 | | |
737 | | /* decrypt the binary blob */ |
738 | 1.95k | ret = xmlMallocAtomic (ret_len + 1); |
739 | 1.95k | if (ret == NULL) { |
740 | 1 | xsltTransformError(tctxt, NULL, tctxt->inst, |
741 | 1 | "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); |
742 | 1 | tctxt->state = XSLT_STATE_STOPPED; |
743 | 1 | xmlXPathReturnEmptyString (ctxt); |
744 | 1 | goto done; |
745 | 1 | } |
746 | 1.95k | PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len); |
747 | 1.95k | ret[ret_len] = 0; |
748 | | |
749 | 1.95k | if (xmlCheckUTF8(ret) == 0) { |
750 | 1.29k | xsltTransformError(tctxt, NULL, tctxt->inst, |
751 | 1.29k | "exsltCryptoRc4DecryptFunction: Invalid UTF-8\n"); |
752 | 1.29k | xmlFree(ret); |
753 | 1.29k | xmlXPathReturnEmptyString(ctxt); |
754 | 1.29k | } else { |
755 | 661 | xmlXPathReturnString(ctxt, ret); |
756 | 661 | } |
757 | | |
758 | 1.96k | done: |
759 | 1.96k | if (key != NULL) |
760 | 1.96k | xmlFree (key); |
761 | 1.96k | if (str != NULL) |
762 | 1.96k | xmlFree (str); |
763 | 1.96k | if (padkey != NULL) |
764 | 1.96k | xmlFree (padkey); |
765 | 1.96k | if (bin != NULL) |
766 | 1.95k | xmlFree (bin); |
767 | 1.96k | } |
768 | | |
769 | | /** |
770 | | * exsltCryptoRegister: |
771 | | * |
772 | | * Registers the EXSLT - Crypto module |
773 | | */ |
774 | | |
775 | | void |
776 | 4 | exsltCryptoRegister (void) { |
777 | 4 | xsltRegisterExtModuleFunction ((const xmlChar *) "md4", |
778 | 4 | EXSLT_CRYPTO_NAMESPACE, |
779 | 4 | exsltCryptoMd4Function); |
780 | 4 | xsltRegisterExtModuleFunction ((const xmlChar *) "md5", |
781 | 4 | EXSLT_CRYPTO_NAMESPACE, |
782 | 4 | exsltCryptoMd5Function); |
783 | 4 | xsltRegisterExtModuleFunction ((const xmlChar *) "sha1", |
784 | 4 | EXSLT_CRYPTO_NAMESPACE, |
785 | 4 | exsltCryptoSha1Function); |
786 | 4 | xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_encrypt", |
787 | 4 | EXSLT_CRYPTO_NAMESPACE, |
788 | 4 | exsltCryptoRc4EncryptFunction); |
789 | 4 | xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_decrypt", |
790 | 4 | EXSLT_CRYPTO_NAMESPACE, |
791 | 4 | exsltCryptoRc4DecryptFunction); |
792 | 4 | } |
793 | | |
794 | | #else |
795 | | /** |
796 | | * exsltCryptoRegister: |
797 | | * |
798 | | * Registers the EXSLT - Crypto module |
799 | | */ |
800 | | void |
801 | | exsltCryptoRegister (void) { |
802 | | } |
803 | | |
804 | | #endif /* defined(HAVE_CRYPTO) */ |
805 | | |
806 | | #endif /* EXSLT_CRYPTO_ENABLED */ |