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

VmpcMac

public class VmpcMac : IMac
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) { return DoFinal(output.AsSpan(outOff)); } public virtual int DoFinal(Span<byte> output) { 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.CopyTo(output); 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"); BlockUpdate(input.AsSpan(inOff, inLen)); } public virtual void BlockUpdate(ReadOnlySpan<byte> input) { for (int i = 0; i < input.Length; i++) { byte b = P[n]; s = P[(s + b) & 255]; byte b2 = P[s]; byte b3 = (byte)(input[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++; } } } }