C# 将.NET分离签名验证转换为bouncycastle

C# 将.NET分离签名验证转换为bouncycastle,c#,hash,bouncycastle,C#,Hash,Bouncycastle,我正在尝试将以下代码(使用.NET内置的加密库)转换为BouncyCastle。不幸的是,由于缺乏文档、对所有Java BC问题的混淆以及使用分离签名的不寻常,我不知道如何做到这一点 .NET代码: 1) 我需要转换的代码: var data = Encoding.ASCII.GetBytes("Hi!"); var signature = File.ReadAllText("Signature.p7s"); byte[] hashedDocument = HashAlgorithm.Creat

我正在尝试将以下代码(使用.NET内置的加密库)转换为BouncyCastle。不幸的是,由于缺乏文档、对所有Java BC问题的混淆以及使用分离签名的不寻常,我不知道如何做到这一点

.NET代码:

1) 我需要转换的代码:

var data = Encoding.ASCII.GetBytes("Hi!");
var signature = File.ReadAllText("Signature.p7s");
byte[] hashedDocument = HashAlgorithm.Create("SHA256").ComputeHash(data);
var cms = new SignedCms(new ContentInfo(hashedDocument), true);
cms.Decode(Convert.FromBase64String(signature));
cms.CheckSignature(true);
2) 生成p7s的代码:

var data = File.ReadAllBytes(fileToSign);
var hash = SHA256.Create().ComputeHash(data);
ContentInfo ci = new ContentInfo(hash);
SignedCms cms = new SignedCms(ci, true);
CmsSigner signer = new CmsSigner(new X509Certificate2(cert, pw));
signer.IncludeOption = X509IncludeOption.WholeChain;
signer.DigestAlgorithm = new Oid("sha256RSA");
signer.SignedAttributes.Add(new Pkcs9DocumentName(cert.SubjectName.Name));
signer.SignedAttributes.Add(new Pkcs9SigningTime());
cms.ComputeSignature(signer);
var enc = Convert.ToBase64String(cms.Encode());
File.WriteAllText(sigFile, enc);

我尝试过BouncyCastle的
rsa DigestSigner
cmssignedata
cmssignedataparser
,以及
SignerUtilities.GetSigner(“SHA-256withRSA”)
(它只返回
rsa DigestSigner
),但他们似乎都没有办法理解p7s文件,也没有办法实际验证它是否适用于指定的数据

因此,考虑到您没有提供如何生成分离签名的示例,我不得不做出一些假设

下面的代码是在.NETCore3.0中运行的

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;

namespace Whatever
{
    class Program
    {
        static string cert = "MIIJmQIBA.... // This here is base64 encoded PFX for the purposes of the demo ONLY";
        static string pwd = "password";

        static void Main(string[] args)
        {
            var data = Encoding.ASCII.GetBytes("Hi!");

            var hash = HashAlgorithm.Create("SHA256").ComputeHash(data);

            var certificate = new X509Certificate2(Convert.FromBase64String(cert), pwd);

            // So since I've no idea how you got p7s, i improvised here:
            var cms = new SignedCms(new ContentInfo(hash), true); // true -> Detached
            var signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, certificate);
            cms.ComputeSignature(signer);
            var data2 = cms.Encode();

            // assuming this was in p7s file
            var xx = Convert.ToBase64String(data2);

            // this passes, this is the .Net validation from OP
            var cms2 = new SignedCms(new ContentInfo(hash), true);
            cms2.Decode(Convert.FromBase64String(xx));
            cms2.CheckSignature(true);

            // Same in bouncy castle:
            BCUtil.Validate(certificate, hash, xx);
        }
    }
}
这是我们的
BCUtil
类:

using System;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using System.IO;
using System.Linq;

namespace Whatever
{
    public class BCUtil
    {
        public static void Validate(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, byte[] hash, string whatToValidate)
        {
            // My understanding is that you always need a cert to validate a signature with BC, but you only need a PUBLIC key
            var certificate = DotNetUtilities.FromX509Certificate(cert);

            // hash here
            var processable = new CmsProcessableByteArray(hash);
            // and signature here, for full .Net convert to old using() {} syntax
            using var str = new MemoryStream(Convert.FromBase64String(whatToValidate));
            var cms = new CmsSignedData(processable, str);
            var signers = cms.GetSignerInfos();
            var signersCollection = signers.GetSigners();

            foreach(var signer in signersCollection.Cast<SignerInformation>())
            {
                if (signer.Verify(certificate.GetPublicKey()))
                {
                    Console.WriteLine("yes banana"); // pass
                }
                else
                {
                    throw new Exception("no banana"); // fail
                }
            }
        }
    }
}
使用系统;
使用Org.BouncyCastle.Cms;
使用Org.BouncyCastle.X509;
使用Org.BouncyCastle.Security;
使用System.IO;
使用System.Linq;
名称空间
{
公共类BCUtil
{
公共静态无效验证(System.Security.Cryptography.X509Certificates.X509Certificate2证书,字节[]散列,字符串whatToValidate)
{
//我的理解是,您总是需要一个证书来验证BC的签名,但您只需要一个公钥
var certificate=DotNetUtilities.FromX509Certificate(cert);
//散列在这里
var processable=新的CmsProcessableByteArray(哈希);
//和签名,用于使用(){}语法将整个.Net转换为旧版本
使用var str=newmemoryStream(Convert.FromBase64String(whatToValidate));
var cms=新的CmsSignedData(可处理,str);
var signers=cms.GetSignerInfos();
var signersCollection=signers.GetSigners();
foreach(signersCollection.Cast()中的var signer)
{
if(signer.Verify(certificate.GetPublicKey()))
{
Console.WriteLine(“是香蕉”);//通过
}
其他的
{
抛出新异常(“无香蕉”);//失败
}
}
}
}
}

如果是这样的话,我也会接受“您没有正确存储它,如果您将其更改为…”的回答。因此。。您是否有
NET code:signature是一个分离的SHA256 RSA签名,存储在p7s文件中的Base64编码
或创建一个签名的代码?@zaitsman-我已经将生成我的p7s的代码添加到子孙后代的问题中,但您下面的回答给出了我所需要的。谢谢