It is an adaption of Java examples of bouncy castle to .NET and a demonstration of using ISignatureFactory instead of the AsymmetricKeyPair. See https://stackoverflow.com/questions/39338094/creating-an-external-2-steps-signature-with-bouncycastle-and-sunmscapi
public class CustomSigner : ISigner
{
private byte[] result;
private readonly X509Certificate2 _signCertificate;
public CustomSigner(X509Certificate2 signCertificate)
{
_signCertificate = signCertificate;
}
public string AlgorithmName
{
get
{
return PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id;
}
}
public void BlockUpdate(byte[] input, int inOff, int length)
{
using System.Security.Cryptography.RSA rsa = _signCertificate.GetRSAPrivateKey();
input = input.Take(length).ToArray();
result = rsa.SignData(input,
System.Security.Cryptography.HashAlgorithmName.SHA256,
System.Security.Cryptography.RSASignaturePadding.Pkcs1);
}
public byte[] GenerateSignature()
{
return result;
}
public void Init(bool forSigning, ICipherParameters parameters)
{
throw new System.NotImplementedException();
}
public void Reset()
{
throw new System.NotImplementedException();
}
public void Update(byte input)
{
throw new System.NotImplementedException();
}
public bool VerifySignature(byte[] signature)
{
throw new System.NotImplementedException();
}
}
public class CustomSignatureFactory : ISignatureFactory
{
private readonly AlgorithmIdentifier algID;
private readonly X509Certificate2 _signingCert;
public CustomSignatureFactory(X509Certificate2 signingCert)
{
algID = new AlgorithmIdentifier(PkcsObjectIdentifiers.Sha256WithRsaEncryption);
_signingCert = signingCert;
}
public object AlgorithmDetails
{
get { return algID; }
}
public IStreamCalculator CreateCalculator()
{
ISigner sig = new CustomSigner(_signingCert);
return new DefaultSigCalculator(sig);
}
}
internal class CustomCmsSigner
{
public static byte[] SignHash(byte[] hash, X509Certificate2 signingCert)
{
X509SubjectKeyIdentifierExtension skiExtension = signingCert.Extensions.OfType().FirstOrDefault();
bouncy.Org.BouncyCastle.X509.X509Certificate bCert = DotNetUtilities.FromX509Certificate(signingCert);
CmsSignedDataGenerator gen = new ();
Attribute attrHash = new(CmsAttributes.MessageDigest, new DerSet(new DerOctetString(hash)));
Attribute attrcontentType = new(CmsAttributes.ContentType, new DerSet(CmsObjectIdentifiers.Data));
Asn1EncodableVector v = new (attrcontentType, attrHash);
SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder()
.WithSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
SignerInfoGenerator signerInfoGenerator = signerInfoGeneratorBuilder.Build(
new CustomSignatureFactory(signingCert), bCert);
gen.AddSignerInfoGenerator(signerInfoGenerator);
using X509Chain x509Chain = X509Chain.Create();
x509Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
x509Chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreEndRevocationUnknown;
x509Chain.Build(signingCert);
var certList = x509Chain.ChainElements.Cast()
.Select(ce => DotNetUtilities.FromX509Certificate(ce.Certificate)).ToList();
var storeParams = new X509CollectionStoreParameters(certList);
var certStore = X509StoreFactory.Create("Certificate/Collection", storeParams);
gen.AddCertificates(certStore);
CmsSignedData s = gen.Generate(CmsSignedGenerator.Data, new CmsProcessableByteArray(new byte[0]), true);
byte[] encoded = s.GetEncoded();
/*CmsSignedData signedCmsData = new CmsSignedData(new CmsProcessableByteArray(new byte[] { 1, 2, 3 }), encoded);
SignerInformation signerInformation = signedCmsData.GetSignerInfos().GetSigners().OfType().FirstOrDefault();
bool verified = signerInformation.Verify(bCert);*/
return encoded;
}
}