Discuss this help topic in SecureBlackbox Forum

XML: Decrypt XML node(s)

After you called TElXMLDecryptor.Decrypt() method to perform decryption, you need to check the value of TElXMLDecryptor.EncryptedDataType. If the property value is xedtElement, the decrypted node is contained in TElXMLDecryptor.DecryptedNode property. If the property value is xedtContent, then the decrypted nodes can be contained in TElXMLDecryptor.DecryptedNode property if there was only one node decrypted, or in TElXMLDecryptor.DecryptedNodeList property, if there were several nodes decrypted.

After you've decrypted the node(s), you need to put them back to the right place of the document. You need to replace the EncryptedData element with the node(s) that were decrypted. This is done using ReplaceChild() method of the parent node, if you have just one decrypted node, or using InsertBefore() method of the parent node when you need to insert several elements. Note, that TElXMLDOMNodeList class, which contains the nodes in DecryptedNodeList property, owns the nodes, so you can't add those nodes directly. You need to use CloneNode() method of the node and add the clone to the document (as the original will be destroyed in future).

C#:


byte[] Decrypt(TElXMLDOMElement EncryptedDataElement, byte[] UserKey)
{
  TElXMLDecryptor Decryptor = new TElXMLDecryptor(null);
  TElXMLKeyInfoSymmetricData SymKeyData = new TElXMLKeyInfoSymmetricData(true);
  try
  {
    Decryptor.Load(EncryptedDataElement);
    if (Decryptor.EncryptKey)
      throw new Exception("Encrypted keys are not supported by this short sample.");

    // setup the key
    SymKeyData.Key.Key = UserKey;
    Decryptor.KeyData = SymKeyData;

    int k = Decryptor.Decrypt(EncryptedDataElement.OwnerDocument);
    if (k != SBXMLEnc.Unit.SB_XML_ENC_ERROR_OK)
    {
      if ((!Decryptor.EncryptKey && (k == SBXMLEnc.Unit.SB_XML_ENC_ERROR_INVALID_KEY)) ||
        (Decryptor.EncryptKey && (k == SBXMLEnc.Unit.SB_XML_ENC_ERROR_INVALID_KEK)))
        throw new Exception("Decryption failed. Bad key or data is corrupted");
      else
        throw new Exception(string.Format("Decryption failed. Error code: {0}", k));
    }

    if (Decryptor.EncryptedDataType != SBXMLSec.Unit.xedtExternal)
    {
      // additionally, we can replace xenc:EncryptedData element with decrypted node(s)
      TElXMLDOMNode ParentNode = EncryptedDataElement.ParentNode;
      if (Decryptor.DecryptedNode != null)
      {
        // replace
        ParentNode.ReplaceChild(Decryptor.DecryptedNode, EncryptedDataElement);
        Decryptor.DecryptedNode = null;
      }
      else
        if ((Decryptor.EncryptedDataType == SBXMLSec.Unit.xedtContent) && (Decryptor.DecryptedNodeList != null))
        {
          for (int i = 0; i < Decryptor.DecryptedNodeList.Length; i++)
            ParentNode.InsertBefore(Decryptor.DecryptedNodeList.get_Item(i).CloneNode(true), EncryptedDataElement);

          ParentNode.RemoveChild(EncryptedDataElement);
        }
    }

    // return the decrypted data
    return Decryptor.DecryptedData;
  }
  finally
  {
    Decryptor.Dispose();
    SymKeyData.Dispose();
  }
}
Delphi:

function Decrypt(EncryptedDataElement : TElXMLDOMElement; const UserKey : ByteArray) : ByteArray;
var
  Decryptor : TElXMLDecryptor;
  SymKeyData : TElXMLKeyInfoSymmetricData;
  ParentNode : TElXMLDOMNode;
  i, k : Integer;
begin
  Decryptor := TElXMLDecryptor.Create(nil);
  SymKeyData := TElXMLKeyInfoSymmetricData.Create(True);
  try
    Decryptor.Load(EncryptedDataElement);
    if Decryptor.EncryptKey then
      raise Exception.Create('Encrypted keys are not supported by this short sample.');

    // setup the key
    SymKeyData.Key.Key := UserKey;
    Decryptor.KeyData :=  SymKeyData;

    k := Decryptor.Decrypt(EncryptedDataElement.OwnerDocument);
    if k <> SB_XML_ENC_ERROR_OK then
    begin
      if (not Decryptor.EncryptKey and (k = SB_XML_ENC_ERROR_INVALID_KEY)) or
         (Decryptor.EncryptKey and (k = SB_XML_ENC_ERROR_INVALID_KEK)) then
        raise Exception.Create('Decryption failed. Bad key or data is corrupted')
      else
        raise Exception.CreateFmt('Decryption failed. Error code: 0x%x', [k]);
    end;

    // return the decrypted data
    Result := Decryptor.DecryptedData;
    if Decryptor.EncryptedDataType <> xedtExternal then
    begin
      // additionally, we can replace xenc:EncryptedData element with decrypted node(s)
      ParentNode := EncryptedDataElement.ParentNode;
      if Assigned(Decryptor.DecryptedNode) then
      begin
        // replace
        ParentNode.ReplaceChild(Decryptor.DecryptedNode, EncryptedDataElement);
        Decryptor.DecryptedNode := nil;
      end
      else
      if (Decryptor.EncryptedDataType = xedtContent) and Assigned(Decryptor.DecryptedNodeList) then
      begin
        for i := 0 to Decryptor.DecryptedNodeList.Length - 1 do
          ParentNode.InsertBefore(Decryptor.DecryptedNodeList.Item[i].CloneNode(True), EncryptedDataElement);

        ParentNode.RemoveChild(EncryptedDataElement);
      end;
    end;
  finally
    FreeAndNil(Decryptor);
    FreeAndNil(SymKeyData);
  end;
end;

How To articles about XML encryption (XMLEnc)

Discuss this help topic in SecureBlackbox Forum