EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Calulate digest value & signature value

Also by EldoS: CallbackRegistry
A component to monitor and control Windows registry access and create virtual registry keys.
#27226
Posted: 11/13/2013 07:16:20
by Jacob jvandiermen (Standard support level)
Joined: 08/09/2013
Posts: 55

Hello Eldos,

I use your Eldos XMLBlackBox components to generate a xml signature.
The purpose for this is to digitally sign a payment order and send it to the bank.
Hereby I use TElXMLSigner object for signing and a TElXMLKeyInfoX509Data for loading the private key certificate.
The setting for the TElXMLSigner object are:
• CanonicalizationMethod := xcmCanon;
• SignatureMethodType := xmtSig;
• SignatureMethod := xsmRSA_SHA1;

For the <ds:Reference> element we only use the <ds:Object> node for the URI.
So we have only one <ds:Reference> element with <ds:Reference URI=”#Resource1”> and
<ds:Object id=”Resource1”> in the <ds:SignedInfo>
When I generate the xml signature and send it to the bank the xml signature is rejected.
The bank confirms that the xml structure and tags are valid.
To verify what is wrong with my xml signature the bank signs the same payment order I used and generated a xml signature.
I can see that the digest value en signature value are different form the values I calculated in my signature file.
To calculate the digest value you have to canonicalized the <ds:Object id=”Resource1”> node and use this as input for the SHA1. Then we encode the output as Base64.
Now I use a function with the standard SHA1 algorithm to calculate the SHA1 value.
Than I encoded this to Base64. That isn’t the right way to do it. Because my input isn't canonicalized before I I use it in the SHA1 function.
How can I do that ? I think I have to use a TElXMLReference object to calculate the digest value for me.
Furthermore when I manipulate the digest value ( I used the digest value the bank calculated) in the xml and calculate the signature value with TElXMLReference object property URINode set to the <ds:SignedInfo> I don’t get the same result for the signature value as the bank. So evindently I'm not setting the proeperties of the TElXMLReferenceto the right values.

Here is the code I Use:

Code

TXMLSignatureNodes =
              (
                dsig_Signature                =  0,

                dsig_SignedInfo               =  1,

                dsig_CanonicalizationMethod   =  2,

                dsig_SignatureMethod          =  3,

                dsig_Reference                =  4,

                dsig_DigestMethod             =  5,

                dsig_DigestValue              =  6,

                dsig_SignatureValue           =  7,

                dsig_KeyInfo                  =  8,

                dsig_X509Data                 =  9,

                dsig_X509SubjectName          = 10,

                dsig_X509Certificate          = 11,

                dsig_KeyValue                 = 12,

                dsig_RSAKeyValue              = 13,

                dsig_Modulus                  = 14,

                dsig_Exponent                 = 15,

                dsig_Object                   = 16,

              );

    TXMLSignatureTypes =
              (
                    xst_Detached,
                    xst_Enveloped,
                    xst_Enveloping
              );

function encryptStringWithSHA1HashBase64Encoding(strValue: AnsiString): AnsiString;
var
  index: Integer;
  DCP_sha1: TDCP_sha1;
  digest: array[0..19] of byte;  // SHA-1 produces a 160bit (20byte) output
  digest4Base64: ByteArray;
begin
  try
    begin
      try
        DCP_sha1:= TDCP_sha1.Create(nil);
        DCP_sha1.Init;
        DCP_sha1.UpdateStr(strValue);
        DCP_sha1.Final(digest);
        SetLength(digest4Base64,succ(High(digest)));
        for index:= low(digest) to high(digest) do
          begin
            digest4Base64[index]:= digest[index];
          end;
        result:= SBEncoding.Base64EncodeArray(digest4Base64,True);
      except
        on E : Exception do
          result:= '';
      end;
    end
  finally
    DCP_sha1.Burn;
    FreeAndNil(DCP_sha1);
  end;
end;

function getSignatureValue(fileNameCertificate,keyName,password: string; xmlDOMDocument: TElXMLDOMDocument ;                                           node2Sign: TXMLSignatureNodes; xmlSignatureType: TXMLSignatureTypes): AnsiString;
var
  index: integer;
  xmlNodeName: string;
  xmlDOMNode, xmlDOMNode4Signing: TElXMLDOMNode;
  xmlDOMNodeList: TElXMLDOMNodeList;
  certificateFileStream: TFileStream;
  xmlReferenceList: TElXMLReferenceList;
  xmlReference: TElXMLReference;
  xmlSigner: TElXMLSigner;
  RSAKeyData: TElXMLKeyInfoRSAData;
  X509KeyInfoData: TElXMLKeyInfoX509Data;
  PGPKeyData: TElXMLKeyInfoPGPData;

  bFound: boolean;
  parentNode: TParentNodeRecord;
