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

IesEngine

public class IesEngine
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Engines { public class IesEngine { private readonly IBasicAgreement agree; private readonly IDerivationFunction kdf; private readonly IMac mac; private readonly BufferedBlockCipher cipher; private readonly byte[] macBuf; private bool forEncryption; private ICipherParameters privParam; private ICipherParameters pubParam; private IesParameters param; public IesEngine(IBasicAgreement agree, IDerivationFunction kdf, IMac mac) { this.agree = agree; this.kdf = kdf; this.mac = mac; macBuf = new byte[mac.GetMacSize()]; } public IesEngine(IBasicAgreement agree, IDerivationFunction kdf, IMac mac, BufferedBlockCipher cipher) { this.agree = agree; this.kdf = kdf; this.mac = mac; macBuf = new byte[mac.GetMacSize()]; this.cipher = cipher; } public virtual void Init(bool forEncryption, ICipherParameters privParameters, ICipherParameters pubParameters, ICipherParameters iesParameters) { this.forEncryption = forEncryption; privParam = privParameters; pubParam = pubParameters; param = (IesParameters)iesParameters; } private byte[] DecryptBlock(byte[] in_enc, int inOff, int inLen, byte[] z) { byte[] array = null; KeyParameter keyParameter = null; KdfParameters kdfParameters = new KdfParameters(z, param.GetDerivationV()); int macKeySize = param.MacKeySize; kdf.Init(kdfParameters); if (inLen < mac.GetMacSize()) throw new InvalidCipherTextException("Length of input must be greater than the MAC"); inLen -= mac.GetMacSize(); if (cipher == null) { byte[] array2 = GenerateKdfBytes(kdfParameters, inLen + macKeySize / 8); array = new byte[inLen]; for (int i = 0; i != inLen; i++) { array[i] = (byte)(in_enc[inOff + i] ^ array2[i]); } keyParameter = new KeyParameter(array2, inLen, macKeySize / 8); } else { int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize; byte[] key = GenerateKdfBytes(kdfParameters, cipherKeySize / 8 + macKeySize / 8); cipher.Init(false, new KeyParameter(key, 0, cipherKeySize / 8)); array = cipher.DoFinal(in_enc, inOff, inLen); keyParameter = new KeyParameter(key, cipherKeySize / 8, macKeySize / 8); } byte[] encodingV = param.GetEncodingV(); mac.Init(keyParameter); mac.BlockUpdate(in_enc, inOff, inLen); mac.BlockUpdate(encodingV, 0, encodingV.Length); mac.DoFinal(macBuf, 0); inOff += inLen; if (!Arrays.FixedTimeEquals(Arrays.CopyOfRange(in_enc, inOff, inOff + macBuf.Length), macBuf)) throw new InvalidCipherTextException("Invalid MAC."); return array; } private byte[] EncryptBlock(byte[] input, int inOff, int inLen, byte[] z) { byte[] array = null; KeyParameter keyParameter = null; KdfParameters kParam = new KdfParameters(z, param.GetDerivationV()); int num = 0; int macKeySize = param.MacKeySize; if (cipher == null) { byte[] array2 = GenerateKdfBytes(kParam, inLen + macKeySize / 8); array = new byte[inLen + mac.GetMacSize()]; num = inLen; for (int i = 0; i != inLen; i++) { array[i] = (byte)(input[inOff + i] ^ array2[i]); } keyParameter = new KeyParameter(array2, inLen, macKeySize / 8); } else { int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize; byte[] key = GenerateKdfBytes(kParam, cipherKeySize / 8 + macKeySize / 8); cipher.Init(true, new KeyParameter(key, 0, cipherKeySize / 8)); num = cipher.GetOutputSize(inLen); byte[] array3 = new byte[num]; int num2 = cipher.ProcessBytes(input, inOff, inLen, array3, 0); num2 += cipher.DoFinal(array3, num2); array = new byte[num2 + mac.GetMacSize()]; num = num2; Array.Copy(array3, 0, array, 0, num2); keyParameter = new KeyParameter(key, cipherKeySize / 8, macKeySize / 8); } byte[] encodingV = param.GetEncodingV(); mac.Init(keyParameter); mac.BlockUpdate(array, 0, num); mac.BlockUpdate(encodingV, 0, encodingV.Length); mac.DoFinal(array, num); return array; } private byte[] GenerateKdfBytes(KdfParameters kParam, int length) { byte[] array = new byte[length]; kdf.Init(kParam); kdf.GenerateBytes(array, 0, array.Length); return array; } public virtual byte[] ProcessBlock(byte[] input, int inOff, int inLen) { agree.Init(privParam); BigInteger n = agree.CalculateAgreement(pubParam); byte[] array = BigIntegers.AsUnsignedByteArray(agree.GetFieldSize(), n); try { return forEncryption ? EncryptBlock(input, inOff, inLen, array) : DecryptBlock(input, inOff, inLen, array); } finally { Array.Clear(array, 0, array.Length); } } } }