XML Security Library

XML Encryption
Example 1. Encrypting

To encrypt data using XML Security Library the application should:
  1. Create encryption context (depending on the application it could be done once in the beggining of the program).
  2. Create or load encryption template that describes the encryption algorithm, encryption key transport mechanism, etc.
  3. Call one of the encryption functions:
    • xmlEncEncryptMemory()
    • xmlEncEncryptUri()
    • xmlEncEncryptXmlNode()
  4. Verifiy the result.
In this example, we will encrypt a string using AES-128 algorithm with session key which will be RSA encrypted and included into the XML document. The source code for this example is included into the package: source code and the encrypted document .

Step 0. Initializing LibXML, OpenSSL and XML Security Library.

Before using the libraries we need to initialize them. This should be done once in the beginning of your program
   
    int rnd_seed = 0;   

    /**
     * Init OpenSSL:
     * this is a BAD way to init random numbers
     * generator
     */   
    while (RAND_status() != 1) {
       RAND_seed(&rnd_seed, sizeof(rnd_seed));
    }
   
    /**
     * Init libxml
     */    
    xmlInitParser();
    LIBXML_TEST_VERSION
 

     /**
     * Init xmlsec
     */
    xmlSecInit();   

Step 1. Loading key and creating the encryption context.

Before encrypting or decrypting the document you should create encryption context object.  In most case you will need only one context object per application

    xmlSecKeysReadContext keysReadCtx;
    xmlSecSimpleKeyMngrPtr keyMgr = NULL;
    xmlEncCtxPtr ctx = NULL;
   
    /**
     * Create Keys managers
     */
    keyMgr = xmlSecSimpleKeyMngrCreate();   
    if(keyMgr == NULL) {
      fprintf(stderr, "Error: failed to create keys manager\n");
      return(-1);   
    }

 
    /**
     * Create Keys Search context
     */
    memset(&keysReadCtx, 0, sizeof(keysReadCtx));
    keysReadCtx.allowedOrigins = xmlSecKeyOriginAll;
    keysReadCtx.findKeyCallback = xmlSecSimpleKeyMngrFindKey;
    keysReadCtx.findKeyContext = keyMgr;

    /**
     * Create enc context
     */
    ctx = xmlEncCtxCreate(&keysReadCtx);
    if(ctx == NULL) {
      fprintf(stderr, "Error: template failed to create context\n");
      return(-1)
    }
    /**
     * load key public rsa key
     */
    if(xmlSecSimpleKeyMngrLoadPublicKey(keyMgr, argv[1], NULL, NULL) == NULL) {
      fprintf(stderr, "Error: failed to load key from \"%s\"\n", argv[1]);
      return(-1);
    }
 
    /**
     * Create Keys Search context
     */
    memset(&keysReadCtx, 0, sizeof(keysReadCtx));

    keysReadCtx.allowedOrigins = xmlSecKeyOriginAll;
    keysReadCtx.findKeyCallback = xmlSecSimpleKeyMngrFindKey;
    keysReadCtx.findKeyContext = keyMgr;
    /**
     * Create Signature Context
     */
    ctx = xmlEncCtxCreate(&keysReadCtx);
    if(dsigCtx == NULL) {
      fprintf(stderr,"Error: failed to create context\n");
      return(-1)
    }

Step 2. Creating the template.

