OMac - CMac Hash

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);
 
Top