EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Encrypting SOAP message

Also by EldoS: Callback File System
Create virtual file systems and disks, expose and manage remote data as if they were files on the local disk.
#30175
Posted: 07/30/2014 08:45:14
by San P (Standard support level)
Joined: 11/07/2009
Posts: 37

My Blackbox version is 9.0.203. With your help I was able to solve XML signing some years back. Now I am trying to Encrypt a SOAP message, and I am having difficulties to understand all the nested and complicated BlackBox classes.
Below is working sample and sample that I can produce with BBX.

Original OK sample
Code
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
  <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
  <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
    <xenc:EncryptedKey Recipient="name:AbcBankCryptCERT">
      <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
      <dsig:KeyInfo>
        <dsig:X509Data>
          <dsig:X509Certificate>MIIDmD...</dsig:X509Certificate>
        </dsig:X509Data>
      </dsig:KeyInfo>
      <xenc:CipherData>
        <xenc:CipherValue>lhfgQh...</xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedKey>
  </dsig:KeyInfo>
  <xenc:CipherData>
    <xenc:CipherValue>UryDRj9...</xenc:CipherValue>
  </xenc:CipherData>
</xenc:EncryptedData>


My BlackBox output
Code
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
  <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
  <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
    <xenc:EncryptedKey Recipient="name:AbcBankCryptCERT">
      <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
      <dsig:KeyInfo>
        <dsig:X509Data>
          <dsig:X509Certificate>MIIDmD...</dsig:X509Certificate>
        </dsig:X509Data>
      </dsig:KeyInfo>
      <xenc:CipherData>
        <xenc:CipherValue>lhfgQh...</xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedKey>
  </dsig:KeyInfo>
  <xenc:CipherData>
    <xenc:CipherValue>UryDRj9...</xenc:CipherValue>
  </xenc:CipherData>
</xenc:EncryptedData>

Compared to original sample my output seems to have at least these differences:

1) There is no 'xenc:' prefix. This kind of crypting related constant can be found in BBX sources. I wonder if that prefix necessary for crypting purposes, and how can I add these prefixes?

2) The <EncryptedData> lines are different. My BBX adds two extra namespaces. How can I alter this behaviour?

3) If I fill in the <EncryptedKey> value before calling TElXMLEncryptor.Encrypt, then the <EncryptedKey> value will not stay in crypted output. I can add this XML Node it afterwards by calling:
TElXMLEncryptor.EncryptedData.EncryptedKey.Recipient := 'name:AbcBankCryptCERT',
but this probably is not the designed way how to call and use this.

4) I do not find the way how to keep <ds:RSAKeyValue> not appearing to the crypted output.
If I try to set the TElXMLEncryptor.EncryptKey := False, then application halts.

This same behaviour is also in Simple Signer Sample. In Simple Signer if I turn that same value to False, also it will raise exception.

---
I saw you have published some new SOAP related 12.x versions too. I wonder if they would be for any help with this matter?

Thanks for any help
-Sanna
#30177
Posted: 07/30/2014 09:26:29
by Dmytro Bogatskyy (EldoS Corp.)

Thank you for contacting us.

Quote
Compared to original sample my output seems to have at least these differences:

You have posted the same outputs (for OK sample and My BlackBox).
Quote
1) There is no 'xenc:' prefix. This kind of crypting related constant can be found in BBX sources. I wonder if that prefix necessary for crypting purposes, and how can I add these prefixes?

No, it's not necessary, you can use any prefix you want, the only thing that namespace URI for the elements should be standard.
You can add "xenc:" prefix using EncryptionPrefix property, for example:
Code
TElXMLEncryptor.Encrypt();
....
TElXMLEncryptor.EncryptedData.EncryptionPrefix := 'xenc';


Quote
3) If I fill in the <EncryptedKey> value before calling TElXMLEncryptor.Encrypt, then the <EncryptedKey> value will not stay in crypted output. I can add this XML Node it afterwards by calling:
TElXMLEncryptor.EncryptedData.EncryptedKey.Recipient := 'name:AbcBankCryptCERT',
but this probably is not the designed way how to call and use this.

