You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET 9与BouncyCastle 2.6.0中实现签名预哈希(PreHash)

实现BouncyCastle推荐的RSA签名预哈希方案(适配.NET 9 + BouncyCastle 2.6.0)

原OpenSSL签名命令

openssl rsautl -sign -in rasi.bin -inkey riktest.key -out allkiri.bin

原基于BouncyCastle的C#实现

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
                        
public class Program
{
    public static void Main()
    {
        // 测试用512位密钥,实际生产必须使用>=2048位密钥保障安全!
        string privatePkcs1Pem = @"-----BEGIN RSA PRIVATE KEY-----
                            MIIBOwIBAAJBANoHbFSEZoOSB9Kxt7t8PoBwmauaODjECHqJgtTU3h4MW5K3857+
                            04Flc6x6a9xxyvCKS5RtOP2gaOlOVtrph0ECAwEAAQJBALu8LpRr2RWrdV7/tfQT
                            HIJd8oQnbAe9DIvuwh/fF08IwApOE/iGL+Ded49eoHHu1OXycZhpHavN/sQMnssP
                            FNECIQDyDIW7V5UUu16ZAeupeQ7zdV6ykVngd0bb3FEn99EchQIhAOaYe3ll211q
                            SIXVjKHudMn3xe6Vvguc9O7cwCB+gyqNAiEAsr3kk6/de23SMZNlf8TR8Z8eyybj
                            BAuQ3BMaKzWpyjECIFMR0UFNYTYIyLF12aCoH2h2mtY1GW5jj5TQ72GFUcktAiAf
                            WWXnts7m8kZWuKjfD0MQiW+w4iAph+51j+wiL3EMAQ==
                            -----END RSA PRIVATE KEY-----";
        byte[] dataToSign = SHA256.HashData(Encoding.UTF8.GetBytes("Data to sign"));
    
        // 导入PKCS#1格式PEM私钥
        PemReader pemReader = new PemReader(new StringReader(privatePkcs1Pem));
        AsymmetricKeyParameter privateKeyParameter = ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;
    
        // 签名原始数据
        ISigner signer = new GenericSigner(new Pkcs1Encoding(new RsaBlindedEngine()), new NullDigest());
        signer.Init(true, privateKeyParameter);
        signer.BlockUpdate(dataToSign, 0, dataToSign.Length);
        byte[] signature = signer.GenerateSignature();
    
        Console.WriteLine(Convert.ToHexString(signature));
    }
}

BouncyCastle开发者的预哈希方案建议

将NullDigest替换为PreHash.For(new Sha256Digest())会更实用。

当然,也可以直接把哈希操作整合到签名流程里——只需要把NullDigest替换成Sha256Digest即可。

适配.NET 9 + BouncyCastle 2.6.0的实现方案

方案一:直接整合哈希与签名流程

当前版本不支持PreHash.For(),但开发者提到的第二种方案可直接使用:将NullDigest替换为Sha256Digest,签名器会自动完成数据哈希→PKCS#1填充→RSA签名的完整流程,无需提前手动计算哈希:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using System;
using System.Text;
using System.IO;
                        
