如何在Delphi中正确签名XML [英] How to properly Sign XML in Delphi

查看:163
本文介绍了如何在Delphi中正确签名XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用证书在Delphi中对XML进行签名,但我得到的只是一些无法识别的字符。
我正在使用此功能

I'm trying to sign XML in Delphi with certificate, but all I'm getting are some unrecognized characters. I'm using this function

var
   xmlData, signature: PByte; data: array[0..0] of PByte;
   msgCert: array[0..0] of PCCERT_CONTEXT;
   dwDataSizeArray: array[0..0] of DWORD;
   sigParams: CRYPT_SIGN_MESSAGE_PARA;
   cbSignedBlob: DWORD;
begin
   if PCertContext = nil then
    Exit;

   GetMem(xmlData, Length(AXml));
   try
      system.Move(Pointer(AXml)^, xmlData^, Length(AXml));
      ZeroMemory(@sigParams, SizeOf(CRYPT_SIGN_MESSAGE_PARA));
      sigParams.cbSize := SizeOf(CRYPT_SIGN_MESSAGE_PARA);
      sigParams.dwMsgEncodingType := (X509_ASN_ENCODING or PKCS_7_ASN_ENCODING);

      sigParams.pSigningCert := PCertContext;
      sigParams.HashAlgorithm.pszObjId := szOID_RSA_MD5;
      //SigParams.cAuthAttr := 0;
      //SigParams.dwInnerContentType := 0;
      //SigParams.cMsgCrl := 0;
      //SigParams.cUnauthAttr := 0;
      //SigParams.dwFlags := 0;
      //SigParams.pvHashAuxInfo := nil;
      //SigParams.rgAuthAttr := nil;  }
      data[0] := xmlData;
      dwDataSizeArray[0] := Length(AXml);
      cbSignedBlob := 0;

      CryptSignMessage(@sigParams, True, 1, @data[0], @dwDataSizeArray[0], nil, @cbSignedBlob);

      GetMem(signature, cbSignedBlob);
      try
         CryptSignMessage(@sigParams, True, 1, @data[0], @dwDataSizeArray[0], signature, @cbSignedBlob);
         SetLength(Result, cbSignedBlob);
         system.Move(signature^, Pointer(Result)^, cbSignedBlob);
      finally
         FreeMem(signature);
      end;
   finally
      FreeMem(xmlData);
   end;
end

但我得到的只是:


'舰餁आ蘪虈'#$ 0DF7'܁ꀂƂりƂʆāัర'#$ 0806'蘪虈'#$0DF7'Ԃ'#5'ରआ蘪虈'# $ 0DF7'܁'#$ 3101'ƂぢƂɞā㠰
br

'#$0B31'serv̆sጆ匂ㅉ『#'#$0A04'ԓ佐呓ㅁ]؏唃'#$ 0 B04#$ 0813'佐呓牁䅃Ђ䤾Eర'#$ 0806'蘪虈'#$0DF7'Ԃ'#5'രआ蘪虈'#$0DF7'āԁЀƂ堀묥䮡悕㈒古虺̐升⠹꺶힊觊 왧䮽㕺⢂꺇宬䝄'#$ 07B3'䲠'#$ D868'㶙㌱㟜'#$ DAF2'#$ 2B83#$ 1C'ity-1.0.xsd
wsu:Id = Timestamp- 3c7c79b4-2afa-4184-9d2c-8f5e721c8421> 2014-01-13T11:26:52Z2014-01-13T11:31:52Z'#0'
OTRRC.PTT'

