<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.1" />

RsaCoreEngine

public class RsaCoreEngine : IRsa
This does your basic RSA algorithm.
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Engines { public class RsaCoreEngine : IRsa { private RsaKeyParameters m_key; private bool m_forEncryption; private int m_bitSize; public virtual void Init(bool forEncryption, ICipherParameters parameters) { ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; if (parametersWithRandom != null) parameters = parametersWithRandom.Parameters; RsaKeyParameters obj = parameters as RsaKeyParameters; if (obj == null) throw new InvalidKeyException("Not an RSA key"); m_key = obj; m_forEncryption = forEncryption; m_bitSize = m_key.Modulus.BitLength; } public virtual int GetInputBlockSize() { CheckInitialised(); if (m_forEncryption) return (m_bitSize - 1) / 8; return (m_bitSize + 7) / 8; } public virtual int GetOutputBlockSize() { CheckInitialised(); if (m_forEncryption) return (m_bitSize + 7) / 8; return (m_bitSize - 1) / 8; } public virtual BigInteger ConvertInput(byte[] inBuf, int inOff, int inLen) { CheckInitialised(); int num = (m_bitSize + 7) / 8; if (inLen > num) throw new DataLengthException("input too large for RSA cipher."); BigInteger bigInteger = new BigInteger(1, inBuf, inOff, inLen); if (bigInteger.CompareTo(m_key.Modulus) >= 0) throw new DataLengthException("input too large for RSA cipher."); return bigInteger; } public virtual byte[] ConvertOutput(BigInteger result) { CheckInitialised(); if (!m_forEncryption) return BigIntegers.AsUnsignedByteArray(result); return BigIntegers.AsUnsignedByteArray(GetOutputBlockSize(), result); } public virtual BigInteger ProcessBlock(BigInteger input) { CheckInitialised(); RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = m_key as RsaPrivateCrtKeyParameters; if (rsaPrivateCrtKeyParameters == null) return input.ModPow(m_key.Exponent, m_key.Modulus); BigInteger p = rsaPrivateCrtKeyParameters.P; BigInteger q = rsaPrivateCrtKeyParameters.Q; BigInteger dP = rsaPrivateCrtKeyParameters.DP; BigInteger dQ = rsaPrivateCrtKeyParameters.DQ; BigInteger qInv = rsaPrivateCrtKeyParameters.QInv; BigInteger bigInteger = input.Remainder(p).ModPow(dP, p); BigInteger bigInteger2 = input.Remainder(q).ModPow(dQ, q); BigInteger bigInteger3 = bigInteger.Subtract(bigInteger2).Multiply(qInv).Mod(p) .Multiply(q) .Add(bigInteger2); if (!bigInteger3.ModPow(rsaPrivateCrtKeyParameters.PublicExponent, rsaPrivateCrtKeyParameters.Modulus).Equals(input)) throw new InvalidOperationException("RSA engine faulty decryption/signing detected"); return bigInteger3; } private void CheckInitialised() { if (m_key == null) throw new InvalidOperationException("RSA engine not initialised"); } } }