IdeaEngine
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class IdeaEngine : IBlockCipher
{
private const int BLOCK_SIZE = 8;
private int[] workingKey;
private static readonly int MASK = 65535;
private static readonly int BASE = 65537;
public virtual string AlgorithmName => "IDEA";
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
throw new ArgumentException("invalid parameter passed to IDEA init - " + Platform.GetTypeName(parameters));
workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
}
public virtual int GetBlockSize()
{
return 8;
}
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (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(workingKey, input, inOff, output, outOff);
return 8;
}
private int BytesToWord(byte[] input, int inOff)
{
return ((input[inOff] << 8) & 65280) + (input[inOff + 1] & 255);
}
private void WordToBytes(int word, byte[] outBytes, int outOff)
{
outBytes[outOff] = (byte)((uint)word >> 8);
outBytes[outOff + 1] = (byte)word;
}
private int Mul(int x, int y)
{
if (x == 0)
x = BASE - y;
else if (y == 0) {
x = BASE - x;
} else {
int num = x * y;
y = (num & MASK);
x = (int)((uint)num >> 16);
x = y - x + ((y < x) ? 1 : 0);
}
return x & MASK;
}
private void IdeaFunc(int[] workingKey, byte[] input, int inOff, byte[] outBytes, int outOff)
{
int x = BytesToWord(input, inOff);
int num = BytesToWord(input, inOff + 2);
int num2 = BytesToWord(input, inOff + 4);
int x2 = BytesToWord(input, inOff + 6);
int num3 = 0;
for (int i = 0; i < 8; i++) {
x = Mul(x, workingKey[num3++]);
num += workingKey[num3++];
num &= MASK;
num2 += workingKey[num3++];
num2 &= MASK;
x2 = Mul(x2, workingKey[num3++]);
int num8 = num;
int num9 = num2;
num2 ^= x;
num ^= x2;
num2 = Mul(num2, workingKey[num3++]);
num += num2;
num &= MASK;
num = Mul(num, workingKey[num3++]);
num2 += num;
num2 &= MASK;
x ^= num;
x2 ^= num2;
num ^= num9;
num2 ^= num8;
}
WordToBytes(Mul(x, workingKey[num3++]), outBytes, outOff);
WordToBytes(num2 + workingKey[num3++], outBytes, outOff + 2);
WordToBytes(num + workingKey[num3++], outBytes, outOff + 4);
WordToBytes(Mul(x2, workingKey[num3]), outBytes, outOff + 6);
}
private 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] = BytesToWord(uKey, i * 2);
}
for (int j = 8; j < 52; j++) {
if ((j & 7) < 6)
array[j] = ((((array[j - 7] & 127) << 9) | (array[j - 6] >> 7)) & MASK);
else if ((j & 7) == 6) {
array[j] = ((((array[j - 7] & 127) << 9) | (array[j - 14] >> 7)) & MASK);
} else {
array[j] = ((((array[j - 15] & 127) << 9) | (array[j - 14] >> 7)) & MASK);
}
}
return array;
}
private int MulInv(int x)
{
if (x < 2)
return x;
int num = 1;
int num2 = BASE / x;
int num3 = BASE % x;
while (num3 != 1) {
int num4 = x / num3;
x %= num3;
num = ((num + num2 * num4) & MASK);
if (x == 1)
return num;
num4 = num3 / x;
num3 %= x;
num2 = ((num2 + num * num4) & MASK);
}
return (1 - num2) & MASK;
}
private int AddInv(int x)
{
return -x & MASK;
}
private int[] InvertKey(int[] inKey)
{
int num = 52;
int[] array = new int[52];
int num2 = 0;
int num4 = MulInv(inKey[num2++]);
int num6 = AddInv(inKey[num2++]);
int num8 = AddInv(inKey[num2++]);
int num10 = MulInv(inKey[num2++]);
array[--num] = num10;
array[--num] = num8;
array[--num] = num6;
array[--num] = num4;
for (int i = 1; i < 8; i++) {
num4 = inKey[num2++];
num6 = inKey[num2++];
array[--num] = num6;
array[--num] = num4;
num4 = MulInv(inKey[num2++]);
num6 = AddInv(inKey[num2++]);
num8 = AddInv(inKey[num2++]);
num10 = MulInv(inKey[num2++]);
array[--num] = num10;
array[--num] = num6;
array[--num] = num8;
array[--num] = num4;
}
num4 = inKey[num2++];
num6 = inKey[num2++];
array[--num] = num6;
array[--num] = num4;
num4 = MulInv(inKey[num2++]);
num6 = AddInv(inKey[num2++]);
num8 = AddInv(inKey[num2++]);
num10 = MulInv(inKey[num2]);
array[--num] = num10;
array[--num] = num8;
array[--num] = num6;
array[--num] = num4;
return array;
}
private int[] GenerateWorkingKey(bool forEncryption, byte[] userKey)
{
if (forEncryption)
return ExpandKey(userKey);
return InvertKey(ExpandKey(userKey));
}
}
}