'舰餁आ蘪虈'#$0DF7'܁ꀂƂりƂʆāัర'#$0806'蘪虈'#$0DF7'Ԃ'#5'ରआ蘪虈'#$0DF7'܁'#$3101'ƂぢƂɞā㠰 〰
'#$0B31'र̆ѕጆ匂ㅉ『،唃'#$0A04'ԓ佐呓ㅁ】؏唃'#$0B04#$0813'佐呓牁䅃Ђ䤾Eర'#$0806'蘪虈'#$0DF7'Ԃ'#5'രआ蘪虈'#$0DF7'āԁЀƂ堀묥䮡悕㈒古虺̐昇⠹꺶힊覬왧䮽㕺⢂꺇宬䝄'#$07B3'䲠'#$D868'㶙㌱㟜'#$DAF2'#$2B83#$1C'ity-1.0.xsd" wsu:Id="Timestamp-3c7c79b4-2afa-4184-9d2c-8f5e721c8421">2014-01-13T11:26:52Z2014-01-13T11:31:52Z'#0' OTRRC.PTT'

签名的XML中还有很多数据需要。
在C#中,这样解决了

and there is alot more data that need to be in signed XML. In C# this was solved like this

    AsymmetricAlgorithm rsa = signCertificate.PrivateKey;

    // Read provided document, find the signature element ...
    MemoryStream documentStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(document));

    XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = true;
    doc.Load(new XmlTextReader(documentStream));

    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("ds", dsigURI);
    XmlNode sig = doc.SelectSingleNode("//*[@Id='" + signatureID + "']", nsmgr);

    XmlNode after = sig.PreviousSibling;
    XmlNode parent = sig.ParentNode;

    SignedXml signedXml = new SignedXml(doc);
    parent.RemoveChild(sig);

    Reference r = new Reference();
    r.Uri = "";
    r.AddTransform(new XmlDsigEnvelopedSignatureTransform());
    signedXml.AddReference(r);

    X509Certificate cert1 = new X509Certificate(signCertificate.GetRawCertData());

    KeyInfo ki = new KeyInfo();
    ki.AddClause(new KeyInfoX509Data(cert1));
    signedXml.KeyInfo = ki;

    signedXml.Signature.Id = signatureID;

    signedXml.SigningKey = rsa;
    signedXml.ComputeSignature();

    XmlNode signature = doc.ImportNode(signedXml.GetXml(), true);
    parent.InsertAfter(signature, after);

    return doc.OuterXml;                

谢谢您的帮助!

推荐答案

看下面的代码:

SetLength(Result, cbSignedBlob);
system.Move(signature^, Pointer(Result)^, cbSignedBlob);

我只是猜测,但结果可能是 string 类型。这是UTF-16编码的字符串。但是,您仅复制了 cbSignedBlob 个字节,这仅占缓冲区的一半。我怀疑您有ANSI编码还是UTF-8编码的文本,但这很难分辨。

I'm just guessing, but Result is probably of type string. That's a UTF-16 encoded string. But you copy in just cbSignedBlob bytes, which fills only half of the buffer. I suspect that you have either ANSI or UTF-8 encoded text, but it is a little hard to tell.

如果文本是UTF-8编码的,那么这就是您做什么:

If the text is UTF-8 encoded, then this is what you do:

var
  utf8: UTF8String;
....
SetLength(utf8, cbSignedBlob);
system.Move(signature^, Pointer(utf8)^, cbSignedBlob);
Result := string(utf8);

如果文本是ANSI编码的,则可以这样做:

If the text is ANSI encoded then you would do this:

var
  ansi: AnsiString(1252); // or whatever the code page really is
....
SetLength(ansi, cbSignedBlob);
system.Move(signature^, Pointer(ansi)^, cbSignedBlob);
Result := string(ansi);

这里可能还有更多事情要做,但是考虑到问题中提出的详细信息,这个数目就足够了如我所见。

There's probably more going on here but given the amount of detail presented in the question, this is as much as I can see.

首先,我非常怀疑您没有进行错误检查。您调用这些API函数,但忽略它们的返回值。我打赌这些功能将失败,并且您的代码将继续执行。下一步是添加错误检查。

For a start I am very suspicious of your lack of error checking. You call these API functions but ignore their return values. I'll wager the functions fail and your code continues regardless. Next step is to add error checking.

这篇关于如何在Delphi中正确签名XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