251 lines
5.6 KiB
C#
251 lines
5.6 KiB
C#
using System;
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Utilities;
|
|
|
|
namespace Org.BouncyCastle.Crypto.Macs;
|
|
|
|
public class Gost28147Mac : IMac
|
|
{
|
|
private const int blockSize = 8;
|
|
|
|
private const int macSize = 4;
|
|
|
|
private int bufOff;
|
|
|
|
private byte[] buf;
|
|
|
|
private byte[] mac;
|
|
|
|
private bool firstStep = true;
|
|
|
|
private int[] workingKey;
|
|
|
|
private byte[] macIV = null;
|
|
|
|
private byte[] S = new byte[128]
|
|
{
|
|
9, 6, 3, 2, 8, 11, 1, 7, 10, 4,
|
|
14, 15, 12, 0, 13, 5, 3, 7, 14, 9,
|
|
8, 10, 15, 0, 5, 2, 6, 12, 11, 4,
|
|
13, 1, 14, 4, 6, 2, 11, 3, 13, 8,
|
|
12, 15, 5, 10, 0, 7, 1, 9, 14, 7,
|
|
10, 12, 13, 1, 3, 9, 0, 2, 11, 4,
|
|
15, 8, 5, 6, 11, 5, 1, 9, 8, 13,
|
|
15, 0, 14, 4, 2, 3, 12, 7, 10, 6,
|
|
3, 10, 13, 12, 1, 2, 0, 11, 7, 5,
|
|
9, 4, 8, 15, 14, 6, 1, 13, 2, 9,
|
|
7, 10, 6, 0, 8, 12, 4, 5, 15, 3,
|
|
11, 14, 11, 10, 15, 5, 0, 12, 14, 8,
|
|
6, 2, 3, 9, 1, 7, 13, 4
|
|
};
|
|
|
|
public string AlgorithmName => "Gost28147Mac";
|
|
|
|
public Gost28147Mac()
|
|
{
|
|
mac = new byte[8];
|
|
buf = new byte[8];
|
|
bufOff = 0;
|
|
}
|
|
|
|
private static int[] GenerateWorkingKey(byte[] userKey)
|
|
{
|
|
if (userKey.Length != 32)
|
|
{
|
|
throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
|
|
}
|
|
int[] array = new int[8];
|
|
for (int i = 0; i != 8; i++)
|
|
{
|
|
array[i] = bytesToint(userKey, i * 4);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public void Init(ICipherParameters parameters)
|
|
{
|
|
Reset();
|
|
buf = new byte[8];
|
|
macIV = null;
|
|
if (parameters is ParametersWithSBox)
|
|
{
|
|
ParametersWithSBox parametersWithSBox = (ParametersWithSBox)parameters;
|
|
parametersWithSBox.GetSBox().CopyTo(S, 0);
|
|
if (parametersWithSBox.Parameters != null)
|
|
{
|
|
workingKey = GenerateWorkingKey(((KeyParameter)parametersWithSBox.Parameters).GetKey());
|
|
}
|
|
return;
|
|
}
|
|
if (parameters is KeyParameter)
|
|
{
|
|
workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
|
|
return;
|
|
}
|
|
if (parameters is ParametersWithIV)
|
|
{
|
|
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
|
|
workingKey = GenerateWorkingKey(((KeyParameter)parametersWithIV.Parameters).GetKey());
|
|
Array.Copy(parametersWithIV.GetIV(), 0, mac, 0, mac.Length);
|
|
macIV = parametersWithIV.GetIV();
|
|
return;
|
|
}
|
|
throw new ArgumentException("invalid parameter passed to Gost28147 init - " + Platform.GetTypeName(parameters));
|
|
}
|
|
|
|
public int GetMacSize()
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
private int gost28147_mainStep(int n1, int key)
|
|
{
|
|
int num = key + n1;
|
|
int num2 = S[num & 0xF];
|
|
num2 += S[16 + ((num >> 4) & 0xF)] << 4;
|
|
num2 += S[32 + ((num >> 8) & 0xF)] << 8;
|
|
num2 += S[48 + ((num >> 12) & 0xF)] << 12;
|
|
num2 += S[64 + ((num >> 16) & 0xF)] << 16;
|
|
num2 += S[80 + ((num >> 20) & 0xF)] << 20;
|
|
num2 += S[96 + ((num >> 24) & 0xF)] << 24;
|
|
num2 += S[112 + ((num >> 28) & 0xF)] << 28;
|
|
int num3 = num2 << 11;
|
|
int num4 = num2 >>> 21;
|
|
return num3 | num4;
|
|
}
|
|
|
|
private void gost28147MacFunc(int[] workingKey, byte[] input, int inOff, byte[] output, int outOff)
|
|
{
|
|
int num = bytesToint(input, inOff);
|
|
int num2 = bytesToint(input, inOff + 4);
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
for (int j = 0; j < 8; j++)
|
|
{
|
|
int num3 = num;
|
|
num = num2 ^ gost28147_mainStep(num, workingKey[j]);
|
|
num2 = num3;
|
|
}
|
|
}
|
|
intTobytes(num, output, outOff);
|
|
intTobytes(num2, output, outOff + 4);
|
|
}
|
|
|
|
private static int bytesToint(byte[] input, int inOff)
|
|
{
|
|
return (int)((input[inOff + 3] << 24) & 0xFF000000u) + ((input[inOff + 2] << 16) & 0xFF0000) + ((input[inOff + 1] << 8) & 0xFF00) + (input[inOff] & 0xFF);
|
|
}
|
|
|
|
private static void intTobytes(int num, byte[] output, int outOff)
|
|
{
|
|
output[outOff + 3] = (byte)(num >> 24);
|
|
output[outOff + 2] = (byte)(num >> 16);
|
|
output[outOff + 1] = (byte)(num >> 8);
|
|
output[outOff] = (byte)num;
|
|
}
|
|
|
|
private static byte[] CM5func(byte[] buf, int bufOff, byte[] mac)
|
|
{
|
|
byte[] array = new byte[buf.Length - bufOff];
|
|
Array.Copy(buf, bufOff, array, 0, mac.Length);
|
|
for (int i = 0; i != mac.Length; i++)
|
|
{
|
|
array[i] ^= mac[i];
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public void Update(byte input)
|
|
{
|
|
if (bufOff == buf.Length)
|
|
{
|
|
byte[] array = new byte[buf.Length];
|
|
Array.Copy(buf, 0, array, 0, mac.Length);
|
|
if (firstStep)
|
|
{
|
|
firstStep = false;
|
|
if (macIV != null)
|
|
{
|
|
array = CM5func(buf, 0, macIV);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
array = CM5func(buf, 0, mac);
|
|
}
|
|
gost28147MacFunc(workingKey, array, 0, mac, 0);
|
|
bufOff = 0;
|
|
}
|
|
buf[bufOff++] = input;
|
|
}
|
|
|
|
public void BlockUpdate(byte[] input, int inOff, int len)
|
|
{
|
|
if (len < 0)
|
|
{
|
|
throw new ArgumentException("Can't have a negative input length!");
|
|
}
|
|
int num = 8 - bufOff;
|
|
if (len > num)
|
|
{
|
|
Array.Copy(input, inOff, buf, bufOff, num);
|
|
byte[] array = new byte[buf.Length];
|
|
Array.Copy(buf, 0, array, 0, mac.Length);
|
|
if (firstStep)
|
|
{
|
|
firstStep = false;
|
|
if (macIV != null)
|
|
{
|
|
array = CM5func(buf, 0, macIV);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
array = CM5func(buf, 0, mac);
|
|
}
|
|
gost28147MacFunc(workingKey, array, 0, mac, 0);
|
|
bufOff = 0;
|
|
len -= num;
|
|
inOff += num;
|
|
while (len > 8)
|
|
{
|
|
array = CM5func(input, inOff, mac);
|
|
gost28147MacFunc(workingKey, array, 0, mac, 0);
|
|
len -= 8;
|
|
inOff += 8;
|
|
}
|
|
}
|
|
Array.Copy(input, inOff, buf, bufOff, len);
|
|
bufOff += len;
|
|
}
|
|
|
|
public int DoFinal(byte[] output, int outOff)
|
|
{
|
|
while (bufOff < 8)
|
|
{
|
|
buf[bufOff++] = 0;
|
|
}
|
|
byte[] array = new byte[buf.Length];
|
|
Array.Copy(buf, 0, array, 0, mac.Length);
|
|
if (firstStep)
|
|
{
|
|
firstStep = false;
|
|
}
|
|
else
|
|
{
|
|
array = CM5func(buf, 0, mac);
|
|
}
|
|
gost28147MacFunc(workingKey, array, 0, mac, 0);
|
|
Array.Copy(mac, mac.Length / 2 - 4, output, outOff, 4);
|
|
Reset();
|
|
return 4;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
Array.Clear(buf, 0, buf.Length);
|
|
bufOff = 0;
|
|
firstStep = true;
|
|
}
|
|
}
|