问题
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
but all I get is:
'舰餁आ蘪虈'#$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'
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;
Thanks for help in advance!
回答1:
Look at this code:
SetLength(Result, cbSignedBlob);
system.Move(signature^, Pointer(Result)^, cbSignedBlob);
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.
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);
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.
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.
来源:https://stackoverflow.com/questions/21090208/how-to-properly-sign-xml-in-delphi