using System;
using System.Collections;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Macs{
/**
* HMAC implementation based on RFC2104
*
* H(K XOR opad, H(K XOR ipad, text))
*/
public class HMac
: IMac
{
private const byte IPAD = (byte)0x36;
private const byte OPAD = (byte)0x5C;
private readonly IDigest digest;
private readonly int digestSize;
private readonly int blockLength;
private readonly byte[] inputPad;
private readonly byte[] outputPad;
public HMac(
IDigest digest)
{
this.digest = digest;
this.digestSize = digest.GetDigestSize();
this.blockLength = digest.GetByteLength();
this.inputPad = new byte[blockLength];
this.outputPad = new byte[blockLength];
}
public string AlgorithmName
{
get { return digest.AlgorithmName + "/HMAC"; }
}
public IDigest GetUnderlyingDigest()
{
return digest;
}
public void Init(
ICipherParameters parameters)
{
digest.Reset();
byte[] key = ((KeyParameter)parameters).GetKey();
int keyLength = key.Length;
if (keyLength > blockLength)
{
digest.BlockUpdate(key, 0, key.Length);
digest.DoFinal(inputPad, 0);
keyLength = digestSize;
}
else
{
Array.Copy(key, 0, inputPad, 0, keyLength);
}
Array.Clear(inputPad, keyLength, blockLength - keyLength);
Array.Copy(inputPad, 0, outputPad, 0, blockLength);
xor(inputPad, IPAD);
xor(outputPad, OPAD);
// Initialise the digest
digest.BlockUpdate(inputPad, 0, inputPad.Length);
}
public int GetMacSize()
{
return digestSize;
}
public void Update(
byte input)
{
digest.Update(input);
}
public void BlockUpdate(
byte[] input,
int inOff,
int len)
{
digest.BlockUpdate(input, inOff, len);
}
public int DoFinal(
byte[] output,
int outOff)
{
byte[] tmp = new byte[digestSize];
digest.DoFinal(tmp, 0);
digest.BlockUpdate(outputPad, 0, outputPad.Length);
digest.BlockUpdate(tmp, 0, tmp.Length);
int len = digest.DoFinal(output, outOff);
// Initialise the digest
digest.BlockUpdate(inputPad, 0, inputPad.Length);
return len;
}
/**
* Reset the mac generator.
*/
public void Reset()
{
// Reset underlying digest
digest.Reset();
// Initialise the digest
digest.BlockUpdate(inputPad, 0, inputPad.Length);
}
private static void xor(byte[] a, byte n)
{
for (int i = 0; i < a.Length; ++i)
{
a[i] ^= n;
}
}
}
}
|