xmlsecurityengine/xmlsec/src/xmlsec_xmlenc.c
changeset 0 e35f40988205
child 24 74f0b3eb154c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlsec/src/xmlsec_xmlenc.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1283 @@
+/** 
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * "XML Encryption" implementation
+ *  http://www.w3.org/TR/xmlenc-core
+ * 
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ * 
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
+ */
+#include "xmlsec_config.h"
+#ifndef XMLSEC_NO_XMLENC
+#include "xmlsec_globals.h"
+ 
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libxml2_tree.h>
+#include <libxml2_parser.h>
+#include <libxml2_globals.h>
+
+#include "xmlsec_xmlsec.h"
+#include "xmlsec_buffer.h"
+#include "xmlsec_xmltree.h"
+#include "xmlsec_keys.h"
+#include "xmlsec_keysmngr.h"
+#include "xmlsec_transforms.h"
+#include "xmlsec_keyinfo.h"
+#include "xmlsec_xmlenc.h"
+#include "xmlsec_errors.h"
+
+static int 	xmlSecEncCtxEncDataNodeRead		(xmlSecEncCtxPtr encCtx, 
+							 xmlNodePtr node);
+static int 	xmlSecEncCtxEncDataNodeWrite		(xmlSecEncCtxPtr encCtx);
+static int 	xmlSecEncCtxCipherDataNodeRead		(xmlSecEncCtxPtr encCtx, 
+							 xmlNodePtr node);
+static int 	xmlSecEncCtxCipherReferenceNodeRead	(xmlSecEncCtxPtr encCtx, 
+							 xmlNodePtr node);
+
+/* The ID attribute in XMLEnc is 'Id' */
+static const xmlChar*		xmlSecEncIds[] = { BAD_CAST "Id", NULL };
+
+
+/**
+ * xmlSecEncCtxCreate:
+ * @keysMngr: 		the pointer to keys manager.
+ *
+ * Creates <enc:EncryptedData/> element processing context.
+ * The caller is responsible for destroying returend object by calling 
+ * #xmlSecEncCtxDestroy function.
+ *
+ * Returns pointer to newly allocated context object or NULL if an error
+ * occurs.
+ */
+EXPORT_C
+xmlSecEncCtxPtr	
+xmlSecEncCtxCreate(xmlSecKeysMngrPtr keysMngr) {
+    xmlSecEncCtxPtr encCtx;
+    int ret;
+    
+    encCtx = (xmlSecEncCtxPtr) xmlMalloc(sizeof(xmlSecEncCtx));
+    if(encCtx == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_MALLOC_FAILED,
+		    "sizeof(xmlSecEncCtx)=%d", 
+		    sizeof(xmlSecEncCtx));
+	return(NULL);
+    }
+    
+    ret = xmlSecEncCtxInitialize(encCtx, keysMngr);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecEncCtxDestroy(encCtx);
+	return(NULL);   
+    }
+    return(encCtx);    
+}
+
+/**
+ * xmlSecEncCtxDestroy:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ *
+ * Destroy context object created with #xmlSecEncCtxCreate function.
+ */
+EXPORT_C
+void  
+xmlSecEncCtxDestroy(xmlSecEncCtxPtr encCtx) {
+    xmlSecAssert(encCtx != NULL);
+    
+    xmlSecEncCtxFinalize(encCtx);
+    xmlFree(encCtx);
+}
+
+/**
+ * xmlSecEncCtxInitialize:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @keysMngr: 		the pointer to keys manager.
+ *
+ * Initializes <enc:EncryptedData/> element processing context.
+ * The caller is responsible for cleaing up returend object by calling 
+ * #xmlSecEncCtxFinalize function.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxInitialize(xmlSecEncCtxPtr encCtx, xmlSecKeysMngrPtr keysMngr) {
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    
+    memset(encCtx, 0, sizeof(xmlSecEncCtx));
+
+    /* initialize key info */
+    ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoReadCtx), keysMngr);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyInfoCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);   
+    }
+    encCtx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead;
+    
+    ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoWriteCtx), keysMngr);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyInfoCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);   
+    }
+    encCtx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite;
+    /* it's not wise to write private key :) */
+    encCtx->keyInfoWriteCtx.keyReq.keyType = xmlSecKeyDataTypePublic;
+
+    /* initializes transforms encCtx */
+    ret = xmlSecTransformCtxInitialize(&(encCtx->transformCtx));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);   
+    }
+
+    return(0);
+}
+
+/**
+ * xmlSecEncCtxFinalize:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ *
+ * Cleans up @encCtx object.
+ */
+EXPORT_C
+void 
+xmlSecEncCtxFinalize(xmlSecEncCtxPtr encCtx) {
+    xmlSecAssert(encCtx != NULL);
+
+    xmlSecEncCtxReset(encCtx);
+    
+    xmlSecTransformCtxFinalize(&(encCtx->transformCtx));
+    xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoReadCtx));
+    xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoWriteCtx));
+
+    memset(encCtx, 0, sizeof(xmlSecEncCtx));
+}
+
+/**
+ * xmlSecEncCtxReset:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ *
+ * Resets @encCtx object, user settings are not touched.
+ */
+EXPORT_C
+void 
+xmlSecEncCtxReset(xmlSecEncCtxPtr encCtx) {
+    xmlSecAssert(encCtx != NULL);
+    
+    xmlSecTransformCtxReset(&(encCtx->transformCtx));
+    xmlSecKeyInfoCtxReset(&(encCtx->keyInfoReadCtx));
+    xmlSecKeyInfoCtxReset(&(encCtx->keyInfoWriteCtx));
+
+    encCtx->operation 		= xmlSecTransformOperationNone;
+    encCtx->result		= NULL;
+    encCtx->resultBase64Encoded = 0;
+    encCtx->resultReplaced	= 0;
+    encCtx->encMethod		= NULL;
+    if(encCtx->encKey != NULL) {
+	xmlSecKeyDestroy(encCtx->encKey);
+	encCtx->encKey = NULL;
+    }
+    
+    if(encCtx->id != NULL) {
+	xmlFree(encCtx->id);
+	encCtx->id = NULL;
+    }	
+    if(encCtx->type != NULL) {
+	xmlFree(encCtx->type);
+	encCtx->type = NULL;
+    }
+    if(encCtx->mimeType != NULL) {
+	xmlFree(encCtx->mimeType);
+	encCtx->mimeType = NULL;
+    }
+    if(encCtx->encoding != NULL) {
+	xmlFree(encCtx->encoding);
+	encCtx->encoding = NULL;
+    }	
+    if(encCtx->recipient != NULL) {
+	xmlFree(encCtx->recipient);
+	encCtx->recipient = NULL;
+    }
+    if(encCtx->carriedKeyName != NULL) {
+	xmlFree(encCtx->carriedKeyName);
+	encCtx->carriedKeyName = NULL;
+    }
+    
+    encCtx->encDataNode = encCtx->encMethodNode = 
+	encCtx->keyInfoNode = encCtx->cipherValueNode = NULL;
+}
+
+/**
+ * xmlSecEncCtxCopyUserPref:
+ * @dst:		the pointer to destination context.
+ * @src:		the pointer to source context.
+ * 
+ * Copies user preference from @src context to @dst.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxCopyUserPref(xmlSecEncCtxPtr dst, xmlSecEncCtxPtr src) {
+    int ret;
+    
+    xmlSecAssert2(dst != NULL, -1);
+    xmlSecAssert2(src != NULL, -1);
+
+    dst->userData 	= src->userData;
+    dst->flags		= src->flags;
+    dst->flags2		= src->flags2;
+    dst->defEncMethodId = src->defEncMethodId;
+    dst->mode 		= src->mode;
+    
+    ret = xmlSecTransformCtxCopyUserPref(&(dst->transformCtx), &(src->transformCtx));
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxCopyUserPref",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoReadCtx), &(src->keyInfoReadCtx));
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyInfoCtxCopyUserPref",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoWriteCtx), &(src->keyInfoWriteCtx));
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyInfoCtxCopyUserPref",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    return(0);
+} 
+
+/**
+ * xmlSecEncCtxBinaryEncrypt:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @tmpl:		the pointer to <enc:EncryptedData/> template node.
+ * @data:		the pointer for binary buffer.
+ * @dataSize:		the @data buffer size.
+ *
+ * Encrypts @data according to template @tmpl.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxBinaryEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, 
+			  const xmlSecByte* data, xmlSecSize dataSize) {
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(encCtx->result == NULL, -1);
+    xmlSecAssert2(tmpl != NULL, -1);
+    xmlSecAssert2(data != NULL, -1);
+
+    /* initialize context and add ID atributes to the list of known ids */    
+    encCtx->operation = xmlSecTransformOperationEncrypt;
+    xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds);
+
+    /* read the template and set encryption method, key, etc. */
+    ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxBinaryExecute",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "dataSize=%d",
+		    dataSize);
+	return(-1);
+    }
+
+    encCtx->result = encCtx->transformCtx.result;
+    xmlSecAssert2(encCtx->result != NULL, -1);
+    
+    ret = xmlSecEncCtxEncDataNodeWrite(encCtx);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeWrite",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);    
+}
+
+/**
+ * xmlSecEncCtxXmlEncrypt:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @tmpl:		the pointer to <enc:EncryptedData/> template node.
+ * @node:		the pointer to node for encryption.
+ *
+ * Encrypts @node according to template @tmpl. If requested, @node is replaced
+ * with result <enc:EncryptedData/> node.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxXmlEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, xmlNodePtr node) {
+    xmlOutputBufferPtr output;
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(encCtx->result == NULL, -1);
+    xmlSecAssert2(tmpl != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(node->doc != NULL, -1);
+
+    /* initialize context and add ID atributes to the list of known ids */    
+    encCtx->operation = xmlSecTransformOperationEncrypt;
+    xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds);
+
+    /* read the template and set encryption method, key, etc. */
+    ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecTransformCtxPrepare(&(encCtx->transformCtx), xmlSecTransformDataTypeBin);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxPrepare",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "type=bin");
+	return(-1);
+    }
+    
+    xmlSecAssert2(encCtx->transformCtx.first != NULL, -1);
+    output = xmlSecTransformCreateOutputBuffer(encCtx->transformCtx.first, 
+						&(encCtx->transformCtx));
+    if(output == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->transformCtx.first)),
+		    "xmlSecTransformCreateOutputBuffer",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    /* push data thru */
+    if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) {
+	/* get the content of the node */
+	xmlNodeDumpOutput(output, node->doc, node, 0, 0, NULL);
+    } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) {
+	xmlNodePtr cur;
+
+	/* get the content of the nodes childs */
+	for(cur = node->children; cur != NULL; cur = cur->next) {
+	    xmlNodeDumpOutput(output, node->doc, cur, 0, 0, NULL);
+	}
+    } else {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_INVALID_TYPE,
+		    "type=%s", 
+		    xmlSecErrorsSafeString(encCtx->type));
+	xmlOutputBufferClose(output);
+	return(-1);	    	
+    }
+    
+    /* close the buffer and flush everything */
+    ret = xmlOutputBufferClose(output);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlOutputBufferClose",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    encCtx->result = encCtx->transformCtx.result;
+    xmlSecAssert2(encCtx->result != NULL, -1);
+    
+    ret = xmlSecEncCtxEncDataNodeWrite(encCtx);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeWrite",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    /* now we need to update our original document */
+    if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) {
+	ret = xmlSecReplaceNode(node, tmpl);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecReplaceNode",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
+	    return(-1);
+	}
+	encCtx->resultReplaced = 1;			       
+    } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) {
+	ret = xmlSecReplaceContent(node, tmpl);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecReplaceContent",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
+	    return(-1);
+	}
+	encCtx->resultReplaced = 1;			       
+    } else {
+	/* we should've catached this error before */
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_INVALID_TYPE,
+		    "type=%s", 
+		    xmlSecErrorsSafeString(encCtx->type));
+	return(-1);	    	
+    }
+    return(0);    
+}
+
+/**
+ * xmlSecEncCtxUriEncrypt:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @tmpl:		the pointer to <enc:EncryptedData/> template node.
+ * @uri:		the URI.
+ *
+ * Encrypts data from @uri according to template @tmpl.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxUriEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, const xmlChar *uri) {
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(encCtx->result == NULL, -1);
+    xmlSecAssert2(tmpl != NULL, -1);
+    xmlSecAssert2(uri != NULL, -1);
+
+    /* initialize context and add ID atributes to the list of known ids */    
+    encCtx->operation = xmlSecTransformOperationEncrypt;
+    xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds);
+
+    /* we need to add input uri transform first */
+    ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, tmpl);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxSetUri",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "uri=%s",
+		    xmlSecErrorsSafeString(uri));
+	return(-1);
+    }
+
+    /* read the template and set encryption method, key, etc. */
+    ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    /* encrypt the data */
+    ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), tmpl->doc);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxExecute",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+        
+    encCtx->result = encCtx->transformCtx.result;
+    xmlSecAssert2(encCtx->result != NULL, -1);
+    
+    ret = xmlSecEncCtxEncDataNodeWrite(encCtx);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeWrite",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+    
+    return(0);
+}
+
+/**
+ * xmlSecEncCtxDecrypt:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @node:		the pointer to <enc:EncryptedData/> node.
+ *
+ * Decrypts @node and if necessary replaces @node with decrypted data.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecEncCtxDecrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr node) {
+    xmlSecBufferPtr buffer;
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    
+    /* decrypt */
+    buffer = xmlSecEncCtxDecryptToBuffer(encCtx, node);
+    if(buffer == NULL) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxDecryptToBuffer",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    /* replace original node if requested */
+    if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) {
+	ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer),  xmlSecBufferGetSize(buffer));
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecReplaceNodeBuffer",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
+	    return(-1);	    	
+	}
+	encCtx->resultReplaced = 1;			       
+    } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) {
+	/* replace the node with the buffer */
+	ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer));
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecReplaceNodeBuffer",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
+	    return(-1);	    	
+	}	
+	encCtx->resultReplaced = 1;			       
+    }
+    return(0);
+}
+
+/**
+ * xmlSecEncCtxDecryptToBuffer:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @node:		the pointer to <enc:EncryptedData/> node.
+ * 
+ * Decrypts @node data to the @encCtx buffer.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+xmlSecBufferPtr
+xmlSecEncCtxDecryptToBuffer(xmlSecEncCtxPtr encCtx, xmlNodePtr node) {
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, NULL);
+    xmlSecAssert2(encCtx->result == NULL, NULL);
+    xmlSecAssert2(node != NULL, NULL);
+
+    /* initialize context and add ID atributes to the list of known ids */    
+    encCtx->operation = xmlSecTransformOperationDecrypt;
+    xmlSecAddIDs(node->doc, node, xmlSecEncIds);
+
+    ret = xmlSecEncCtxEncDataNodeRead(encCtx, node);
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxEncDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+
+    /* decrypt the data */
+    if(encCtx->cipherValueNode != NULL) {
+        xmlChar* data = NULL;
+        xmlSecSize dataSize = 0;
+
+	data = xmlNodeGetContent(encCtx->cipherValueNode);
+	if(data == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->cipherValueNode)),
+			XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(NULL);
+	}	
+	dataSize = xmlStrlen(data);
+
+        ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize);
+	if(ret < 0) {
+    	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecTransformCtxBinaryExecute",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    if(data != NULL) {
+		xmlFree(data);
+	    }
+	    return(NULL);
+	}
+	if(data != NULL) {
+	    xmlFree(data);
+	}
+    } else {
+        ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), node->doc);
+	if(ret < 0) {
+    	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecTransformCtxBinaryExecute",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(NULL);
+	}
+    }
+    
+    encCtx->result = encCtx->transformCtx.result;
+    xmlSecAssert2(encCtx->result != NULL, NULL);
+    
+    return(encCtx->result);
+}
+
+static int 
+xmlSecEncCtxEncDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) {
+    xmlNodePtr cur;
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2((encCtx->operation == xmlSecTransformOperationEncrypt) || (encCtx->operation == xmlSecTransformOperationDecrypt), -1);
+    xmlSecAssert2(node != NULL, -1);
+
+    switch(encCtx->mode) {
+	case xmlEncCtxModeEncryptedData:
+	    if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedData, xmlSecEncNs)) {
+    		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+			    XMLSEC_ERRORS_R_INVALID_NODE,
+			    "expected=%s",
+			    xmlSecErrorsSafeString(xmlSecNodeEncryptedData));
+		return(-1);	    
+	    }
+	    break;
+	case xmlEncCtxModeEncryptedKey:
+	    if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedKey, xmlSecEncNs)) {
+    		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+			    XMLSEC_ERRORS_R_INVALID_NODE,
+			    "expected=%s",
+			    xmlSecErrorsSafeString(xmlSecNodeEncryptedKey));
+		return(-1);	    
+	    }
+	    break;
+    }
+    
+    /* first read node data */
+    xmlSecAssert2(encCtx->id == NULL, -1);
+    xmlSecAssert2(encCtx->type == NULL, -1);
+    xmlSecAssert2(encCtx->mimeType == NULL, -1);
+    xmlSecAssert2(encCtx->encoding == NULL, -1);
+    xmlSecAssert2(encCtx->recipient == NULL, -1);
+    xmlSecAssert2(encCtx->carriedKeyName == NULL, -1);
+    
+    encCtx->id = xmlGetProp(node, xmlSecAttrId);
+    encCtx->type = xmlGetProp(node, xmlSecAttrType);
+    encCtx->mimeType = xmlGetProp(node, xmlSecAttrMimeType);
+    encCtx->encoding = xmlGetProp(node, xmlSecAttrEncoding);    
+    if(encCtx->mode == xmlEncCtxModeEncryptedKey) {
+	encCtx->recipient = xmlGetProp(node, xmlSecAttrRecipient);    
+    }
+    cur = xmlSecGetNextElementNode(node->children);
+    
+    /* first node is optional EncryptionMethod, we'll read it later */
+    xmlSecAssert2(encCtx->encMethodNode == NULL, -1);
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionMethod, xmlSecEncNs))) {
+	encCtx->encMethodNode = cur;
+        cur = xmlSecGetNextElementNode(cur->next);
+    }
+
+    /* next node is optional KeyInfo, we'll process it later */
+    xmlSecAssert2(encCtx->keyInfoNode == NULL, -1);
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) {
+	encCtx->keyInfoNode = cur;
+	cur = xmlSecGetNextElementNode(cur->next);
+    }    
+
+    /* next is required CipherData node */
+    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeCipherData, xmlSecEncNs))) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_INVALID_NODE,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeCipherData));
+	return(-1);
+    }
+    
+    ret = xmlSecEncCtxCipherDataNodeRead(encCtx, cur);
+    if(ret < 0) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxCipherDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    cur = xmlSecGetNextElementNode(cur->next);
+
+    /* next is optional EncryptionProperties node (we simply ignore it) */
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionProperties, xmlSecEncNs))) {
+	cur = xmlSecGetNextElementNode(cur->next);
+    }
+
+    /* there are more possible nodes for the <EncryptedKey> node */
+    if(encCtx->mode == xmlEncCtxModeEncryptedKey) {
+	/* next is optional ReferenceList node (we simply ignore it) */
+        if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReferenceList, xmlSecEncNs))) {
+	    cur = xmlSecGetNextElementNode(cur->next);
+	}
+
+        /* next is optional CarriedKeyName node (we simply ignore it) */
+	if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCarriedKeyName, xmlSecEncNs))) {
+	    encCtx->carriedKeyName = xmlNodeGetContent(cur);
+	    if(encCtx->carriedKeyName == NULL) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+			    XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+			    "node=%s",
+			    xmlSecErrorsSafeString(xmlSecNodeCipherData));
+		return(-1);
+	    }
+	    cur = xmlSecGetNextElementNode(cur->next);
+	}
+    }
+
+    /* if there is something left than it's an error */
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    /* now read the encryption method node */
+    xmlSecAssert2(encCtx->encMethod == NULL, -1);
+    if(encCtx->encMethodNode != NULL) {
+	encCtx->encMethod = xmlSecTransformCtxNodeRead(&(encCtx->transformCtx), encCtx->encMethodNode,
+						xmlSecTransformUsageEncryptionMethod);
+	if(encCtx->encMethod == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		    	NULL,
+			"xmlSecTransformCtxNodeRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode)));
+	    return(-1);	    
+	}	
+    } else if(encCtx->defEncMethodId != xmlSecTransformIdUnknown) {
+	encCtx->encMethod = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), 
+							      encCtx->defEncMethodId);
+	if(encCtx->encMethod == NULL) {
+    	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecTransformCtxAppend",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+    } else {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_INVALID_DATA,
+		    "encryption method not specified");
+	return(-1);
+    }
+    encCtx->encMethod->operation = encCtx->operation;
+    
+    /* we have encryption method, find key */
+    ret = xmlSecTransformSetKeyReq(encCtx->encMethod, &(encCtx->keyInfoReadCtx.keyReq));
+    if(ret < 0) {
+    	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformSetKeyReq",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "transform=%s",
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod)));
+	return(-1);
+    }	
+
+    if((encCtx->encKey == NULL) && (encCtx->keyInfoReadCtx.keysMngr != NULL) 
+			&& (encCtx->keyInfoReadCtx.keysMngr->getKey != NULL)) {
+	encCtx->encKey = (encCtx->keyInfoReadCtx.keysMngr->getKey)(encCtx->keyInfoNode, 
+							     &(encCtx->keyInfoReadCtx));
+    }
+    
+    /* check that we have exactly what we want */
+    if((encCtx->encKey == NULL) || 
+       (!xmlSecKeyMatch(encCtx->encKey, NULL, &(encCtx->keyInfoReadCtx.keyReq)))) {
+
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_KEY_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    /* set the key to the transform */
+    ret = xmlSecTransformSetKey(encCtx->encMethod, encCtx->encKey);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformSetKey",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "transform=%s",
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod)));
+	return(-1);
+    }
+
+    /* if we need to write result to xml node then we need base64 encode it */
+    if((encCtx->operation == xmlSecTransformOperationEncrypt) && (encCtx->cipherValueNode != NULL)) {	
+	xmlSecTransformPtr base64Encode;
+	
+	/* we need to add base64 encode transform */
+	base64Encode = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), xmlSecTransformBase64Id);
+    	if(base64Encode == NULL) {
+    	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecTransformCtxCreateAndAppend",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+	base64Encode->operation 	= xmlSecTransformOperationEncode;
+	encCtx->resultBase64Encoded 	= 1;
+    }
+    
+    return(0);
+}
+
+static int 
+xmlSecEncCtxEncDataNodeWrite(xmlSecEncCtxPtr encCtx) {
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(encCtx->result != NULL, -1);
+    xmlSecAssert2(encCtx->encKey != NULL, -1);
+    
+    /* write encrypted data to xml (if requested) */
+    if(encCtx->cipherValueNode != NULL) {	
+	xmlSecAssert2(xmlSecBufferGetData(encCtx->result) != NULL, -1);
+
+	xmlNodeSetContentLen(encCtx->cipherValueNode,
+			    xmlSecBufferGetData(encCtx->result),
+			    xmlSecBufferGetSize(encCtx->result));
+	if (OOM_FLAG)
+	    {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlNodeSetContentLen",
+			XMLSEC_ERRORS_R_MALLOC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	    }			    
+	encCtx->resultReplaced = 1;
+    }
+
+    /* update <enc:KeyInfo/> node */
+    if(encCtx->keyInfoNode != NULL) {
+	ret = xmlSecKeyInfoNodeWrite(encCtx->keyInfoNode, encCtx->encKey, &(encCtx->keyInfoWriteCtx));
+	if(ret < 0) {
+    	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecKeyInfoNodeWrite",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}	
+    }
+    
+    return(0);
+}
+
+static int 
+xmlSecEncCtxCipherDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) {
+    xmlNodePtr cur;
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    
+    cur = xmlSecGetNextElementNode(node->children);
+    
+    /* we either have CipherValue or CipherReference node  */
+    xmlSecAssert2(encCtx->cipherValueNode == NULL, -1);
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherValue, xmlSecEncNs))) {
+        /* don't need data from CipherData node when we are encrypting */
+	if(encCtx->operation == xmlSecTransformOperationDecrypt) {
+	    xmlSecTransformPtr base64Decode;
+	
+	    /* we need to add base64 decode transform */
+	    base64Decode = xmlSecTransformCtxCreateAndPrepend(&(encCtx->transformCtx), xmlSecTransformBase64Id);
+    	    if(base64Decode == NULL) {
+    		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    "xmlSecTransformCtxCreateAndPrepend",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+	        return(-1);
+	    }
+	}
+	encCtx->cipherValueNode = cur;
+        cur = xmlSecGetNextElementNode(cur->next);
+    } else if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherReference, xmlSecEncNs))) {
+        /* don't need data from CipherReference node when we are encrypting */
+	if(encCtx->operation == xmlSecTransformOperationDecrypt) {
+    	    ret = xmlSecEncCtxCipherReferenceNodeRead(encCtx, cur);
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+		    	    NULL,
+			    "xmlSecEncCtxCipherReferenceNodeRead",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    "node=%s",
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+		return(-1);	    
+	    }
+	}	
+        cur = xmlSecGetNextElementNode(cur->next);
+    }
+    
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+static int 
+xmlSecEncCtxCipherReferenceNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) {
+    xmlNodePtr cur;
+    xmlChar* uri;
+    int ret;
+    
+    xmlSecAssert2(encCtx != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    
+    /* first read the optional uri attr and check that we can process it */
+    uri = xmlGetProp(node, xmlSecAttrURI);
+    ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, node);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxSetUri",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "uri=%s",
+		    xmlSecErrorsSafeString(uri));
+	xmlFree(uri);
+	return(-1);	    
+    }		
+    xmlFree(uri);
+
+    cur = xmlSecGetNextElementNode(node->children);
+    
+    /* the only one node is optional Transforms node */
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecEncNs))) {
+	ret = xmlSecTransformCtxNodesListRead(&(encCtx->transformCtx), cur,
+				    xmlSecTransformUsageDSigTransform);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		    	NULL,
+			"xmlSecTransformCtxNodesListRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode)));
+	    return(-1);	    
+	}	
+        cur = xmlSecGetNextElementNode(cur->next);
+    }
+    
+    /* if there is something left than it's an error */
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+/**
+ * xmlSecEncCtxDebugDump:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @output:		the pointer to output FILE.
+ *
+ * Prints the debug information about @encCtx to @output.
+ */
+EXPORT_C
+void 
+xmlSecEncCtxDebugDump(xmlSecEncCtxPtr encCtx, FILE* output) {
+    xmlSecAssert(encCtx != NULL);
+    xmlSecAssert(output != NULL);
+
+    switch(encCtx->mode) {
+	case xmlEncCtxModeEncryptedData:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "= DATA ENCRYPTION CONTEXT\n");
+	    } else {
+		fprintf(output, "= DATA DECRYPTION CONTEXT\n");
+	    }
+	    break;
+	case xmlEncCtxModeEncryptedKey:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "= KEY ENCRYPTION CONTEXT\n");
+	    } else {
+		fprintf(output, "= KEY DECRYPTION CONTEXT\n");
+	    }
+	    break;
+    }
+    fprintf(output, "== Status: %s\n",
+	    (encCtx->resultReplaced) ? "replaced" : "not-replaced" );
+
+    fprintf(output, "== flags: 0x%08x\n", encCtx->flags);
+    fprintf(output, "== flags2: 0x%08x\n", encCtx->flags2);
+
+    if(encCtx->id != NULL) {
+	fprintf(output, "== Id: \"%s\"\n", encCtx->id);
+    }
+    if(encCtx->type != NULL) {
+	fprintf(output, "== Type: \"%s\"\n", encCtx->type);
+    }
+    if(encCtx->mimeType != NULL) {
+	fprintf(output, "== MimeType: \"%s\"\n", encCtx->mimeType);
+    }
+    if(encCtx->encoding != NULL) {
+	fprintf(output, "== Encoding: \"%s\"\n", encCtx->encoding);
+    }
+    if(encCtx->recipient != NULL) {
+	fprintf(output, "== Recipient: \"%s\"\n", encCtx->recipient);
+    }
+    if(encCtx->carriedKeyName != NULL) {
+	fprintf(output, "== CarriedKeyName: \"%s\"\n", encCtx->carriedKeyName);
+    }
+    
+    fprintf(output, "== Key Info Read Ctx:\n");
+    xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoReadCtx), output);
+
+    fprintf(output, "== Key Info Write Ctx:\n");
+    xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoWriteCtx), output);
+
+    fprintf(output, "== Encryption Transform Ctx:\n");
+    xmlSecTransformCtxDebugDump(&(encCtx->transformCtx), output);
+
+    if(encCtx->encMethod != NULL) {
+        fprintf(output, "== Encryption Method:\n");
+	xmlSecTransformDebugDump(encCtx->encMethod, output);
+    }
+
+    if(encCtx->encKey != NULL) {
+        fprintf(output, "== Encryption Key:\n");
+	xmlSecKeyDebugDump(encCtx->encKey, output);
+    }
+    
+    if((encCtx->result != NULL) && 
+       (xmlSecBufferGetData(encCtx->result) != NULL) && 
+       (encCtx->resultBase64Encoded != 0)) {
+
+	fprintf(output, "== Result - start buffer:\n");
+	fwrite(xmlSecBufferGetData(encCtx->result), 
+	       xmlSecBufferGetSize(encCtx->result), 1,
+	       output);
+	fprintf(output, "\n== Result - end buffer\n");
+    }
+}
+
+/**
+ * xmlSecEncCtxDebugXmlDump:
+ * @encCtx:		the pointer to <enc:EncryptedData/> processing context.
+ * @output:		the pointer to output FILE.
+ *
+ * Prints the debug information about @encCtx to @output in XML format.
+ */
+EXPORT_C
+void 
+xmlSecEncCtxDebugXmlDump(xmlSecEncCtxPtr encCtx, FILE* output) {
+    xmlSecAssert(encCtx != NULL);
+    xmlSecAssert(output != NULL);
+
+    switch(encCtx->mode) {
+	case xmlEncCtxModeEncryptedData:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "<DataEncryptionContext ");
+	    } else {
+		fprintf(output, "<DataDecryptionContext ");
+	    }
+	    break;
+	case xmlEncCtxModeEncryptedKey:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "<KeyEncryptionContext ");
+	    } else {
+		fprintf(output, "<KeyDecryptionContext ");
+	    }
+	    break;
+    }
+    fprintf(output, "status=\"%s\" >\n", (encCtx->resultReplaced) ? "replaced" : "not-replaced" );
+
+    fprintf(output, "<Flags>%08x</Flags>\n", encCtx->flags);
+    fprintf(output, "<Flags2>%08x</Flags2>\n", encCtx->flags2);
+
+    if(encCtx->id != NULL) {
+	fprintf(output, "<Id>%s</Id>\n", encCtx->id);
+    }
+    if(encCtx->type != NULL) {
+	fprintf(output, "<Type>%s</Type>\n", encCtx->type);
+    }
+    if(encCtx->mimeType != NULL) {
+	fprintf(output, "<MimeType>%s</MimeType>\n", encCtx->mimeType);
+    }
+    if(encCtx->encoding != NULL) {
+	fprintf(output, "<Encoding>%s</Encoding>\n", encCtx->encoding);
+    }
+    if(encCtx->recipient != NULL) {
+	fprintf(output, "<Recipient>%s</Recipient>\n", encCtx->recipient);
+    }
+    if(encCtx->carriedKeyName != NULL) {
+	fprintf(output, "<CarriedKeyName>%s</CarriedKeyName>\n", encCtx->carriedKeyName);
+    }
+
+    fprintf(output, "<KeyInfoReadCtx>\n");
+    xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoReadCtx), output);
+    fprintf(output, "</KeyInfoReadCtx>\n");
+
+    fprintf(output, "<KeyInfoWriteCtx>\n");
+    xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoWriteCtx), output);
+    fprintf(output, "</KeyInfoWriteCtx>\n");
+
+    fprintf(output, "<EncryptionTransformCtx>\n");
+    xmlSecTransformCtxDebugXmlDump(&(encCtx->transformCtx), output);
+    fprintf(output, "</EncryptionTransformCtx>\n");
+
+    if(encCtx->encMethod != NULL) {
+        fprintf(output, "<EncryptionMethod>\n");
+	xmlSecTransformDebugXmlDump(encCtx->encMethod, output);
+        fprintf(output, "</EncryptionMethod>\n");
+    }
+
+    if(encCtx->encKey != NULL) {
+        fprintf(output, "<EncryptionKey>\n");
+	xmlSecKeyDebugXmlDump(encCtx->encKey, output);
+        fprintf(output, "</EncryptionKey>\n");
+    }
+    
+    if((encCtx->result != NULL) && 
+       (xmlSecBufferGetData(encCtx->result) != NULL) && 
+       (encCtx->resultBase64Encoded != 0)) {
+
+	fprintf(output, "<Result>");
+	fwrite(xmlSecBufferGetData(encCtx->result), 
+	       xmlSecBufferGetSize(encCtx->result), 1,
+	       output);
+	fprintf(output, "</Result>\n");
+    }
+
+    switch(encCtx->mode) {
+	case xmlEncCtxModeEncryptedData:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "</DataEncryptionContext>\n");
+	    } else {
+		fprintf(output, "</DataDecryptionContext>\n");
+	    }
+	    break;
+	case xmlEncCtxModeEncryptedKey:
+	    if(encCtx->operation == xmlSecTransformOperationEncrypt) {    
+		fprintf(output, "</KeyEncryptionContext>\n");
+	    } else {
+		fprintf(output, "</KeyDecryptionContext>\n");
+	    }
+	    break;
+    }
+}
+
+#endif /* XMLSEC_NO_XMLENC */
+