It is right place. The Encrypt method encrypts data and generates EncryptedData structure that you can modify prior saving to xml.
Quote
4) I do not find the way how to keep <ds:RSAKeyValue> not appearing to the crypted output.
If I try to set the TElXMLEncryptor.EncryptKey := False, then application halts.

If you set EncryptKey property to false, then a component expect a symmetric key, and the component should raise an exception if you would set not TElXMLKeyInfoSymmetricData object to KeyData property.
If you don't want to include RSAKeyValue element just disable TElXMLKeyInfoX509Data.IncludeKeyValue property for a KeyEncryptionKeyData key.
Quote
I saw you have published some new SOAP related 12.x versions too. I wonder if they would be for any help with this matter?

No, as SOAP components doesn't support encryption at the moment.
#30180
Posted: 07/30/2014 12:49:39
by San P (Standard support level)
Joined: 11/07/2009
Posts: 37

Oops, sorry... I was trying to take off extra indenting, and then accidentally posted the same XML twice.
My BlackBox output
Code
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
  <ds:KeyInfo>
    <EncryptedKey Recipient="name:AbcBankCryptCERT">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
      <ds:KeyInfo>
        <ds:KeyValue>
          <ds:RSAKeyValue>
            <ds:Modulus>v5B6zrx...</ds:Modulus>
            <ds:Exponent>Aw==</ds:Exponent>
          </ds:RSAKeyValue>
        </ds:KeyValue>
      </ds:KeyInfo>
      <CipherData>
        <CipherValue>q2Hz/yc...</CipherValue>
      </CipherData>
    </EncryptedKey>
  </ds:KeyInfo>
  <CipherData>
    <CipherValue>udZ2L...</CipherValue>
  </CipherData>
</EncryptedData>

I'll pass here snippet about the code how I create that output. The TElX509Certificate component probably would not be needed at all. But I have never got this style from BBX Samples to load the Public Key:
Code
F := TFileStream.Create('C:\TEST\Certificate.CER', fmOpenRead or fmShareDenyWrite);
RSAKeyData.RSAKeyMaterial.LoadPublic(F); // This always fails.

The following Function takes un-encrypted SOAP string as parameter, encrypts it and returns it as encrypted in Resulting string.
Code
function TForm1.CryptSoap(stSoapXML : String): String;
var
  Encryptor: TElXMLEncryptor;
  SymKeyData: TElXMLKeyInfoSymmetricData;
  RSAKeyData: TElXMLKeyInfoRSAData;
  X509KeyData: TElXMLKeyInfoX509Data;
  Node, EncNode: TElXMLDOMNode;
  ElXMLDOMDocument1:TElXMLDOMDocument;
  ElX509Certificate1: TElX509Certificate;
  F: TFileStream;
  i:Integer;
