summary refs log tree commit diff
path: root/Crypto/src/crypto/macs/HMac.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/macs/HMac.cs')
-rw-r--r--Crypto/src/crypto/macs/HMac.cs134
1 files changed, 134 insertions, 0 deletions
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; + } + } + } +}