我真的需要帮助,请。
我在 Stackoverflow 上检查了其他类似的问题,但它不适用于我的情况。
情况:我正在开发一个应用程序,需要使用 USB 令牌对 PDF 文档进行签名。
生成的pdf带有数字签名,但验证失败。
我按照以下步骤操作:
X509Store st = new X509Store(StoreName.My, StoreLocation.LocalMachine);
st.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certSelected = st.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
st.Close();
var cert = certSelected[0];
using var reader = new PdfReader(pdfPathSelected);
{
using (var outputStream = new MemoryStream())
{
var signer = new PdfSigner(reader, outputStream, new StampingProperties());
var appearance = new SignatureFieldAppearance(string.Empty);
var signerName = _x509CertificateService.GetSignerName(chain[0]);
var appearanceText = new SignedAppearanceText();
appearanceText.SetSignedBy(signerName)
.SetReasonLine("Reason: Assinatura Digital.")
.SetLocationLine("Location: Sistema Doc Digital.")
.SetSignDate(signer.GetSignDate())
.GenerateDescriptionText();
var fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Images", "tcpdf_signature.png");
var img = ImageDataFactory.Create(fileName);
appearance.SetContent(appearanceText, img);
signer.SetSignatureAppearance(appearance);
signer.SetPageNumber(signer.GetDocument().GetNumberOfPages());
signer.SetPageRect(signaturesCount > 0 ? new Rectangle(50, 50, 450, 30) : new Rectangle(50, 5, 450, 30));
var contentInfo = new ContentInfo(File.ReadAllBytes(pdfPathSelected));
var signedCms = new SignedCms(contentInfo, true);
var rsaCng = cert.GetRSAPrivateKey() as RSACng;
var cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert, rsaCng)
{
DigestAlgorithm = new Oid("SHA256"), // SHA256
IncludeOption = X509IncludeOption.EndCertOnly
};
signedCms.ComputeSignature(cmsSigner, false);
var externalSignature = new CmsSignatureContainer(signedCms);
signer.SignExternalContainer(externalSignature, 8192);
File.WriteAllBytes(destPdfSigned, outputStream.ToArray());
}
}
CmsSignatureContainer 类:
public class CmsSignatureContainer : IExternalSignatureContainer
{
private readonly SignedCms signedCms;
public CmsSignatureContainer(SignedCms signedCms)
{
this.signedCms = signedCms;
}
public byte[] Sign(Stream data)
{
// You may need to adjust the format depending on the specific requirements of your PDF signature
return signedCms.Encode();
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite);
signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
}
}
我成功解决了问题,签名实现不正确,外部签名容器的使用也不正确。 正确的做法是创建一个继承自 IExternalSignature 的类,并在 Sign 方法的实现中创建一个 SHA256 哈希器,计算哈希值并在 RSA 验证密钥上生成签名哈希值。 谢谢!