begin
  SymKeyData := nil;
  RSAKeyData := nil;
  X509KeyData := nil;
  ElXMLDOMDocument1 := TElXMLDOMDocument.Create;
  // My own routine to load SOAP XML string to TElXMLDOMDocument
  XMLDOMDocLoadFromString(ElXMLDOMDocument1, stSoapXML);
  begin
    Encryptor := TElXMLEncryptor.Create(Self);
    try
       Encryptor.EncryptKey := True;
       Encryptor.EncryptionMethod := xem3DES;
       Encryptor.KeyName := '';
       Encryptor.EncryptedDataType := xedtElement;
       if Encryptor.EncryptKey then
       begin
         Encryptor.KeyEncryptionType := xetKeyTransport;
         Encryptor.KeyTransportMethod := xktRSA15;
         Encryptor.KeyWrapMethod := xwm3DES;
         SymKeyData := TElXMLKeyInfoSymmetricData.Create(True);

         { Generate random Key & IV }
         SymKeyData.Key.Generate(T3DESKeySize * 8);
         SymKeyData.Key.GenerateIV(8 * 8);
         Encryptor.KeyData := SymKeyData;

         RSAKeyData := TElXMLKeyInfoRSAData.Create(True);
         RSAKeyData.RSAKeyMaterial.Passphrase := '';
         X509KeyData := TElXMLKeyInfoX509Data.Create(True);

         // This should keep RSA Key NOT being saved to SOAP, seems not to work.
         X509KeyData.IncludeKeyValue := False;
         ElX509Certificate1 := TElX509Certificate.Create(nil);
         F := TFileStream.Create('C:\TEST\Certificate.CER', fmOpenRead or fmShareDenyWrite);
         F.Position :=0;
         ElX509Certificate1.LoadFromStream(F,i);

         RSAKeyData.RSAKeyMaterial.Assign(ElX509Certificate1.KeyMaterial);
         if RSAKeyData.RSAKeyMaterial.PublicKey then
           Encryptor.KeyEncryptionKeyData := RSAKeyData
         else
         if Assigned(X509KeyData.Certificate) then
           Encryptor.KeyEncryptionKeyData := X509KeyData
         else
           raise EElXMLError.Create('Key not loaded.');
       end;

       // My own seek routine to Find 'CreateCertificateRequest' node.
       Node := DmWs.DtcFindElementByName(ElXMLDOMDocument1.DocumentElement, 'CreateCertificateRequest');

       Encryptor.Encrypt(Node);
       Encryptor.EncryptedData.EncryptedKey.Recipient := 'name:AbcBankCryptCERT';
       try
         EncNode := Encryptor.Save(ElXMLDOMDocument1);
       except
         on E: Exception do
           raise EELXMLError.CreateFmt('Encrypted data saving failed. (%s)', [E.Message]);
       end;
       Node.ParentNode.ReplaceChild(EncNode, Node);
       // Finally, return crypted XMLDOMDoc SOAP content in Result string.
       DmWs.XMLDOMDocSaveToString(ElXMLDOMDocument1, Result);

    finally
      FreeAndNil(Encryptor);
      FreeAndNil(SymKeyData);
      FreeAndNil(RSAKeyData);
      FreeAndNil(X509KeyData);
      FreeAndNil(ElXMLDOMDocument1);
      FreeAndNil(ElX509Certificate1);
      FreeAndNil(F);
    end;
  end;
end;

As I told in my earlier post, the created output has differences compared to the wanted target. Bank rejects it, without a word about the reason.

Thanks
-Sanna
#30189
Posted: 08/01/2014 09:06:10
by San P (Standard support level)
Joined: 11/07/2009
Posts: 37

There seems not be any more comments about my previous question. Here's shorter and more pinpointed question.

XML is this
Code
<soapenv xmlns:pkif="http://bank.dk/PKI">
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
</xenc:EncryptedData>
</soapenv>

Code is this
Code
procedure TForm1.Btn1Click(Sender: TObject);
var
  aElXMLDOMDocument : TElXMLDOMDocument;
  aElXMLDOMElement : ElXMLDOMElement;
  F : TFileStream;
begin
  aElXMLDOMDocument := TElXMLDOMDocument.Create;
  F := TFileStream.Create('E:\DEL\SOAP1.XML', fmOpenRead or fmShareDenyWrite);
  F.Position := 0;
  aElXMLDOMDocument.LoadFromStream(F, 'utf-8', True);
  F.Free;

  aElXMLDOMElement := FindElementByName(aElXMLDOMDocument.DocumentElement, 'EncryptedData','http://www.w3.org/2001/04/xmlenc#');
  if aElXMLDOMElement <> nil then
  aElXMLDOMElement.RemoveAttributeNS('http://www.w3.org/2001/04/xmlenc#', 'EncryptedData');

  F := TFileStream.Create('E:\DEL\SOAP-OUT.XML', fmCreate);
  aElXMLDOMDocument.SaveToStream(F, xcmNone,'utf-8');
  F.Free;
  aElXMLDOMDocument.Free;
end;

My intention is to remove the 'xmlns:xenc="http://www.w3.org/2001/04/xmlenc#' name space away, but this code does not seem to work. What could be wrong?

Thanks
-Sanna
#30192
Posted: 08/01/2014 13:48:06
by Dmytro Bogatskyy (EldoS Corp.)

