我正在尝试使用证书在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;
提前感谢您的帮助!
答案 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函数但忽略它们的返回值。我打赌功能失败,你的代码无论如何都会继续。下一步是添加错误检查。