如何在Delphi中正确签名XML

时间:2014-01-13 11:31:08

标签: xml delphi certificate delphi-2010 xml-signature

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

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' ƂぢƂɞā㠰   〰
  '#$ 0B31' र̆ѕጆ匂ㅉ『,唃 '#$0A04'ԓ佐呓ㅁ】؏唃' #$ 0B04#$ 0813 '佐呓牁䅃Ђ䤾èర' #$ 0806 '蘪虈' #$0DF7'Ԃ” #5'രआ蘪虈 '#$0DF7'āԁЀƂ堀묥䮡悕㈒古虺̐升⠹꺶힊觊왧䮽㕺⢂꺇宬䝄' #$ 07B3 '䲠' #$ D868 '㶙㌱㟜' #$ DAF2' #$ 2B83#$ 1C'ity-1.0.xsd”   WSU:编号= “时间戳的3c7c79b4-2afa-4184-9d2c-8f5e721c8421” > 2014-01-13T11:26:52Z2014-01-13T11:31:52Z '#0'   OTRRC.PTT'

并且需要在签名XML中有更多数据。 在C#中,这就像这样解决了

    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;                

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

看看这段代码:

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

我只是猜测,但Result可能属于string类型。那是一个UTF-16编码的字符串。但是你只复制cbSignedBlob个字节,它只填充缓冲区的一半。我怀疑你有ANSI或UTF-8编码文本,但有点难以辨别。

如果文本是UTF-8编码的,那就是你要做的:

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

如果文本是ANSI编码的,那么你会这样做:

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

这里可能会有更多内容,但考虑到问题中提供的详细信息量,这是我能看到的。

首先,我非常怀疑你没有错误检查。您调用这些API函数但忽略它们的返回值。我打赌功能失败,你的代码无论如何都会继续。下一步是添加错误检查。