HMAC
Provides HMAC algorithm implementation.
using System;
using System.Security.Cryptography;
namespace SshNet.Security.Cryptography
{
public abstract class HMAC : KeyedHashAlgorithm
{
private IHashProvider _hashProvider;
private byte[] _innerPadding;
private byte[] _outerPadding;
private readonly int _hashSize;
private bool _innerPaddingWritten;
protected abstract int BlockSize { get; }
public override int HashSize => _hashSize;
public override byte[] Key {
get {
return base.Key;
}
set {
SetKey(value);
}
}
private HMAC(IHashProvider hashProvider)
{
if (hashProvider == null)
throw new ArgumentNullException("hashProvider");
_hashProvider = hashProvider;
_hashSize = _hashProvider.HashSize;
}
internal HMAC(IHashProvider hashProvider, byte[] key, int hashSize)
: this(hashProvider, key)
{
_hashSize = hashSize;
}
internal HMAC(IHashProvider hashProvider, byte[] key)
: this(hashProvider)
{
SetKey(key);
}
public override void Initialize()
{
_hashProvider.Reset();
_innerPaddingWritten = false;
}
protected override void HashCore(byte[] rgb, int ib, int cb)
{
if (!_innerPaddingWritten) {
_hashProvider.TransformBlock(_innerPadding, 0, BlockSize, _innerPadding, 0);
_innerPaddingWritten = true;
}
_hashProvider.HashCore(rgb, ib, cb);
}
protected override byte[] HashFinal()
{
byte[] array = _hashProvider.ComputeHash(new byte[0]);
_hashProvider.TransformBlock(_outerPadding, 0, BlockSize, _outerPadding, 0);
_hashProvider.TransformFinalBlock(array, 0, array.Length);
byte[] hash = _hashProvider.Hash;
return GetTruncatedHash(hash);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_hashProvider != null) {
_hashProvider.Dispose();
_hashProvider = null;
}
}
private byte[] GetTruncatedHash(byte[] hash)
{
int num = HashSize / 8;
if (hash.Length == num)
return hash;
byte[] array = new byte[num];
Buffer.BlockCopy(hash, 0, array, 0, num);
return array;
}
private void SetKey(byte[] value)
{
byte[] shortenedKey = GetShortenedKey(value);
_innerPadding = new byte[BlockSize];
_outerPadding = new byte[BlockSize];
for (int i = 0; i < shortenedKey.Length; i++) {
_innerPadding[i] = (byte)(54 ^ shortenedKey[i]);
_outerPadding[i] = (byte)(92 ^ shortenedKey[i]);
}
for (int j = shortenedKey.Length; j < BlockSize; j++) {
_innerPadding[j] = 54;
_outerPadding[j] = 92;
}
base.Key = shortenedKey;
}
private byte[] GetShortenedKey(byte[] key)
{
if (key.Length > BlockSize)
return _hashProvider.ComputeHash(key);
return key;
}
}
}