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