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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|