Hello,
Quote
My intention is to remove the 'xmlns:xenc="http://www.w3.org/2001/04/xmlenc#' name space away, but this code does not seem to work. What could be wrong?

You can't remove a namespace declaration that is being used if it is not defined in the parent elements. The prefix itself doesn't hold enough information to identify element. Shortly speaking, the local name (name without a prefix) and namespace URI is the main info of the element and the prefix is a secondary info (for usability).
#30193
Posted: 08/01/2014 16:54:51
by San P (Standard support level)
Joined: 11/07/2009
Posts: 37

Thanks for your response. I have a crypted XML-sample that returns some response from Bank. My SOAP XML does not get any reponse. I am trying to make sure my BBX created XML would be as identical as possible. Now BBX already creates almost identical output.

Piece of the working sample
Code
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">

My sample
Code
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<dsig:KeyInfo">

As you can see BBX puts that 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"' namespace differently than the working code. I have not found property or setting that would make it to appear in <dsig:KeyInfo>.

My simple idea was to move it inside XML to the wanted location. So take it out where it is now, and re-create it in <dsig:KeyInfo> node. Bank really gives response only with the original sample, not with my sample.

I am not sure if that namespace location has anything to do it. The reason may be somewhere inside my the crypted SOAP nodes anyway.

Thanks
-Sanna
#30194
Posted: 08/02/2014 06:02:00
by Dmytro Bogatskyy (EldoS Corp.)

Hello,
Quote
As you can see BBX puts that 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"' namespace differently than the working code. I have not found property or setting that would make it to appear in <dsig:KeyInfo>.

My simple idea was to move it inside XML to the wanted location. So take it out where it is now, and re-create it in <dsig:KeyInfo> node. Bank really gives response only with the original sample, not with my sample.

To change "ds" prefix you can use SignaturePrefix property, it is similar to EncryptionPrefix property, for example:
Code
TElXMLEncryptor.Encrypt();
...
TElXMLEncryptor.EncryptedData.EncryptionPrefix := 'xenc';
TElXMLEncryptor.EncryptedData.SignaturePrefix := 'dsig';

Then, as you need this namespace declaration only in KeyInfo element, you can do the following:
Code
TElXMLEncryptor.Save(...);
...
TElXMLEncryptor.EncryptedData.XMLElement.RemoveAttribute('xmlns:dsig');
// namespace declaration for KeyInfo element would be created automatically
#30234
Posted: 08/07/2014 12:22:27
by San P (Standard support level)
Joined: 11/07/2009
Posts: 37

Thanks, that "namespace declaration for KeyInfo element would be created automatically" was just the magic I was missing. I immediately got the SOAP nodes to look like those in the original sample.

Yet it took this far to find what was causing my SOAP:s still rejected by bank, not a single line as response. After checking and testing several, several times all the possible SOAP lines, key lengths etc. through I finally found what was the difference.

For long time I thought it was the missing BBX <CR>s. Or some other invisible magic after that kept my identical SOAP messages rejected by bank. Finally I found it was the invisible BOM in the beginning. Bank did not accept that and stayed completely silent.

I knew the existence of BOM in general. This new SOAP encrypting operation just brought it there so silently. Took days and I could not realize it, as there were tens of other lines and things to suspect.
But thanks, now it looks much better already.
#30235
Posted: 08/07/2014 13:02:01
by Dmytro Bogatskyy (EldoS Corp.)

Thank you for the info.

If you need to save an XML document without BOM (byte order mark), then you can use a following code:
Code
  F := TFileStream.Create(Filename, fmCreate or fmOpenWrite);
  Codec := TElXMLUTF8Codec.Create;
  try
    Codec.WriteBOM := False; // Prevent BOM
    XMLDocument.SaveToStream(F, xcmNone, Codec);
  finally
    FreeAndNil(Codec);
    FreeAndNil(F);
  end;
Also by EldoS: Solid File System
A virtual file system that offers a feature-rich storage for application documents and data with built-in compression and encryption.

Reply

Statistics

Topic viewed 1109 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!