namespace com.hitrust.Security.Cryptography { using System; using System.Security.Cryptography; public sealed class HMAC : KeyedHashAlgorithm { private HashAlgorithm m_HashAlgorithm; private bool m_IsDisposed; private bool m_IsHashing; private byte[] m_KeyBuffer; public HMAC(HashAlgorithm hash) : this(hash, null) { } public HMAC(HashAlgorithm hash, byte[] rgbKey) { if (hash == null) { throw new ArgumentNullException(); } if (rgbKey == null) { rgbKey = new byte[hash.HashSize / 8]; new RNGCryptoServiceProvider().GetBytes(rgbKey); } this.m_HashAlgorithm = hash; this.Key = (byte[]) rgbKey.Clone(); this.m_IsDisposed = false; this.Initialize(); } protected override void Dispose(bool disposing) { this.m_IsDisposed = true; base.Dispose(true); this.m_HashAlgorithm.Clear(); try { GC.SuppressFinalize(this); } catch { } } ~HMAC() { this.m_HashAlgorithm.Clear(); } protected override void HashCore(byte[] rgb, int ib, int cb) { if (this.m_IsDisposed) { throw new ObjectDisposedException(base.GetType().FullName); } if (!this.m_IsHashing) { byte[] key; this.m_KeyBuffer = new byte[0x40]; byte[] padded = new byte[0x40]; if (this.Key.Length > 0x40) { key = this.m_HashAlgorithm.ComputeHash(this.Key); } else { key = this.Key; } Array.Copy(key, 0, this.m_KeyBuffer, 0, key.Length); for (int i = 0; i < 0x40; i++) { padded[i] = (byte) (this.m_KeyBuffer[i] ^ 0x36); } this.m_HashAlgorithm.TransformBlock(padded, 0, padded.Length, padded, 0); this.m_IsHashing = true; } this.m_HashAlgorithm.TransformBlock(rgb, ib, cb, rgb, ib); } protected override byte[] HashFinal() { if (this.m_IsDisposed) { throw new ObjectDisposedException(base.GetType().FullName); } this.m_HashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); byte[] dataHash = this.m_HashAlgorithm.Hash; byte[] padded = new byte[0x40]; for (int i = 0; i < 0x40; i++) { padded[i] = (byte) (this.m_KeyBuffer[i] ^ 0x5c); } this.m_HashAlgorithm.Initialize(); this.m_HashAlgorithm.TransformBlock(padded, 0, padded.Length, padded, 0); this.m_HashAlgorithm.TransformFinalBlock(dataHash, 0, dataHash.Length); dataHash = this.m_HashAlgorithm.Hash; Array.Clear(this.m_KeyBuffer, 0, this.m_KeyBuffer.Length); this.m_KeyBuffer = null; this.m_IsHashing = false; return dataHash; } public override void Initialize() { if (this.m_IsDisposed) { throw new ObjectDisposedException(base.GetType().FullName); } this.m_HashAlgorithm.Initialize(); this.m_IsHashing = false; base.State = 0; } public override int HashSize { get { return this.m_HashAlgorithm.HashSize; } } } }