<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />

Gost3411Digest

public class Gost3411Digest : IDigest, IMemoable
using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Digests { public class Gost3411Digest : IDigest, IMemoable { private const int DIGEST_LENGTH = 32; private byte[] H = new byte[32]; private byte[] L = new byte[32]; private byte[] M = new byte[32]; private byte[] Sum = new byte[32]; private byte[][] C = MakeC(); private byte[] xBuf = new byte[32]; private int xBufOff; private ulong byteCount; private readonly IBlockCipher cipher = new Gost28147Engine(); private byte[] sBox; private byte[] K = new byte[32]; private byte[] a = new byte[8]; internal short[] wS = new short[16]; internal short[] w_S = new short[16]; internal byte[] S = new byte[32]; internal byte[] U = new byte[32]; internal byte[] V = new byte[32]; internal byte[] W = new byte[32]; private static readonly byte[] C2 = new byte[32] { 0, byte.MaxValue, 0, byte.MaxValue, 0, byte.MaxValue, 0, byte.MaxValue, byte.MaxValue, 0, byte.MaxValue, 0, byte.MaxValue, 0, byte.MaxValue, 0, 0, byte.MaxValue, byte.MaxValue, 0, byte.MaxValue, 0, 0, byte.MaxValue, byte.MaxValue, 0, 0, 0, byte.MaxValue, byte.MaxValue, 0, byte.MaxValue }; public string AlgorithmName => "Gost3411"; private static byte[][] MakeC() { byte[][] array = new byte[4][]; for (int i = 0; i < 4; i++) { array[i] = new byte[32]; } return array; } public Gost3411Digest() { sBox = Gost28147Engine.GetSBox("D-A"); cipher.Init(true, new ParametersWithSBox(null, sBox)); Reset(); } public Gost3411Digest(byte[] sBoxParam) { sBox = Arrays.Clone(sBoxParam); cipher.Init(true, new ParametersWithSBox(null, sBox)); Reset(); } public Gost3411Digest(Gost3411Digest t) { Reset(t); } public int GetDigestSize() { return 32; } public void Update(byte input) { xBuf[xBufOff++] = input; if (xBufOff == xBuf.Length) { sumByteArray(xBuf); processBlock(xBuf, 0); xBufOff = 0; } byteCount++; } public void BlockUpdate(byte[] input, int inOff, int length) { while (xBufOff != 0 && length > 0) { Update(input[inOff]); inOff++; length--; } while (length >= xBuf.Length) { Array.Copy(input, inOff, xBuf, 0, xBuf.Length); sumByteArray(xBuf); processBlock(xBuf, 0); inOff += xBuf.Length; length -= xBuf.Length; byteCount += (uint)xBuf.Length; } while (length > 0) { Update(input[inOff]); inOff++; length--; } } private byte[] P(byte[] input) { int num = 0; for (int i = 0; i < 8; i++) { K[num++] = input[i]; K[num++] = input[8 + i]; K[num++] = input[16 + i]; K[num++] = input[24 + i]; } return K; } private byte[] A(byte[] input) { for (int i = 0; i < 8; i++) { a[i] = (byte)(input[i] ^ input[i + 8]); } Array.Copy(input, 8, input, 0, 24); Array.Copy(a, 0, input, 24, 8); return input; } private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff) { cipher.Init(true, new KeyParameter(key)); cipher.ProcessBlock(input, inOff, s, sOff); } private void fw(byte[] input) { cpyBytesToShort(input, wS); w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]); Array.Copy(wS, 1, w_S, 0, 15); cpyShortToBytes(w_S, input); } private void processBlock(byte[] input, int inOff) { Array.Copy(input, inOff, M, 0, 32); H.CopyTo(U, 0); M.CopyTo(V, 0); for (int i = 0; i < 32; i++) { W[i] = (byte)(U[i] ^ V[i]); } E(P(W), S, 0, H, 0); for (int j = 1; j < 4; j++) { byte[] array = A(U); for (int k = 0; k < 32; k++) { U[k] = (byte)(array[k] ^ C[j][k]); } V = A(A(V)); for (int l = 0; l < 32; l++) { W[l] = (byte)(U[l] ^ V[l]); } E(P(W), S, j * 8, H, j * 8); } for (int m = 0; m < 12; m++) { fw(S); } for (int n = 0; n < 32; n++) { S[n] = (byte)(S[n] ^ M[n]); } fw(S); for (int num = 0; num < 32; num++) { S[num] = (byte)(H[num] ^ S[num]); } for (int num2 = 0; num2 < 61; num2++) { fw(S); } Array.Copy(S, 0, H, 0, H.Length); } private void Finish() { Pack.UInt64_To_LE(byteCount * 8, L); while (xBufOff != 0) { Update(0); } processBlock(L, 0); processBlock(Sum, 0); } public int DoFinal(byte[] output, int outOff) { Finish(); H.CopyTo(output, outOff); Reset(); return 32; } public void Reset() { byteCount = 0; xBufOff = 0; Array.Clear(H, 0, H.Length); Array.Clear(L, 0, L.Length); Array.Clear(M, 0, M.Length); Array.Clear(C[1], 0, C[1].Length); Array.Clear(C[3], 0, C[3].Length); Array.Clear(Sum, 0, Sum.Length); Array.Clear(xBuf, 0, xBuf.Length); C2.CopyTo(C[2], 0); } private void sumByteArray(byte[] input) { int num = 0; for (int i = 0; i != Sum.Length; i++) { int num2 = (Sum[i] & 255) + (input[i] & 255) + num; Sum[i] = (byte)num2; num = num2 >> 8; } } private static void cpyBytesToShort(byte[] S, short[] wS) { for (int i = 0; i < S.Length / 2; i++) { wS[i] = (short)(((S[i * 2 + 1] << 8) & 65280) | (S[i * 2] & 255)); } } private static void cpyShortToBytes(short[] wS, byte[] S) { for (int i = 0; i < S.Length / 2; i++) { S[i * 2 + 1] = (byte)(wS[i] >> 8); S[i * 2] = (byte)wS[i]; } } public int GetByteLength() { return 32; } public IMemoable Copy() { return new Gost3411Digest(this); } public void Reset(IMemoable other) { Gost3411Digest gost3411Digest = (Gost3411Digest)other; sBox = gost3411Digest.sBox; cipher.Init(true, new ParametersWithSBox(null, sBox)); Reset(); Array.Copy(gost3411Digest.H, 0, H, 0, gost3411Digest.H.Length); Array.Copy(gost3411Digest.L, 0, L, 0, gost3411Digest.L.Length); Array.Copy(gost3411Digest.M, 0, M, 0, gost3411Digest.M.Length); Array.Copy(gost3411Digest.Sum, 0, Sum, 0, gost3411Digest.Sum.Length); Array.Copy(gost3411Digest.C[1], 0, C[1], 0, gost3411Digest.C[1].Length); Array.Copy(gost3411Digest.C[2], 0, C[2], 0, gost3411Digest.C[2].Length); Array.Copy(gost3411Digest.C[3], 0, C[3], 0, gost3411Digest.C[3].Length); Array.Copy(gost3411Digest.xBuf, 0, xBuf, 0, gost3411Digest.xBuf.Length); xBufOff = gost3411Digest.xBufOff; byteCount = gost3411Digest.byteCount; } } }