VmpcMac
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using System;
namespace Org.BouncyCastle.Crypto.Macs
{
public class VmpcMac : IMac
{
private byte g;
private byte n;
private byte[] P;
private byte s;
private readonly byte[] T = new byte[32];
private byte[] workingIV;
private byte[] workingKey;
private byte x1;
private byte x2;
private byte x3;
private byte x4;
public virtual string AlgorithmName => "VMPC-MAC";
public virtual int DoFinal(byte[] output, int outOff)
{
for (int i = 1; i < 25; i++) {
s = P[(s + P[n & 255]) & 255];
x4 = P[(x4 + x3 + i) & 255];
x3 = P[(x3 + x2 + i) & 255];
x2 = P[(x2 + x1 + i) & 255];
x1 = P[(x1 + s + i) & 255];
T[g & 31] = (byte)(T[g & 31] ^ x1);
T[(g + 1) & 31] = (byte)(T[(g + 1) & 31] ^ x2);
T[(g + 2) & 31] = (byte)(T[(g + 2) & 31] ^ x3);
T[(g + 3) & 31] = (byte)(T[(g + 3) & 31] ^ x4);
g = (byte)((g + 4) & 31);
byte b = P[n & 255];
P[n & 255] = P[s & 255];
P[s & 255] = b;
n = (byte)((n + 1) & 255);
}
for (int j = 0; j < 768; j++) {
s = P[(s + P[j & 255] + T[j & 31]) & 255];
byte b2 = P[j & 255];
P[j & 255] = P[s & 255];
P[s & 255] = b2;
}
byte[] array = new byte[20];
for (int k = 0; k < 20; k++) {
s = P[(s + P[k & 255]) & 255];
array[k] = P[(P[P[s & 255] & 255] + 1) & 255];
byte b3 = P[k & 255];
P[k & 255] = P[s & 255];
P[s & 255] = b3;
}
Array.Copy(array, 0, output, outOff, array.Length);
Reset();
return array.Length;
}
public virtual int GetMacSize()
{
return 20;
}
public virtual void Init(ICipherParameters parameters)
{
ParametersWithIV parametersWithIV = parameters as ParametersWithIV;
if (parametersWithIV == null)
throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters");
KeyParameter keyParameter = parametersWithIV.Parameters as KeyParameter;
if (keyParameter == null)
throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters");
int keyLength = keyParameter.KeyLength;
if (keyLength < 16 || keyLength > 64)
throw new ArgumentException("VMPC requires 16 to 64 bytes of key");
int iVLength = parametersWithIV.IVLength;
if (iVLength < 16 || iVLength > 64)
throw new ArgumentException("VMPC requires 16 to 64 bytes of IV");
workingKey = keyParameter.GetKey();
workingIV = parametersWithIV.GetIV();
Reset();
}
private void InitKey(byte[] keyBytes, byte[] ivBytes)
{
n = 0;
s = 0;
P = new byte[256];
for (int i = 0; i < 256; i++) {
P[i] = (byte)i;
}
VmpcEngine.KsaRound(P, ref s, keyBytes);
VmpcEngine.KsaRound(P, ref s, ivBytes);
}
public virtual void Reset()
{
InitKey(workingKey, workingIV);
g = (x1 = (x2 = (x3 = (x4 = (n = 0)))));
Array.Clear(T, 0, T.Length);
}
public virtual void Update(byte input)
{
byte b = P[n];
s = P[(s + b) & 255];
byte b2 = P[s];
byte b3 = (byte)(input ^ P[(P[b2] + 1) & 255]);
x4 = P[(x4 + x3) & 255];
x3 = P[(x3 + x2) & 255];
x2 = P[(x2 + x1) & 255];
x1 = P[(x1 + s + b3) & 255];
T[g & 31] = (byte)(T[g & 31] ^ x1);
T[(g + 1) & 31] = (byte)(T[(g + 1) & 31] ^ x2);
T[(g + 2) & 31] = (byte)(T[(g + 2) & 31] ^ x3);
T[(g + 3) & 31] = (byte)(T[(g + 3) & 31] ^ x4);
g = (byte)((g + 4) & 31);
P[n] = b2;
P[s] = b;
n++;
}
public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
{
Check.DataLength(input, inOff, inLen, "input buffer too short");
for (int i = 0; i < inLen; i++) {
byte b = P[n];
s = P[(s + b) & 255];
byte b2 = P[s];
byte b3 = (byte)(input[inOff + i] ^ P[(P[b2] + 1) & 255]);
x4 = P[(x4 + x3) & 255];
x3 = P[(x3 + x2) & 255];
x2 = P[(x2 + x1) & 255];
x1 = P[(x1 + s + b3) & 255];
T[g & 31] = (byte)(T[g & 31] ^ x1);
T[(g + 1) & 31] = (byte)(T[(g + 1) & 31] ^ x2);
T[(g + 2) & 31] = (byte)(T[(g + 2) & 31] ^ x3);
T[(g + 3) & 31] = (byte)(T[(g + 3) & 31] ^ x4);
g = (byte)((g + 4) & 31);
P[n] = b2;
P[s] = b;
n++;
}
}
}
}