- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / libxslt / libexslt / crypto.c
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  */
53 static void
54 exsltCryptoBin2Hex (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  */
83 static int
84 exsltCryptoHex2Bin (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
126 static void
127 exsltCryptoCryptoApiReportError (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
143 static HCRYPTHASH
144 exsltCryptoCryptoApiCreateHash (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  */
182 static void
183 exsltCryptoCryptoApiHash (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
206 static void
207 exsltCryptoCryptoApiRc4Encrypt (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
257 static void
258 exsltCryptoCryptoApiRc4Decrypt (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
332 static void
333 exsltCryptoGcryptInit (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  */
363 static void
364 exsltCryptoGcryptHash (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
373 static void
374 exsltCryptoGcryptRc4Encrypt (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
412 static void
413 exsltCryptoGcryptRc4Decrypt (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  */
462 static int
463 exsltCryptoPopString (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  */
492 static void
493 exsltCryptoMd4Function (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  */
525 static void
526 exsltCryptoMd5Function (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  */
558 static void
559 exsltCryptoSha1Function (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  */
591 static void
592 exsltCryptoRc4EncryptFunction (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
671 done:
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  */
689 static void
690 exsltCryptoRc4DecryptFunction (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
767 done:
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
784 void
785 exsltCryptoRegister (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  */
809 void
810 exsltCryptoRegister (void) {
811 }
812
813 #endif /* defined(HAVE_CRYPTO) */
814
815 #endif /* EXSLT_CRYPTO_ENABLED */