我正在尝试将以下代码(使用.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的RsaDigestSigner
,CmsSignedData
,CmsSignedDataParser
和SignerUtilities.GetSigner("SHA-256withRSA")
(它们只返回RsaDigestSigner
),但似乎都没有既可以理解p7s文件,又可以实际验证它是否适用于指定的数据。
答案 0 :(得分:1)
因此,考虑到您尚未提供有关如何生成分离签名的示例,我不得不作一些假设。
下面的代码在.net Core 3.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
}
}
}
}
}