175 lines
4.7 KiB
C#
175 lines
4.7 KiB
C#
using System;
|
|
using System.Collections;
|
|
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.Crypto.Parameters;
|
|
using Org.BouncyCastle.Security;
|
|
using Org.BouncyCastle.Utilities;
|
|
|
|
namespace Org.BouncyCastle.Crypto.Signers;
|
|
|
|
public class RsaDigestSigner : ISigner
|
|
{
|
|
private readonly IAsymmetricBlockCipher rsaEngine;
|
|
|
|
private readonly AlgorithmIdentifier algId;
|
|
|
|
private readonly IDigest digest;
|
|
|
|
private bool forSigning;
|
|
|
|
private static readonly IDictionary oidMap;
|
|
|
|
public virtual string AlgorithmName => digest.AlgorithmName + "withRSA";
|
|
|
|
static RsaDigestSigner()
|
|
{
|
|
oidMap = Platform.CreateHashtable();
|
|
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["MD2"] = PkcsObjectIdentifiers.MD2;
|
|
oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
|
|
oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
|
|
}
|
|
|
|
public RsaDigestSigner(IDigest digest)
|
|
: this(digest, (DerObjectIdentifier)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;
|
|
this.algId = algId;
|
|
}
|
|
|
|
public virtual void Init(bool forSigning, ICipherParameters parameters)
|
|
{
|
|
this.forSigning = forSigning;
|
|
AsymmetricKeyParameter asymmetricKeyParameter = ((!(parameters is ParametersWithRandom)) ? ((AsymmetricKeyParameter)parameters) : ((AsymmetricKeyParameter)((ParametersWithRandom)parameters).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 length)
|
|
{
|
|
digest.BlockUpdate(input, inOff, length);
|
|
}
|
|
|
|
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 = DerEncode(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[] array = new byte[digest.GetDigestSize()];
|
|
digest.DoFinal(array, 0);
|
|
byte[] array2;
|
|
byte[] array3;
|
|
try
|
|
{
|
|
array2 = rsaEngine.ProcessBlock(signature, 0, signature.Length);
|
|
array3 = DerEncode(array);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
if (array2.Length == array3.Length)
|
|
{
|
|
return Arrays.ConstantTimeAreEqual(array2, array3);
|
|
}
|
|
if (array2.Length == array3.Length - 2)
|
|
{
|
|
int num = array2.Length - array.Length - 2;
|
|
int num2 = array3.Length - array.Length - 2;
|
|
byte[] array4;
|
|
(array4 = array3)[1] = (byte)(array4[1] - 2);
|
|
(array4 = array3)[3] = (byte)(array4[3] - 2);
|
|
int num3 = 0;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
num3 |= array2[num + i] ^ array3[num2 + i];
|
|
}
|
|
for (int j = 0; j < num; j++)
|
|
{
|
|
num3 |= array2[j] ^ array3[j];
|
|
}
|
|
return num3 == 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual void Reset()
|
|
{
|
|
digest.Reset();
|
|
}
|
|
|
|
private byte[] DerEncode(byte[] hash)
|
|
{
|
|
if (algId == null)
|
|
{
|
|
return hash;
|
|
}
|
|
DigestInfo digestInfo = new DigestInfo(algId, hash);
|
|
return digestInfo.GetDerEncoded();
|
|
}
|
|
}
|