begin
   result:= '';
  //For signing we have to point to a node that blackbox calls the reference  
  //object  which we will use for the singing.
  xmlReference:= TElXMLReference.Create;
  xmlReference.DigestMethod := xdmSHA1;


  //assign the node element we are going to use for signing to the refernce
  //object URINode propertie
  xmlNodeName:= replaceUnderscoreByColon(getXMLSignatureNodesEnumNameAsString(node2Sign));
  // just to check if node has all the siblings
  xmlDOMNodeList:= xmlDOMDocument.ChildNodes;
  //We just want the first node from the xml this is the <ds:SigendInfo> node
  xmlDOMNode:= xmlDOMNodeList.Item[pred(xmlDOMNodeList.Length)];
  if xmlDOMNode.HasChildNodes then
    for index:= 0 to Pred(xmlDOMNode.ChildNodes.Length) do
      begin
        if AnsiCompareStr(xmlNodeName,xmlDOMNode.ChildNodes.Item[index].NodeName) = 0 then
          begin
            //we have to initialize a TElXMLDomNode if we are using the  
            //enveloped or enveloping method for signing
            xmlDOMNode4Signing:= xmlDOMNode.ChildNodes.Item[index].CloneNode(true);
            xmlReference.URINode:= xmlDOMNode.ChildNodes.Item[index];
            Break;
          end;
      end;

  xmlReference.URI:= '';
  xmlReference.URI := '#' + xmlNodeName;
  xmlReference.TransformChain.Add(TElXMLEnvelopedSignatureTransform.Create);
  xmlReferenceList:= TElXMLReferenceList.Create;
  xmlReferenceList.Add(xmlReference);

  //For the actual signing we use the TElXMLSigner object. Because the signing
  //is with a certificate
  //we use a TElXMLKeyInfoX509Data object which will contain the certificate
  //information
  xmlSigner:= TElXMLSigner.Create(nil);
  case (xmlSignatureType) of
    TXMLSignatureTypes.xst_Enveloped:   xmlSigner.SignatureType:= xstEnveloped;
    TXMLSignatureTypes.xst_Enveloping:  xmlSigner.SignatureType:= xstEnveloping
  end;
  xmlSigner.CanonicalizationMethod := xcmCanon;
  xmlSigner.SignatureMethodType := xmtSig;
  xmlSigner.SignatureMethod := xsmRSA_SHA1;
  xmlSigner.MACMethod:= xmmHMAC_SHA1;
  xmlSigner.References := xmlReferenceList;
  xmlSigner.KeyName := keyName;
  xmlSigner.IncludeKey := True;

  RSAKeyData := TElXMLKeyInfoRSAData.Create(True);
  RSAKeyData.RSAKeyMaterial.Passphrase := password;
  X509KeyInfoData := TElXMLKeyInfoX509Data.Create(True);
  PGPKeyData := TElXMLKeyInfoPGPData.Create(True);

  //We use the TElXMLKeyInfoRSAData object to read all the info from the
  //certifiacte
  try
    certificateFileStream:= TFileStream.Create(fileNameCertificate, fmOPENREAD or fmShareDenyWrite );
  except
  end;
  //If the TElXMLKeyInfoRSAData hasn't got a secret key we can use the TElXMLKeyInfoX509Data object
  //to retieve  de certifiacte information
  if not RSAKeyData.RSAKeyMaterial.SecretKey then
  begin
    certificateFileStream.Position := 0;
    loadCertificate(certificateFileStream, RSAKeyData.RSAKeyMaterial.Passphrase,X509KeyInfoData);
  end;


  FreeAndNil(certificateFileStream);

  if Assigned(X509KeyInfoData.Certificate) then
    begin
      xmlSigner.KeyData := X509KeyInfoData;
    end;

  xmlSigner.UpdateReferencesDigest;

  xmlSigner.GenerateSignature;
  xmlSigner.Signature.SignaturePrefix:= 'dsig';

  try
    xmlSigner.Save(xmlDOMNode4Signing);
    if Assigned(xmlSigner)  then
      begin
        if Assigned(xmlSigner.Signature) then
          if Assigned(xmlSigner.Signature.SignatureValue) then
            result:= SBEncoding.Base64EncodeArray(xmlSigner.Signature.SignatureValue.Value,True);
      end;
  except

  end;

  FreeAndNil(xmlSigner);
  FreeAndNil(RSAKeyData);
  FreeAndNil(X509KeyInfoData);
  FreeAndNil(PGPKeyData);
  FreeAndNil(xmlReferenceList);
end;


Regards,

Jacob
#27228
Posted: 11/13/2013 07:45:11
by Dmytro Bogatskyy (EldoS Corp.)

The question has been moved to HelpDesk for investigation

Reply

Statistics

Topic viewed 1822 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!