RsaDigestSigner
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.TeleTrust;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
using System;
using System.Collections.Generic;
namespace Org.BouncyCastle.Crypto.Signers
{
public class RsaDigestSigner : ISigner
{
private readonly IAsymmetricBlockCipher rsaEngine;
private readonly AlgorithmIdentifier m_digestAlgID;
private readonly IDigest digest;
private bool forSigning;
private static readonly IDictionary<string, DerObjectIdentifier> OidMap;
public virtual string AlgorithmName => digest.AlgorithmName + "withRSA";
static RsaDigestSigner()
{
OidMap = new Dictionary<string, DerObjectIdentifier>(StringComparer.OrdinalIgnoreCase);
OidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
OidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
OidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
OidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
OidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
OidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
OidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
OidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
OidMap["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
OidMap["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
OidMap["SHA3-224"] = NistObjectIdentifiers.IdSha3_224;
OidMap["SHA3-256"] = NistObjectIdentifiers.IdSha3_256;
OidMap["SHA3-384"] = NistObjectIdentifiers.IdSha3_384;
OidMap["SHA3-512"] = NistObjectIdentifiers.IdSha3_512;
OidMap["MD2"] = PkcsObjectIdentifiers.MD2;
OidMap["MD4"] = PkcsObjectIdentifiers.MD4;
OidMap["MD5"] = PkcsObjectIdentifiers.MD5;
}
public RsaDigestSigner(IDigest digest)
: this(digest, CollectionUtilities.GetValueOrNull(OidMap, digest.AlgorithmName))
{
}
public RsaDigestSigner(IDigest digest, DerObjectIdentifier digestOid)
: this(digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
{
}
public RsaDigestSigner(IDigest digest, AlgorithmIdentifier algId)
: this(new RsaCoreEngine(), digest, algId)
{
}
public RsaDigestSigner(IRsa rsa, IDigest digest, DerObjectIdentifier digestOid)
: this(rsa, digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
{
}
public RsaDigestSigner(IRsa rsa, IDigest digest, AlgorithmIdentifier algId)
: this(new RsaBlindedEngine(rsa), digest, algId)
{
}
public RsaDigestSigner(IAsymmetricBlockCipher rsaEngine, IDigest digest, AlgorithmIdentifier algId)
{
this.rsaEngine = new Pkcs1Encoding(rsaEngine);
this.digest = digest;
m_digestAlgID = algId;
}
public virtual void Init(bool forSigning, ICipherParameters parameters)
{
this.forSigning = forSigning;
AsymmetricKeyParameter asymmetricKeyParameter = (AsymmetricKeyParameter)ParameterUtilities.IgnoreRandom(parameters);
if (forSigning && !asymmetricKeyParameter.IsPrivate)
throw new InvalidKeyException("Signing requires private key.");
if (!forSigning && asymmetricKeyParameter.IsPrivate)
throw new InvalidKeyException("Verification requires public key.");
Reset();
rsaEngine.Init(forSigning, parameters);
}
public virtual void Update(byte input)
{
digest.Update(input);
}
public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
{
digest.BlockUpdate(input, inOff, inLen);
}
public virtual void BlockUpdate(ReadOnlySpan<byte> input)
{
digest.BlockUpdate(input);
}
public virtual int GetMaxSignatureSize()
{
return rsaEngine.GetOutputBlockSize();
}
public virtual byte[] GenerateSignature()
{
if (!forSigning)
throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
byte[] array = new byte[digest.GetDigestSize()];
digest.DoFinal(array, 0);
byte[] array2 = (m_digestAlgID != null) ? DerEncode(m_digestAlgID, array) : CheckDerEncoded(array);
return rsaEngine.ProcessBlock(array2, 0, array2.Length);
}
public virtual bool VerifySignature(byte[] signature)
{
if (forSigning)
throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
byte[] a;
try {
a = rsaEngine.ProcessBlock(signature, 0, signature.Length);
} catch (Exception) {
return false;
}
byte[] array = new byte[digest.GetDigestSize()];
digest.DoFinal(array, 0);
if (m_digestAlgID == null)
return Arrays.FixedTimeEquals(a, CheckDerEncoded(array));
if (Arrays.FixedTimeEquals(a, DerEncode(m_digestAlgID, array)))
return true;
if (TryGetAltAlgID(m_digestAlgID, out AlgorithmIdentifier altAlgID) && Arrays.FixedTimeEquals(a, DerEncode(altAlgID, array)))
return true;
return false;
}
public virtual void Reset()
{
digest.Reset();
}
private static byte[] CheckDerEncoded(byte[] hash)
{
DigestInfo.GetInstance(hash);
return hash;
}
private static byte[] DerEncode(AlgorithmIdentifier digestAlgID, byte[] hash)
{
return new DigestInfo(digestAlgID, DerOctetString.WithContents(hash)).GetEncoded("DER");
}
private static bool TryGetAltAlgID(AlgorithmIdentifier algID, out AlgorithmIdentifier altAlgID)
{
Asn1Encodable parameters = algID.Parameters;
if (parameters == null)
altAlgID = new AlgorithmIdentifier(algID.Algorithm, DerNull.Instance);
else {
if (!DerNull.Instance.Equals(parameters)) {
altAlgID = null;
return false;
}
altAlgID = new AlgorithmIdentifier(algID.Algorithm, null);
}
return true;
}
}
}