In this example we will create encryption template dynamically. However, you can also prepare encryption templates manually, save as XML files and quickly load them into the application.

    xmlEncTmplPtr tmplKey = NULL;
    xmlEncTmplPtr tmplData = NULL;
    xmlEncResultPtr result = NULL;
    xmlNodePtr cur;
    int ret;
   
    /**
     * Create the EncryptedData node
     */
    tmplData = xmlEncTmplCreate(NULL, NULL, NULL, NULL);
    if(tmplData == NULL) {
     
fprintf(stderr, "Error: template creation failed\n");
      goto done;    
    }

    /**
     * Set the encryption method
     */
    cur = xmlEncTmplAddEncMethod(tmplData, xmlSecEncAes128Cbc);
    if(cur == NULL) {
fprintf(stderr, "Error: failed to add Enc Method\n");
      goto done;    
    }

    /**
     * Add EncryptionProperties node just for fun
     */
    cur = xmlEncTmplAddEncProperty(tmplData, BAD_CAST "Classified", NULL);
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add KeyInfo\n");
      goto done;    
    }
    xmlSetProp(cur, BAD_CAST "Level", BAD_CAST "Top secret: destroy before reading");

    /**
     * The encrypted data should be saved in CipherValue node
     */
    cur = xmlEncTmplAddCipherValue(tmplData);   
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add CipherValue\n");
      goto done;    
    }

    /**
     * Add key info node
     */
    cur = xmlEncTmplAddKeyInfo(tmplData);
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add KeyInfo\n");
      goto done;    
    }

    /**
     * The session AES key will be RSA encrypted and included
     * in the message
     */
    tmplKey = xmlKeyInfoAddEncryptedKey(cur, NULL, NULL, NULL);
    if(tmplKey == NULL) {
      fprintf(stderr, "Error: failed to add EncryptedKey\n");
      goto done;    
    }
   
    /**
     * Set the encryption method for encrypting the key
     */
    cur = xmlEncTmplAddEncMethod(tmplKey, xmlSecEncRsaOaep);
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add EncryptedKey Enc Method\n");
      goto done;    
    }
   
    /**
     * The encrypted key should be stored in XML document
     */
    cur = xmlEncTmplAddCipherValue(tmplKey);   
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add EncryptedKey CipherValue\n");
      goto done;    
    }

    /**
     * Now specify the key used to encrypt session key
     */
    cur = xmlEncTmplAddKeyInfo(tmplKey);
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add EncryptedKey KeyInfo\n");
      goto done;    
    }

    cur = xmlKeyInfoAddKeyName(cur);
    if(cur == NULL) {
      fprintf(stderr, "Error: failed to add EncryptedKey KeyName\n");
      goto done;    
    }          

Step 3. Encrypt the data and print result document to stdout.

We are ready to encrypt the document!
   
    static const char buf[] = "big secret";
 
   /**
     * Finally encrypt everything
     */
    ret = xmlEncEncryptMemory(ctx, tmplData, (const unsigned char*)buf,
                 strlen(buf), &result);
    if(ret < 0) {
       fprintf(stderr, "Error: memory encryption failed\n");
       goto done;    
    }
    
    /**
     * And print result to stdout
     */                 
    xmlDocDump(stdout, tmplData->doc)

Step 4. Cleanup.

At the end we need to destroy encryption context, the doc and KeysManager; shutdown XML Security Library, libxml and OpenSSL:

     /*
     * Cleanup
     */  
    if(ctx != NULL) {
       xmlEncCtxDestroy(ctx);
    }
    if(keyMgr != NULL) {
       xmlSecSimpleKeyMngrDestroy(keyMgr);
    }
    
    /**
     * Shutdown XML Sec
     */
    xmlSecShutdown();

    /**
     * Shutdown libxslt
     */
    xsltCleanupGlobals();


    /*
     * Shutdown libxml
     */
    xmlCleanupParser();
    
    /*
     * Shutdown OpenSSL
     */
    RAND_cleanup();
    ERR_clear_error();

Appendix A. The encrypted document.

<?xml version="1.0"?>
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>test-rsa-key</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>
ETFcDnUPrXyZpaUNDCbe6r6E+YIWmoXBcppWHgv03H+0jIH+w74YKRJh601KUA4u
KDUK/MbglWQ40FvQ4vhOC4X0uGtWizRllOoZJHn9ppzAcIuwURQOIjCNl9GtrcEx
14HNIlUoAEXjIbbwSaGCS5u4IdtxzhS2f9P8INh5PkpJjV9EYT73cbX4Cq5e4Yto
Puox+NUpfOhSfPhTf+41+3u99Nn6oaxlLokfl//lbSE8gD2Yo48cyXN2HkX4tchF
qOFdCb5bYXA/NmLnrdXXm1Fpuf4QoLDXmbfrCXGF+mHSBkVC1C49FL4ynIVGcBF3
FibDfsohFvg/ucbDhKHNVQ==
</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>
BwP8RHXhJ8xcFVSONxfkwOxhgZNElAmJbaaAdzAIjbk=
</CipherValue>
</CipherData>
<EncryptionProperties>
<EncryptionProperty Id="Classified" Level="Top secret"/>
</EncryptionProperties>
</EncryptedData>

Aleksey Sanin