diff --git a/Crypto/src/crypto/macs/HMac.cs b/Crypto/src/crypto/macs/HMac.cs
new file mode 100644
index 000000000..3f9b0cef0
--- /dev/null
+++ b/Crypto/src/crypto/macs/HMac.cs
@@ -0,0 +1,134 @@
+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;
+ }
+ }
+ }
+}
|