<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

IdeaEngine

public class IdeaEngine : IBlockCipher
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Engines { public class IdeaEngine : IBlockCipher { private const int Base = 65537; private const int BlockSize = 8; private const int Mask = 65535; private int[] m_workingKey; public virtual string AlgorithmName => "IDEA"; public virtual void Init(bool forEncryption, ICipherParameters parameters) { KeyParameter keyParameter = parameters as KeyParameter; if (keyParameter == null) throw new ArgumentException("invalid parameter passed to IDEA Init - " + Platform.GetTypeName(parameters)); m_workingKey = GenerateWorkingKey(forEncryption, keyParameter.GetKey()); } public virtual int GetBlockSize() { return 8; } public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { if (m_workingKey == null) throw new InvalidOperationException("IDEA engine not initialised"); Check.DataLength(input, inOff, 8, "input buffer too short"); Check.OutputLength(output, outOff, 8, "output buffer too short"); IdeaFunc(m_workingKey, input.AsSpan(inOff), output.AsSpan(outOff)); return 8; } public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output) { if (m_workingKey == null) throw new InvalidOperationException("IDEA engine not initialised"); Check.DataLength(input, 8, "input buffer too short"); Check.OutputLength(output, 8, "output buffer too short"); IdeaFunc(m_workingKey, input, output); return 8; } private int Mul(int x, int y) { if (x == 0) x = 65537 - y; else if (y == 0) { x = 65537 - x; } else { int num = x * y; y = (num & 65535); x = (int)((uint)num >> 16); x = y - x + ((y < x) ? 1 : 0); } return x & 65535; } private void IdeaFunc(int[] workingKey, ReadOnlySpan<byte> input, Span<byte> output) { int x = Pack.BE_To_UInt16(input); int num = Pack.BE_To_UInt16(input.Slice(2, input.Length - 2)); int num2 = Pack.BE_To_UInt16(input.Slice(4, input.Length - 4)); int x2 = Pack.BE_To_UInt16(input.Slice(6, input.Length - 6)); int num3 = 0; for (int i = 0; i < 8; i++) { x = Mul(x, workingKey[num3++]); num += workingKey[num3++]; num &= 65535; num2 += workingKey[num3++]; num2 &= 65535; x2 = Mul(x2, workingKey[num3++]); int num8 = num; int num9 = num2; num2 ^= x; num ^= x2; num2 = Mul(num2, workingKey[num3++]); num += num2; num &= 65535; num = Mul(num, workingKey[num3++]); num2 += num; num2 &= 65535; x ^= num; x2 ^= num2; num ^= num9; num2 ^= num8; } Pack.UInt16_To_BE((ushort)Mul(x, workingKey[num3++]), output); Pack.UInt16_To_BE((ushort)(num2 + workingKey[num3++]), output.Slice(2, output.Length - 2)); Pack.UInt16_To_BE((ushort)(num + workingKey[num3++]), output.Slice(4, output.Length - 4)); Pack.UInt16_To_BE((ushort)Mul(x2, workingKey[num3]), output.Slice(6, output.Length - 6)); } private static int[] ExpandKey(byte[] uKey) { int[] array = new int[52]; if (uKey.Length < 16) { byte[] array2 = new byte[16]; Array.Copy(uKey, 0, array2, array2.Length - uKey.Length, uKey.Length); uKey = array2; } for (int i = 0; i < 8; i++) { array[i] = Pack.BE_To_UInt16(uKey.AsSpan(i * 2)); } for (int j = 8; j < 52; j++) { if ((j & 7) < 6) array[j] = ((((array[j - 7] & 127) << 9) | (array[j - 6] >> 7)) & 65535); else if ((j & 7) == 6) { array[j] = ((((array[j - 7] & 127) << 9) | (array[j - 14] >> 7)) & 65535); } else { array[j] = ((((array[j - 15] & 127) << 9) | (array[j - 14] >> 7)) & 65535); } } return array; } private static int MulInv(int x) { if (x < 2) return x; int num = 1; int num2 = 65537 / x; int num3 = 65537 % x; while (num3 != 1) { int num4 = x / num3; x %= num3; num = ((num + num2 * num4) & 65535); if (x == 1) return num; num4 = num3 / x; num3 %= x; num2 = ((num2 + num * num4) & 65535); } return (1 - num2) & 65535; } private static int AddInv(int x) { return -x & 65535; } private static int[] InvertKey(int[] inKey) { int[] array = new int[52]; int num = 0; int num2 = 52; int num4 = MulInv(inKey[num++]); int num6 = AddInv(inKey[num++]); int num8 = AddInv(inKey[num++]); int num10 = MulInv(inKey[num++]); array[--num2] = num10; array[--num2] = num8; array[--num2] = num6; array[--num2] = num4; for (int i = 1; i < 8; i++) { num4 = inKey[num++]; num6 = inKey[num++]; array[--num2] = num6; array[--num2] = num4; num4 = MulInv(inKey[num++]); num6 = AddInv(inKey[num++]); num8 = AddInv(inKey[num++]); num10 = MulInv(inKey[num++]); array[--num2] = num10; array[--num2] = num6; array[--num2] = num8; array[--num2] = num4; } num4 = inKey[num++]; num6 = inKey[num++]; array[--num2] = num6; array[--num2] = num4; num4 = MulInv(inKey[num++]); num6 = AddInv(inKey[num++]); num8 = AddInv(inKey[num++]); num10 = MulInv(inKey[num]); array[--num2] = num10; array[--num2] = num8; array[--num2] = num6; array[--num2] = num4; return array; } private static int[] GenerateWorkingKey(bool forEncryption, byte[] userKey) { int[] array = ExpandKey(userKey); if (!forEncryption) return InvertKey(array); return array; } } }