public class Program
{
    public static void Main()
    {
        // 测试用512位密钥,实际生产必须使用>=2048位密钥保障安全!
        string privatePkcs1Pem = @"-----BEGIN RSA PRIVATE KEY-----
                            MIIBOwIBAAJBANoHbFSEZoOSB9Kxt7t8PoBwmauaODjECHqJgtTU3h4MW5K3857+
                            04Flc6x6a9xxyvCKS5RtOP2gaOlOVtrph0ECAwEAAQJBALu8LpRr2RWrdV7/tfQT
                            HIJd8oQnbAe9DIvuwh/fF08IwApOE/iGL+Ded49eoHHu1OXycZhpHavN/sQMnssP
                            FNECIQDyDIW7V5UUu16ZAeupeQ7zdV6ykVngd0bb3FEn99EchQIhAOaYe3ll211q
                            SIXVjKHudMn3xe6Vvguc9O7cwCB+gyqNAiEAsr3kk6/de23SMZNlf8TR8Z8eyybj
                            BAuQ3BMaKzWpyjECIFMR0UFNYTYIyLF12aCoH2h2mtY1GW5jj5TQ72GFUcktAiAf
                            WWXnts7m8kZWuKjfD0MQiW+w4iAph+51j+wiL3EMAQ==
                            -----END RSA PRIVATE KEY-----";
        // 直接传入原始数据,无需提前计算哈希
        byte[] rawData = Encoding.UTF8.GetBytes("Data to sign");
    
        // 导入PKCS#1格式PEM私钥
        PemReader pemReader = new PemReader(new StringReader(privatePkcs1Pem));
        AsymmetricKeyParameter privateKeyParameter = ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;
    
        // 使用Sha256Digest替代NullDigest,签名器自动完成哈希+签名
        ISigner signer = new GenericSigner(new Pkcs1Encoding(new RsaBlindedEngine()), new Sha256Digest());
        signer.Init(true, privateKeyParameter);
        signer.BlockUpdate(rawData, 0, rawData.Length);
        byte[] signature = signer.GenerateSignature();
    
        Console.WriteLine(Convert.ToHexString(signature));
    }
}

方案二:模拟PreHash预哈希逻辑(针对已提前计算哈希的场景)

如果必须提前计算哈希值,再进行签名,可以手动构造符合PKCS#1 v1.5标准的哈希摘要ASN.1结构,再传入签名器完成填充与签名,以此模拟PreHash.For()的效果:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
                        
public class Program
{
    public static void Main()
    {
        // 测试用512位密钥,实际生产必须使用>=2048位密钥保障安全!
        string privatePkcs1Pem = @"-----BEGIN RSA PRIVATE KEY-----
                            MIIBOwIBAAJBANoHbFSEZoOSB9Kxt7t8PoBwmauaODjECHqJgtTU3h4MW5K3857+
                            04Flc6x6a9xxyvCKS5RtOP2gaOlOVtrph0ECAwEAAQJBALu8LpRr2RWrdV7/tfQT
                            HIJd8oQnbAe9DIvuwh/fF08IwApOE/iGL+Ded49eoHHu1OXycZhpHavN/sQMnssP
                            FNECIQDyDIW7V5UUu16ZAeupeQ7zdV6ykVngd0bb3FEn99EchQIhAOaYe3ll211q
                            SIXVjKHudMn3xe6Vvguc9O7cwCB+gyqNAiEAsr3kk6/de23SMZNlf8TR8Z8eyybj
                            BAuQ3BMaKzWpyjECIFMR0UFNYTYIyLF12aCoH2h2mtY1GW5jj5TQ72GFUcktAiAf
                            WWXnts7m8kZWuKjfD0MQiW+w4iAph+51j+wiL3EMAQ==
                            -----END RSA PRIVATE KEY-----";
        // 提前计算SHA256哈希
        byte[] dataHash = SHA256.HashData(Encoding.UTF8.GetBytes("Data to sign"));
    
        // 导入PKCS#1格式PEM私钥
        PemReader pemReader = new PemReader(new StringReader(privatePkcs1Pem));
        AsymmetricKeyParameter privateKeyParameter = ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;
    
        // 构造PKCS#1 v1.5要求的哈希摘要ASN.1结构
        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(X509ObjectIdentifiers.IdSha256);
        DigestInfo digestInfo = new DigestInfo(sha256AlgId, dataHash);
        byte[] encodedDigest = digestInfo.GetDerEncoded();
    
        // 使用NullDigest签名编码后的摘要结构,模拟PreHash的效果
        ISigner signer = new GenericSigner(new Pkcs1Encoding(new RsaBlindedEngine()), new NullDigest());
        signer.Init(true, privateKeyParameter);
        signer.BlockUpdate(encodedDigest, 0, encodedDigest.Length);
        byte[] signature = signer.GenerateSignature();
    
        Console.WriteLine(Convert.ToHexString(signature));
    }
}

内容的提问来源于stack exchange,提问作者Andrus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:44:57