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

ElGamalEngine

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 ElGamalEngine : IAsymmetricBlockCipher { private ElGamalKeyParameters key; private SecureRandom random; private bool forEncryption; private int bitSize; public virtual string AlgorithmName => "ElGamal"; public virtual void Init(bool forEncryption, ICipherParameters parameters) { ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; if (parametersWithRandom != null) { key = (ElGamalKeyParameters)parametersWithRandom.Parameters; random = parametersWithRandom.Random; } else { key = (ElGamalKeyParameters)parameters; random = (forEncryption ? CryptoServicesRegistrar.GetSecureRandom() : null); } this.forEncryption = forEncryption; bitSize = key.Parameters.P.BitLength; if (forEncryption) { if (!(key is ElGamalPublicKeyParameters)) throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption."); } else if (!(key is ElGamalPrivateKeyParameters)) { throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption."); } } public virtual int GetInputBlockSize() { if (forEncryption) return (bitSize - 1) / 8; return 2 * ((bitSize + 7) / 8); } public virtual int GetOutputBlockSize() { if (forEncryption) return 2 * ((bitSize + 7) / 8); return (bitSize - 1) / 8; } public virtual byte[] ProcessBlock(byte[] input, int inOff, int length) { if (key == null) throw new InvalidOperationException("ElGamal engine not initialised"); int num = forEncryption ? ((bitSize - 1 + 7) / 8) : GetInputBlockSize(); if (length > num) throw new DataLengthException("input too large for ElGamal cipher.\n"); BigInteger p = key.Parameters.P; byte[] array; if (key is ElGamalPrivateKeyParameters) { int num2 = length / 2; BigInteger bigInteger = new BigInteger(1, input, inOff, num2); BigInteger val = new BigInteger(1, input, inOff + num2, num2); ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)key; array = bigInteger.ModPow(p.Subtract(BigInteger.One).Subtract(elGamalPrivateKeyParameters.X), p).Multiply(val).Mod(p) .ToByteArrayUnsigned(); } else { BigInteger bigInteger2 = new BigInteger(1, input, inOff, length); if (bigInteger2.BitLength >= p.BitLength) throw new DataLengthException("input too large for ElGamal cipher.\n"); ElGamalPublicKeyParameters elGamalPublicKeyParameters = (ElGamalPublicKeyParameters)key; BigInteger other = p.Subtract(BigInteger.Two); BigInteger bigInteger3; do { bigInteger3 = new BigInteger(p.BitLength, random); } while (bigInteger3.SignValue == 0 || bigInteger3.CompareTo(other) > 0); BigInteger n = key.Parameters.G.ModPow(bigInteger3, p); BigInteger n2 = bigInteger2.Multiply(elGamalPublicKeyParameters.Y.ModPow(bigInteger3, p)).Mod(p); array = new byte[GetOutputBlockSize()]; int num3 = array.Length / 2; BigIntegers.AsUnsignedByteArray(n, array, 0, num3); BigIntegers.AsUnsignedByteArray(n2, array, num3, array.Length - num3); } return array; } } }