BuC
New member
Code:
using System;
using System.Security.Cryptography;
namespace FreeeeeDat
{
public enum OMACVariant
{
OMAC1,
OMAC2
}
public class OMAC : KeyedHashAlgorithm
{
private SymmetricAlgorithm _algorithm;
private ICryptoTransform _cipher;
private readonly OMACVariant _variant;
public OMACVariant Variant { get { return _variant; } }
private byte[] _buffer;
private int _bufferPosition;
private byte[] _lu1;
private byte[] _lu2;
public OMAC()
: this(Rijndael.Create(), OMACVariant.OMAC1, null)
{
}
public OMAC(SymmetricAlgorithm algorithm, OMACVariant variant)
: this(algorithm, variant, null)
{
}
public OMAC(SymmetricAlgorithm algorithm, OMACVariant variant, byte[] key)
{
if (algorithm == null)
throw new ArgumentNullException("algorithm");
if (algorithm.BlockSize != 64 && algorithm.BlockSize != 128)
throw new ArgumentException("Unsupported block size");
if (variant != OMACVariant.OMAC1 && variant != OMACVariant.OMAC2)
throw new ArgumentException("Invalid OMAC variant");
_algorithm = algorithm;
_variant = variant;
_buffer = new byte[algorithm.BlockSize / 8];
_lu1 = new byte[algorithm.BlockSize / 8];
_lu2 = new byte[algorithm.BlockSize / 8];
HashSizeValue = algorithm.BlockSize;
if (key == null)
KeyValue = algorithm.Key;
else
Key = key;
}
public override byte[] Key
{
set
{
if (!_algorithm.ValidKeySize(value.Length * 8))
throw new ArgumentException("Invalid key size");
base.Key = value;
if (_cipher != null)
{
_cipher.Dispose();
_cipher = null;
}
}
}
private void CreateCipher()
{
_algorithm.BlockSize = HashSizeValue;
_algorithm.Mode = CipherMode.ECB;
_algorithm.Padding = PaddingMode.None;
_cipher = _algorithm.CreateEncryptor(KeyValue, null);
_cipher.TransformBlock(_buffer, 0, _buffer.Length, _buffer, 0);
ApplyU(_buffer, _lu1);
if (_variant == OMACVariant.OMAC1)
ApplyU(_lu1, _lu2);
else
ApplyInverseU(_buffer, _lu2);
Array.Clear(_buffer, 0, _buffer.Length);
}
private void ApplyU(byte[] source, byte[] dest)
{
for (int i = 0; ; )
{
dest[i] = (byte)(source[i] << 1);
if (++i >= source.Length)
break;
if ((source[i] & 0x80) != 0)
dest[i - 1] |= 0x1;
}
if ((source[0] & 0x80) != 0)
{
if (dest.Length == 8)
dest[7] ^= 0x1B;
else
dest[15] ^= 0x87;
}
}
private void ApplyInverseU(byte[] source, byte[] dest)
{
for (int i = source.Length - 1; ; )
{
dest[i] = (byte)(source[i] >> 1);
if (--i < 0)
break;
if ((source[i] & 0x01) != 0)
dest[i + 1] |= 0x80;
}
if ((source[source.Length - 1] & 0x01) != 0)
{
dest[0] ^= 0x80;
if (dest.Length == 8)
dest[7] ^= 0x0D;
else
dest[15] ^= 0x43;
}
}
public override void Initialize()
{
Array.Clear(_buffer, 0, _buffer.Length);
_bufferPosition = 0;
}
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
if (_cipher == null)
CreateCipher();
while (true)
{
int count = Math.Min(cbSize, _buffer.Length - _bufferPosition);
for (int i = 0; i < count; i++)
_buffer[_bufferPosition++] ^= array[ibStart + i];
cbSize -= count;
if (cbSize == 0)
break;
_cipher.TransformBlock(_buffer, 0, _buffer.Length, _buffer, 0);
_bufferPosition = 0;
ibStart += count;
}
}
protected override byte[] HashFinal()
{
if (_bufferPosition < _buffer.Length)
{
_buffer[_bufferPosition] ^= 0x80;
for (int i = 0; i < _buffer.Length; i++)
_buffer[i] ^= _lu2[i];
}
else
{
for (int i = 0; i < _buffer.Length; i++)
_buffer[i] ^= _lu1[i];
}
byte[] ret = new byte[_buffer.Length];
_cipher.TransformBlock(_buffer, 0, _buffer.Length, ret, 0);
return ret;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_algorithm != null)
{
_algorithm.Clear();
_algorithm = null;
}
if (_cipher != null)
{
_cipher.Dispose();
_cipher = null;
}
if (_buffer != null)
{
Array.Clear(_buffer, 0, _buffer.Length);
_buffer = null;
}
if (_lu1 != null)
{
Array.Clear(_lu1, 0, _lu1.Length);
_lu1 = null;
}
if (_lu2 != null)
{
Array.Clear(_lu2, 0, _lu2.Length);
_lu2 = null;
}
}
base.Dispose(disposing);
}
}
}
Usage:
Code:
OMAC omac = new OMAC();
omac.Key = KEY;
byte[] hash = omac.ComputeHash(data);