如何在C#中实现符合NACH标准的PKCS#7文本文件签名?
C#/.NET 实现 NACH 要求的 PKCS#7 文本文件签名
.NET 对 NACH 签名算法的支持情况
NACH指定的签名算法是SHA256withRSA的PKCS#7(CMS)签名,这是标准密码学算法,.NET平台(包括.NET Framework、.NET Core/.NET 5+)完全支持,可通过两种方式实现:
- .NET原生
System.Security.Cryptography.Pkcs命名空间:封装了PKCS#7签名的完整流程,无需额外依赖 - Bouncy Castle库:与Java实现逻辑高度一致,适合需要严格对齐Java代码细节的场景
对应Java步骤的C#实现
以下是与Java步骤一一对应的C#实现方案,包含两种实现方式:
方式1:.NET原生API实现
using System; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; public class NachSignatureGenerator { /// <summary> /// 生成符合NACH要求的PKCS#7签名 /// </summary> /// <param name="pfxPath">PFX密钥库文件路径</param> /// <param name="pfxPassword">PFX文件密码</param> /// <param name="inputFilePath">待签名的文本文件路径</param> /// <returns>签名Base64、证书Base64、原始文件Base64</returns> public static (string SignatureBase64, string CertificateBase64, string OriginalFileBase64) GenerateSignature(string pfxPath, string pfxPassword, string inputFilePath) { // 步骤1:加载PFX密钥库,提取证书和私钥 var cert = new X509Certificate2( pfxPath, pfxPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); var privateKey = cert.GetRSAPrivateKey(); // 步骤3:读取原始文件字节 byte[] originalFileBytes = File.ReadAllBytes(inputFilePath); // 步骤2、4-8:创建PKCS#7签名(原生API已封装摘要+签名流程) var contentInfo = new ContentInfo(originalFileBytes); var signedCms = new SignedCms(contentInfo, false); var signer = new CmsSigner(cert) { DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1") // SHA256的OID,对应SHA256WITHRSA }; signedCms.ComputeSignature(signer); byte[] signatureBytes = signedCms.Encode(); // 步骤9:Base64编码签名 string signatureBase64 = Convert.ToBase64String(signatureBytes); // 步骤10:Base64编码证书 string certBase64 = Convert.ToBase64String(cert.RawData); // 步骤11:Base64编码原始文件 string originalBase64 = Convert.ToBase64String(originalFileBytes); return (signatureBase64, certBase64, originalBase64); } }
方式2:Bouncy Castle实现(与Java逻辑完全对齐)
先安装Bouncy Castle的NuGet包:
dotnet add package BouncyCastle.NetCore
实现代码:
using System; using System.IO; using Org.BouncyCastle.Cms; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; public class NachBouncyCastleSignatureGenerator { /// <summary> /// 用Bouncy Castle生成符合NACH要求的PKCS#7签名 /// </summary> /// <param name="pfxPath">PFX密钥库文件路径</param> /// <param name="pfxPassword">PFX文件密码</param> /// <param name="inputFilePath">待签名的文本文件路径</param> /// <returns>签名Base64、证书Base64、原始文件Base64</returns> public static (string SignatureBase64, string CertificateBase64, string OriginalFileBase64) GenerateSignature(string pfxPath, string pfxPassword, string inputFilePath) { // 步骤1:加载PFX密钥库 var pkcs12Store = new Pkcs12Store( new FileStream(pfxPath, FileMode.Open, FileAccess.Read), pfxPassword.ToCharArray()); // 获取密钥别名 string alias = null; foreach (string al in pkcs12Store.Aliases) { if (pkcs12Store.IsKeyEntry(al)) { alias = al; break; } } var keyEntry = pkcs12Store.GetKey(alias); var privateKey = keyEntry.Key; X509CertificateEntry certEntry = pkcs12Store.GetCertificate(alias); X509Certificate cert = certEntry.Certificate; // 步骤3:读取原始文件字节 byte[] originalFileBytes = File.ReadAllBytes(inputFilePath); // 步骤4:创建CMSSignedDataGenerator(与Java代码一致) var generator = new CmsSignedDataGenerator(); generator.AddSigner( privateKey, cert, CmsSignedDataGenerator.DigestSha256); // 对应SHA256WITHRSA算法 // 生成PKCS#7签名 var content = new CmsProcessableByteArray(originalFileBytes); CmsSignedData signedData = generator.Generate(content, false); byte[] signatureBytes = signedData.GetEncoded(); // 步骤9:Base64编码签名 string signatureBase64 = Convert.ToBase64String(signatureBytes); // 步骤10:Base64编码证书 string certBase64 = Convert.ToBase64String(cert.GetEncoded()); // 步骤11:Base64编码原始文件 string originalBase64 = Convert.ToBase64String(originalFileBytes); return (signatureBase64, certBase64, originalBase64); } }
注意事项
- 加载PFX文件时,若遇到私钥访问权限问题,可调整
X509KeyStorageFlags参数(比如添加X509KeyStorageFlags.UserKeySet) - 两种实现方式生成的签名均符合NACH的PKCS#7要求,可根据项目依赖选择合适的方案
内容的提问来源于stack exchange,提问作者Ashid Das
相关产品推荐
相关产品推荐

