HC128Engine
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class HC128Engine : IStreamCipher
{
private readonly uint[] p = new uint[512];
private readonly uint[] q = new uint[512];
private uint cnt;
private byte[] key;
private byte[] iv;
private bool initialised;
private readonly byte[] buf = new byte[4];
private int idx;
public virtual string AlgorithmName => "HC-128";
private static uint F1(uint x)
{
return Integers.RotateRight(x, 7) ^ Integers.RotateRight(x, 18) ^ (x >> 3);
}
private static uint F2(uint x)
{
return Integers.RotateRight(x, 17) ^ Integers.RotateRight(x, 19) ^ (x >> 10);
}
private uint G1(uint x, uint y, uint z)
{
return (Integers.RotateRight(x, 10) ^ Integers.RotateRight(z, 23)) + Integers.RotateRight(y, 8);
}
private uint G2(uint x, uint y, uint z)
{
return (Integers.RotateLeft(x, 10) ^ Integers.RotateLeft(z, 23)) + Integers.RotateLeft(y, 8);
}
private uint H1(uint x)
{
return q[x & 255] + q[((x >> 16) & 255) + 256];
}
private uint H2(uint x)
{
return p[x & 255] + p[((x >> 16) & 255) + 256];
}
private static uint Mod1024(uint x)
{
return x & 1023;
}
private static uint Mod512(uint x)
{
return x & 511;
}
private static uint Dim(uint x, uint y)
{
return Mod512(x - y);
}
private uint Step()
{
uint num = Mod512(cnt);
uint result;
if (cnt < 512) {
p[num] += G1(p[Dim(num, 3)], p[Dim(num, 10)], p[Dim(num, 511)]);
result = (H1(p[Dim(num, 12)]) ^ p[num]);
} else {
q[num] += G2(q[Dim(num, 3)], q[Dim(num, 10)], q[Dim(num, 511)]);
result = (H2(q[Dim(num, 12)]) ^ q[num]);
}
cnt = Mod1024(cnt + 1);
return result;
}
private void Init()
{
if (key.Length != 16)
throw new ArgumentException("The key must be 128 bits long");
if (iv.Length != 16)
throw new ArgumentException("The IV must be 128 bits long");
idx = 0;
cnt = 0;
uint[] array = new uint[1280];
Pack.LE_To_UInt32(key, 0, array, 0, 4);
Array.Copy(array, 0, array, 4, 4);
Pack.LE_To_UInt32(iv, 0, array, 8, 4);
Array.Copy(array, 8, array, 12, 4);
for (uint num = 16; num < 1280; num++) {
array[num] = F2(array[num - 2]) + array[num - 7] + F1(array[num - 15]) + array[num - 16] + num;
}
Array.Copy(array, 256, p, 0, 512);
Array.Copy(array, 768, q, 0, 512);
for (int i = 0; i < 512; i++) {
p[i] = Step();
}
for (int j = 0; j < 512; j++) {
q[j] = Step();
}
cnt = 0;
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
ParametersWithIV parametersWithIV = parameters as ParametersWithIV;
if (parametersWithIV == null)
throw new ArgumentException("HC-128 Init parameters must include an IV");
KeyParameter keyParameter = parametersWithIV.Parameters as KeyParameter;
if (keyParameter == null)
throw new ArgumentException("Invalid parameter passed to HC128 init - " + Platform.GetTypeName(parameters), "parameters");
key = keyParameter.GetKey();
iv = parametersWithIV.GetIV();
Init();
initialised = true;
}
private byte GetByte()
{
if (idx == 0)
Pack.UInt32_To_LE(Step(), buf);
byte result = buf[idx];
idx = ((idx + 1) & 3);
return result;
}
public virtual void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
Check.DataLength(input, inOff, len, "input buffer too short");
Check.OutputLength(output, outOff, len, "output buffer too short");
for (int i = 0; i < len; i++) {
output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
}
}
public virtual void Reset()
{
Init();
}
public virtual byte ReturnByte(byte input)
{
return (byte)(input ^ GetByte());
}
}
}