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
143static HCRYPTHASH
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
206static void
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
257static void
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_TYPES_H
321# include <sys/types.h>
322#endif
323#ifdef HAVE_STDINT_H
324# include <stdint.h>
325#endif
326
327#ifdef HAVE_SYS_SELECT_H
328#include <sys/select.h>		/* needed by gcrypt.h 4 Jul 04 */
329#endif
330#include <gcrypt.h>
331
332static void
333exsltCryptoGcryptInit (void) {
334    static int gcrypt_init;
335    xmlLockLibrary ();
336
337    if (!gcrypt_init) {
338/* The function `gcry_check_version' must be called before any other
339	 function in the library, because it initializes the thread support
340	 subsystem in Libgcrypt. To achieve this in all generality, it is
341	 necessary to synchronize the call to this function with all other calls
342	 to functions in the library, using the synchronization mechanisms
343	 available in your thread library. (from gcrypt.info)
344*/
345	gcry_check_version (GCRYPT_VERSION);
346	gcrypt_init = 1;
347    }
348
349    xmlUnlockLibrary ();
350}
351
352/**
353 * exsltCryptoGcryptHash:
354 * @ctxt: an XPath parser context
355 * @algorithm: hashing algorithm to use
356 * @msg: text to be hashed
357 * @msglen: length of text to be hashed
358 * @dest: buffer to place hash result
359 *
360 * Helper function which hashes a message using MD4, MD5, or SHA1.
361 * using gcrypt
362 */
363static void
364exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED,
365/* changed the enum to int */
366		       int algorithm, const char *msg,
367		       unsigned long msglen,
368		       char dest[HASH_DIGEST_LENGTH]) {
369    exsltCryptoGcryptInit ();
370    gcry_md_hash_buffer (algorithm, dest, msg, msglen);
371}
372
373static void
374exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt,
375			     const unsigned char *key,
376			     const unsigned char *msg, int msglen,
377			     unsigned char *dest, int destlen) {
378    gcry_cipher_hd_t cipher;
379    gcry_error_t rc = 0;
380
381    exsltCryptoGcryptInit ();
382
383    rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
384			   GCRY_CIPHER_MODE_STREAM, 0);
385    if (rc) {
386	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
387			    NULL,
388			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
389			    gcry_strerror (rc));
390    }
391
392    rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
393    if (rc) {
394	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
395			    NULL,
396			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
397			    gcry_strerror (rc));
398    }
399
400    rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen,
401			      (const unsigned char *) msg, msglen);
402    if (rc) {
403	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
404			    NULL,
405			    "exslt:crypto internal error %s (gcry_cipher_encrypt)\n",
406			    gcry_strerror (rc));
407    }
408
409    gcry_cipher_close (cipher);
410}
411
412static void
413exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt,
414			     const unsigned char *key,
415			     const unsigned char *msg, int msglen,
416			     unsigned char *dest, int destlen) {
417    gcry_cipher_hd_t cipher;
418    gcry_error_t rc = 0;
419
420    exsltCryptoGcryptInit ();
421
422    rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
423			   GCRY_CIPHER_MODE_STREAM, 0);
424    if (rc) {
425	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
426			    NULL,
427			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
428			    gcry_strerror (rc));
429    }
430
431    rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
432    if (rc) {
433	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
434			    NULL,
435			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
436			    gcry_strerror (rc));
437    }
438
439    rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen,
440			      (const unsigned char *) msg, msglen);
441    if (rc) {
442	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
443			    NULL,
444			    "exslt:crypto internal error %s (gcry_cipher_decrypt)\n",
445			    gcry_strerror (rc));
446    }
447
448    gcry_cipher_close (cipher);
449}
450
451#endif /* defined(HAVE_GCRYPT) */
452
453#if defined(HAVE_CRYPTO)
454
455/**
456 * exsltCryptoPopString:
457 * @ctxt: an XPath parser context
458 * @nargs: the number of arguments
459 *
460 * Helper function which checks for and returns first string argument and its length
461 */
462static int
463exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs,
464		      xmlChar ** str) {
465
466    int str_len = 0;
467
468    if ((nargs < 1) || (nargs > 2)) {
469	xmlXPathSetArityError (ctxt);
470	return 0;
471    }
472
473    *str = xmlXPathPopString (ctxt);
474    str_len = xmlUTF8Strlen (*str);
475
476    if (str_len == 0) {
477	xmlXPathReturnEmptyString (ctxt);
478	xmlFree (*str);
479	return 0;
480    }
481
482    return str_len;
483}
484
485/**
486 * exsltCryptoMd4Function:
487 * @ctxt: an XPath parser context
488 * @nargs: the number of arguments
489 *
490 * computes the md4 hash of a string and returns as hex
491 */
492static void
493exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) {
494
495    int str_len = 0;
496    xmlChar *str = NULL, *ret = NULL;
497    unsigned char hash[HASH_DIGEST_LENGTH];
498    unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1];
499
500    str_len = exsltCryptoPopString (ctxt, nargs, &str);
501    if (str_len == 0) {
502	xmlXPathReturnEmptyString (ctxt);
503	xmlFree (str);
504	return;
505    }
506
507    PLATFORM_HASH (ctxt, PLATFORM_MD4, (const char *) str, str_len,
508		   (char *) hash);
509    exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
510
511    ret = xmlStrdup ((xmlChar *) hex);
512    xmlXPathReturnString (ctxt, ret);
513
514    if (str != NULL)
515	xmlFree (str);
516}
517
518/**
519 * exsltCryptoMd5Function:
520 * @ctxt: an XPath parser context
521 * @nargs: the number of arguments
522 *
523 * computes the md5 hash of a string and returns as hex
524 */
525static void
526exsltCryptoMd5Function (xmlXPathParserContextPtr ctxt, int nargs) {
527
528    int str_len = 0;
529    xmlChar *str = NULL, *ret = NULL;
530    unsigned char hash[HASH_DIGEST_LENGTH];
531    unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1];
532
533    str_len = exsltCryptoPopString (ctxt, nargs, &str);
534    if (str_len == 0) {
535	xmlXPathReturnEmptyString (ctxt);
536	xmlFree (str);
537	return;
538    }
539
540    PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len,
541		   (char *) hash);
542    exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
543
544    ret = xmlStrdup ((xmlChar *) hex);
545    xmlXPathReturnString (ctxt, ret);
546
547    if (str != NULL)
548	xmlFree (str);
549}
550
551/**
552 * exsltCryptoSha1Function:
553 * @ctxt: an XPath parser context
554 * @nargs: the number of arguments
555 *
556 * computes the sha1 hash of a string and returns as hex
557 */
558static void
559exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) {
560
561    int str_len = 0;
562    xmlChar *str = NULL, *ret = NULL;
563    unsigned char hash[HASH_DIGEST_LENGTH];
564    unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1];
565
566    str_len = exsltCryptoPopString (ctxt, nargs, &str);
567    if (str_len == 0) {
568	xmlXPathReturnEmptyString (ctxt);
569	xmlFree (str);
570	return;
571    }
572
573    PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len,
574		   (char *) hash);
575    exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
576
577    ret = xmlStrdup ((xmlChar *) hex);
578    xmlXPathReturnString (ctxt, ret);
579
580    if (str != NULL)
581	xmlFree (str);
582}
583
584/**
585 * exsltCryptoRc4EncryptFunction:
586 * @ctxt: an XPath parser context
587 * @nargs: the number of arguments
588 *
589 * computes the sha1 hash of a string and returns as hex
590 */
591static void
592exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
593
594    int key_len = 0, key_size = 0;
595    int str_len = 0, bin_len = 0, hex_len = 0;
596    xmlChar *key = NULL, *str = NULL, *padkey = NULL;
597    xmlChar *bin = NULL, *hex = NULL;
598    xsltTransformContextPtr tctxt = NULL;
599
600    if (nargs != 2) {
601	xmlXPathSetArityError (ctxt);
602	return;
603    }
604    tctxt = xsltXPathGetTransformContext(ctxt);
605
606    str = xmlXPathPopString (ctxt);
607    str_len = xmlUTF8Strlen (str);
608
609    if (str_len == 0) {
610	xmlXPathReturnEmptyString (ctxt);
611	xmlFree (str);
612	return;
613    }
614
615    key = xmlXPathPopString (ctxt);
616    key_len = xmlUTF8Strlen (key);
617
618    if (key_len == 0) {
619	xmlXPathReturnEmptyString (ctxt);
620	xmlFree (key);
621	xmlFree (str);
622	return;
623    }
624
625    padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
626    if (padkey == NULL) {
627	xsltTransformError(tctxt, NULL, tctxt->inst,
628	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
629	tctxt->state = XSLT_STATE_STOPPED;
630	xmlXPathReturnEmptyString (ctxt);
631	goto done;
632    }
633    memset(padkey, 0, RC4_KEY_LENGTH + 1);
634
635    key_size = xmlUTF8Strsize (key, key_len);
636    if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) {
637	xsltTransformError(tctxt, NULL, tctxt->inst,
638	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
639	tctxt->state = XSLT_STATE_STOPPED;
640	xmlXPathReturnEmptyString (ctxt);
641	goto done;
642    }
643    memcpy (padkey, key, key_size);
644
645/* encrypt it */
646    bin_len = str_len;
647    bin = xmlStrdup (str);
648    if (bin == NULL) {
649	xsltTransformError(tctxt, NULL, tctxt->inst,
650	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
651	tctxt->state = XSLT_STATE_STOPPED;
652	xmlXPathReturnEmptyString (ctxt);
653	goto done;
654    }
655    PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len);
656
657/* encode it */
658    hex_len = str_len * 2 + 1;
659    hex = xmlMallocAtomic (hex_len);
660    if (hex == NULL) {
661	xsltTransformError(tctxt, NULL, tctxt->inst,
662	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
663	tctxt->state = XSLT_STATE_STOPPED;
664	xmlXPathReturnEmptyString (ctxt);
665	goto done;
666    }
667
668    exsltCryptoBin2Hex (bin, str_len, hex, hex_len);
669    xmlXPathReturnString (ctxt, hex);
670
671done:
672    if (key != NULL)
673	xmlFree (key);
674    if (str != NULL)
675	xmlFree (str);
676    if (padkey != NULL)
677	xmlFree (padkey);
678    if (bin != NULL)
679	xmlFree (bin);
680}
681
682/**
683 * exsltCryptoRc4DecryptFunction:
684 * @ctxt: an XPath parser context
685 * @nargs: the number of arguments
686 *
687 * computes the sha1 hash of a string and returns as hex
688 */
689static void
690exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
691
692    int key_len = 0, key_size = 0;
693    int str_len = 0, bin_len = 0, ret_len = 0;
694    xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin =
695	NULL, *ret = NULL;
696    xsltTransformContextPtr tctxt = NULL;
697
698    if (nargs != 2) {
699	xmlXPathSetArityError (ctxt);
700	return;
701    }
702    tctxt = xsltXPathGetTransformContext(ctxt);
703
704    str = xmlXPathPopString (ctxt);
705    str_len = xmlUTF8Strlen (str);
706
707    if (str_len == 0) {
708	xmlXPathReturnEmptyString (ctxt);
709	xmlFree (str);
710	return;
711    }
712
713    key = xmlXPathPopString (ctxt);
714    key_len = xmlUTF8Strlen (key);
715
716    if (key_len == 0) {
717	xmlXPathReturnEmptyString (ctxt);
718	xmlFree (key);
719	xmlFree (str);
720	return;
721    }
722
723    padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
724    if (padkey == NULL) {
725	xsltTransformError(tctxt, NULL, tctxt->inst,
726	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
727	tctxt->state = XSLT_STATE_STOPPED;
728	xmlXPathReturnEmptyString (ctxt);
729	goto done;
730    }
731    memset(padkey, 0, RC4_KEY_LENGTH + 1);
732    key_size = xmlUTF8Strsize (key, key_len);
733    if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) {
734	xsltTransformError(tctxt, NULL, tctxt->inst,
735	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
736	tctxt->state = XSLT_STATE_STOPPED;
737	xmlXPathReturnEmptyString (ctxt);
738	goto done;
739    }
740    memcpy (padkey, key, key_size);
741
742/* decode hex to binary */
743    bin_len = str_len;
744    bin = xmlMallocAtomic (bin_len);
745    if (bin == NULL) {
746	xsltTransformError(tctxt, NULL, tctxt->inst,
747	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
748	tctxt->state = XSLT_STATE_STOPPED;
749	xmlXPathReturnEmptyString (ctxt);
750	goto done;
751    }
752    ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len);
753
754/* decrypt the binary blob */
755    ret = xmlMallocAtomic (ret_len);
756    if (ret == NULL) {
757	xsltTransformError(tctxt, NULL, tctxt->inst,
758	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
759	tctxt->state = XSLT_STATE_STOPPED;
760	xmlXPathReturnEmptyString (ctxt);
761	goto done;
762    }
763    PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len);
764
765    xmlXPathReturnString (ctxt, ret);
766
767done:
768    if (key != NULL)
769	xmlFree (key);
770    if (str != NULL)
771	xmlFree (str);
772    if (padkey != NULL)
773	xmlFree (padkey);
774    if (bin != NULL)
775	xmlFree (bin);
776}
777
778/**
779 * exsltCryptoRegister:
780 *
781 * Registers the EXSLT - Crypto module
782 */
783
784void
785exsltCryptoRegister (void) {
786    xsltRegisterExtModuleFunction ((const xmlChar *) "md4",
787				   EXSLT_CRYPTO_NAMESPACE,
788				   exsltCryptoMd4Function);
789    xsltRegisterExtModuleFunction ((const xmlChar *) "md5",
790				   EXSLT_CRYPTO_NAMESPACE,
791				   exsltCryptoMd5Function);
792    xsltRegisterExtModuleFunction ((const xmlChar *) "sha1",
793				   EXSLT_CRYPTO_NAMESPACE,
794				   exsltCryptoSha1Function);
795    xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_encrypt",
796				   EXSLT_CRYPTO_NAMESPACE,
797				   exsltCryptoRc4EncryptFunction);
798    xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_decrypt",
799				   EXSLT_CRYPTO_NAMESPACE,
800				   exsltCryptoRc4DecryptFunction);
801}
802
803#else
804/**
805 * exsltCryptoRegister:
806 *
807 * Registers the EXSLT - Crypto module
808 */
809void
810exsltCryptoRegister (void) {
811}
812
813#endif /* defined(HAVE_CRYPTO) */
814
815#endif /* EXSLT_CRYPTO_ENABLED */
816