Git init
[external/xmlsec1.git] / examples / encrypt3.c
1 /** 
2  * XML Security Library example: Encrypting XML file with a session key and dynamicaly created template.
3  * 
4  * Encrypts XML file using a dynamicaly created template file and a session 
5  * DES key (encrypted with an RSA key).
6  * 
7  * Usage: 
8  *      ./encrypt3 <xml-doc> <rsa-pem-key-file> 
9  *
10  * Example:
11  *      ./encrypt3 encrypt3-doc.xml rsakey.pem > encrypt3-res.xml
12  *
13  * The result could be decrypted with decrypt3 example:
14  *      ./decrypt3 encrypt3-res.xml
15  *
16  * This is free software; see Copyright file in the source
17  * distribution for preciese wording.
18  * 
19  * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
20  */
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #include <libxml/tree.h>
26 #include <libxml/xmlmemory.h>
27 #include <libxml/parser.h>
28
29 #ifndef XMLSEC_NO_XSLT
30 #include <libxslt/xslt.h>
31 #endif /* XMLSEC_NO_XSLT */
32
33 #include <xmlsec/xmlsec.h>
34 #include <xmlsec/xmltree.h>
35 #include <xmlsec/xmlenc.h>
36 #include <xmlsec/templates.h>
37 #include <xmlsec/crypto.h>
38
39 xmlSecKeysMngrPtr load_rsa_keys(char* key_file);
40 int encrypt_file(xmlSecKeysMngrPtr mngr, const char* xml_file, const char* key_name);
41
42 int 
43 main(int argc, char **argv) {
44     xmlSecKeysMngrPtr mngr;
45     
46     assert(argv);
47
48     if(argc != 3) {
49         fprintf(stderr, "Error: wrong number of arguments.\n");
50         fprintf(stderr, "Usage: %s <xml-file> <key-file>\n", argv[0]);
51         return(1);
52     }
53
54     /* Init libxml and libxslt libraries */
55     xmlInitParser();
56     LIBXML_TEST_VERSION
57     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
58     xmlSubstituteEntitiesDefault(1);
59 #ifndef XMLSEC_NO_XSLT
60     xmlIndentTreeOutput = 1; 
61 #endif /* XMLSEC_NO_XSLT */
62                 
63     /* Init xmlsec library */
64     if(xmlSecInit() < 0) {
65         fprintf(stderr, "Error: xmlsec initialization failed.\n");
66         return(-1);
67     }
68
69     /* Check loaded library version */
70     if(xmlSecCheckVersion() != 1) {
71         fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n");
72         return(-1);
73     }
74
75     /* Load default crypto engine if we are supporting dynamic
76      * loading for xmlsec-crypto libraries. Use the crypto library
77      * name ("openssl", "nss", etc.) to load corresponding 
78      * xmlsec-crypto library.
79      */
80 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
81     if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
82         fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n"
83                         "that you have it installed and check shared libraries path\n"
84                         "(LD_LIBRARY_PATH) envornment variable.\n");
85         return(-1);     
86     }
87 #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
88
89     /* Init crypto library */
90     if(xmlSecCryptoAppInit(NULL) < 0) {
91         fprintf(stderr, "Error: crypto initialization failed.\n");
92         return(-1);
93     }
94
95     /* Init xmlsec-crypto library */
96     if(xmlSecCryptoInit() < 0) {
97         fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n");
98         return(-1);
99     }
100
101     /* create keys manager and load keys */
102     mngr = load_rsa_keys(argv[2]);
103     if(mngr == NULL) {
104         return(-1);
105     }
106
107     /* we use key filename as key name here */
108     if(encrypt_file(mngr, argv[1], argv[2]) < 0) {
109         xmlSecKeysMngrDestroy(mngr);
110         return(-1);
111     }    
112
113     /* destroy keys manager */
114     xmlSecKeysMngrDestroy(mngr);
115     
116     /* Shutdown xmlsec-crypto library */
117     xmlSecCryptoShutdown();
118     
119     /* Shutdown crypto library */
120     xmlSecCryptoAppShutdown();
121     
122     /* Shutdown xmlsec library */
123     xmlSecShutdown();
124
125     /* Shutdown libxslt/libxml */
126 #ifndef XMLSEC_NO_XSLT
127     xsltCleanupGlobals();            
128 #endif /* XMLSEC_NO_XSLT */
129     xmlCleanupParser();
130     
131     return(0);
132 }
133
134 /**
135  * load_rsa_keys:
136  * @key_file:           the key filename.
137  *
138  * Creates simple keys manager and load RSA key from #key_file in it.
139  * The caller is responsible for destroing returned keys manager using
140  * @xmlSecKeysMngrDestroy.
141  *
142  * Returns the pointer to newly created keys manager or NULL if an error
143  * occurs.
144  */
145 xmlSecKeysMngrPtr 
146 load_rsa_keys(char* key_file) {
147     xmlSecKeysMngrPtr mngr;
148     xmlSecKeyPtr key;
149     
150     assert(key_file);
151     
152     /* create and initialize keys manager, we use a simple list based
153      * keys manager, implement your own xmlSecKeysStore klass if you need
154      * something more sophisticated 
155      */
156     mngr = xmlSecKeysMngrCreate();
157     if(mngr == NULL) {
158         fprintf(stderr, "Error: failed to create keys manager.\n");
159         return(NULL);
160     }
161     if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
162         fprintf(stderr, "Error: failed to initialize keys manager.\n");
163         xmlSecKeysMngrDestroy(mngr);
164         return(NULL);
165     }    
166     
167     /* load private RSA key */
168     key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
169     if(key == NULL) {
170         fprintf(stderr,"Error: failed to load rsa key from file \"%s\"\n", key_file);
171         xmlSecKeysMngrDestroy(mngr);
172         return(NULL);
173     }
174
175     /* set key name to the file name, this is just an example! */
176     if(xmlSecKeySetName(key, BAD_CAST key_file) < 0) {
177         fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file);
178         xmlSecKeyDestroy(key);  
179         xmlSecKeysMngrDestroy(mngr);
180         return(NULL);
181     }
182         
183     /* add key to keys manager, from now on keys manager is responsible 
184      * for destroying key 
185      */
186     if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) {
187         fprintf(stderr,"Error: failed to add key from \"%s\" to keys manager\n", key_file);
188         xmlSecKeyDestroy(key);
189         xmlSecKeysMngrDestroy(mngr);
190         return(NULL);
191     }
192
193     return(mngr);
194 }
195
196 /**
197  * encrypt_file:
198  * @mngr:               the pointer to keys manager.
199  * @xml_file:           the encryption template file name.
200  * @key_name:           the RSA key name.
201  *
202  * Encrypts #xml_file using a dynamicaly created template, a session DES key 
203  * and an RSA key from keys manager.
204  *
205  * Returns 0 on success or a negative value if an error occurs.
206  */
207 int 
208 encrypt_file(xmlSecKeysMngrPtr mngr, const char* xml_file, const char* key_name) {
209     xmlDocPtr doc = NULL;
210     xmlNodePtr encDataNode = NULL;
211     xmlNodePtr keyInfoNode = NULL;
212     xmlNodePtr encKeyNode = NULL;
213     xmlNodePtr keyInfoNode2 = NULL;
214     xmlSecEncCtxPtr encCtx = NULL;
215     int res = -1;
216     
217     assert(mngr);
218     assert(xml_file);
219     assert(key_name);
220
221     /* load template */
222     doc = xmlParseFile(xml_file);
223     if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){
224         fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_file);
225         goto done;      
226     }
227     
228     /* create encryption template to encrypt XML file and replace 
229      * its content with encryption result */
230     encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId,
231                                 NULL, xmlSecTypeEncElement, NULL, NULL);
232     if(encDataNode == NULL) {
233         fprintf(stderr, "Error: failed to create encryption template\n");
234         goto done;   
235     }
236
237     /* we want to put encrypted data in the <enc:CipherValue/> node */
238     if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) {
239         fprintf(stderr, "Error: failed to add CipherValue node\n");
240         goto done;   
241     }
242
243     /* add <dsig:KeyInfo/> */
244     keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
245     if(keyInfoNode == NULL) {
246         fprintf(stderr, "Error: failed to add key info\n");
247         goto done;              
248     }
249
250     /* add <enc:EncryptedKey/> to store the encrypted session key */
251     encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, 
252                                     xmlSecTransformRsaPkcs1Id, 
253                                     NULL, NULL, NULL);
254     if(encKeyNode == NULL) {
255         fprintf(stderr, "Error: failed to add key info\n");
256         goto done;              
257     }
258
259     /* we want to put encrypted key in the <enc:CipherValue/> node */
260     if(xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
261         fprintf(stderr, "Error: failed to add CipherValue node\n");
262         goto done;   
263     }
264
265     /* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> */
266     keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL);
267     if(keyInfoNode2 == NULL) {
268         fprintf(stderr, "Error: failed to add key info\n");
269         goto done;              
270     }
271     
272     /* set key name so we can lookup key when needed */
273     if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode2, key_name) == NULL) {
274         fprintf(stderr, "Error: failed to add key name\n");
275         goto done;              
276     }
277
278     /* create encryption context */
279     encCtx = xmlSecEncCtxCreate(mngr);
280     if(encCtx == NULL) {
281         fprintf(stderr,"Error: failed to create encryption context\n");
282         goto done;
283     }
284
285     /* generate a Triple DES key */
286     encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession);
287     if(encCtx->encKey == NULL) {
288         fprintf(stderr,"Error: failed to generate session des key\n");
289         goto done;
290     }
291
292     /* encrypt the data */
293     if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) {
294         fprintf(stderr,"Error: encryption failed\n");
295         goto done;
296     }
297     
298     /* we template is inserted in the doc */
299     encDataNode = NULL;
300         
301     /* print encrypted data with document to stdout */
302     xmlDocDump(stdout, doc);
303     
304     /* success */
305     res = 0;
306
307 done:    
308
309     /* cleanup */
310     if(encCtx != NULL) {
311         xmlSecEncCtxDestroy(encCtx);
312     }
313
314     if(encDataNode != NULL) {
315         xmlFreeNode(encDataNode);
316     }
317         
318     if(doc != NULL) {
319         xmlFreeDoc(doc); 
320     }
321     return(res);
322 }
323