Files
SuperVPN/output/Libraries/BouncyCastle.Crypto/Org/BouncyCastle/Crypto/Engines/ElGamalEngine.cs
2025-10-09 09:57:24 +09:00

115 lines
3.3 KiB
C#

using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
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)
{
if (parameters is ParametersWithRandom)
{
ParametersWithRandom parametersWithRandom = (ParametersWithRandom)parameters;
key = (ElGamalKeyParameters)parametersWithRandom.Parameters;
random = parametersWithRandom.Random;
}
else
{
key = (ElGamalKeyParameters)parameters;
random = new SecureRandom();
}
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;
BigInteger bigInteger2 = bigInteger.ModPow(p.Subtract(BigInteger.One).Subtract(elGamalPrivateKeyParameters.X), p).Multiply(val).Mod(p);
array = bigInteger2.ToByteArrayUnsigned();
}
else
{
BigInteger bigInteger3 = new BigInteger(1, input, inOff, length);
if (bigInteger3.BitLength >= p.BitLength)
{
throw new DataLengthException("input too large for ElGamal cipher.\n");
}
ElGamalPublicKeyParameters elGamalPublicKeyParameters = (ElGamalPublicKeyParameters)key;
BigInteger value = p.Subtract(BigInteger.Two);
BigInteger bigInteger4;
do
{
bigInteger4 = new BigInteger(p.BitLength, random);
}
while (bigInteger4.SignValue == 0 || bigInteger4.CompareTo(value) > 0);
BigInteger g = key.Parameters.G;
BigInteger bigInteger5 = g.ModPow(bigInteger4, p);
BigInteger bigInteger6 = bigInteger3.Multiply(elGamalPublicKeyParameters.Y.ModPow(bigInteger4, p)).Mod(p);
array = new byte[GetOutputBlockSize()];
byte[] array2 = bigInteger5.ToByteArrayUnsigned();
byte[] array3 = bigInteger6.ToByteArrayUnsigned();
array2.CopyTo(array, array.Length / 2 - array2.Length);
array3.CopyTo(array, array.Length - array3.Length);
}
return array;
}
}