如何在C#中使用SafeNet Token的私钥签名PDF哈希数据
根因分析
- 你当前代码的核心错误是尝试修改RSACng的导出策略并调用
ExportParameters(true)导出私钥明文,SafeNet这类智能卡的私钥是硬件级不可导出的,修改导出策略的操作对硬件保护的密钥完全无效,直接触发权限异常,这就是你看到“Key not valid for use in specified state”报错的直接原因。 - XML签名能正常工作的原因是
SignedXml直接使用原始的RSACng密钥实例调用系统CNG接口完成签名,全程不触碰私钥导出逻辑,签名运算直接在智能卡硬件内部执行,会正常触发密码输入弹窗。
修复方案
你完全不需要把私钥导出给BouncyCastle做签名,直接用系统原生的RSACng实例完成签名运算即可,修改后的签名逻辑如下:
public static byte[] Sign(X509Certificate2Collection selectedCert, byte[] hashByteArray) { X509Certificate2 cert = selectedCert[0]; // 转换证书链给PdfPKCS7用,这部分不需要修改 var bouncyCertChains = ConvertX509Cert2ListToBouncyCastleX509CertList(selectedCert); // 直接获取原生RSACng实例,不要做任何私钥导出操作 var rsaCng = cert.GetRSAPrivateKey() as RSACng; // 初始化PdfPKCS7,计算待签名的认证属性字节 PdfPKCS7 pdfpkcs7 = new PdfPKCS7(null, bouncyCertChains.ToArray(), DigestAlgorithms.SHA256, false); byte[] authenticatedAttrBytes = pdfpkcs7.GetAuthenticatedAttributeBytes(hashByteArray, PdfSigner.CryptoStandard.CMS, null, null); // 直接用原生RSACng做签名,运算在智能卡硬件内执行,会自动触发密码输入弹窗 byte[] signature = rsaCng.SignData(authenticatedAttrBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // 剩余PKCS7封装逻辑保持不变 pdfpkcs7.SetExternalDigest(signature, null, "RSA"); return pdfpkcs7.GetEncodedPKCS7(hashByteArray, null, null, null, PdfSigner.CryptoStandard.CMS); }
额外注意事项
- 加载证书时请确保
X509KeyStorageFlags参数配置正确,建议加上X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet,确保程序能正确关联到智能卡的密钥容器。 - 不要对智能卡的密钥调用任何修改属性、导出私钥的操作,所有签名运算都直接调用原生RSA实例的签名接口即可。
内容的提问来源于stack exchange,提问作者sharif2008
相关产品推荐
相关产品推荐

