package org.bouncycastle.crypto.macs;
import java.util.Hashtable;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.params.KeyParameter;
public class HMac
implements Mac
{
private final static byte IPAD = (byte)0x36;
private final static byte OPAD = (byte)0x5C;
private Digest digest;
private int digestSize;
private int blockLength;
private byte[] inputPad;
private byte[] outputPad;
private static Hashtable blockLengths;
static
{
blockLengths = new Hashtable();
blockLengths.put("GOST3411", new Integer(32));
blockLengths.put("MD2", new Integer(16));
blockLengths.put("MD4", new Integer(64));
blockLengths.put("MD5", new Integer(64));
blockLengths.put("RIPEMD128", new Integer(64));
blockLengths.put("RIPEMD160", new Integer(64));
blockLengths.put("SHA-1", new Integer(64));
blockLengths.put("SHA-224", new Integer(64));
blockLengths.put("SHA-256", new Integer(64));
blockLengths.put("SHA-384", new Integer(128));
blockLengths.put("SHA-512", new Integer(128));
blockLengths.put("Tiger", new Integer(64));
blockLengths.put("Whirlpool", new Integer(64));
}
private static int getByteLength(
Digest digest)
{
if (digest instanceof ExtendedDigest)
{
return ((ExtendedDigest)digest).getByteLength();
}
Integer b = (Integer)blockLengths.get(digest.getAlgorithmName());
if (b == null)
{
throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
}
return b.intValue();
}
public HMac(
Digest digest)
{
this(digest, getByteLength(digest));
}
private HMac(
Digest digest,
int byteLength)
{
this.digest = digest;
digestSize = digest.getDigestSize();
this.blockLength = byteLength;
inputPad = new byte[blockLength];
outputPad = new byte[blockLength];
}
public String getAlgorithmName()
{
return digest.getAlgorithmName() + "/HMAC";
}
public Digest getUnderlyingDigest()
{
return digest;
}
public void init(
CipherParameters params)
{
digest.reset();
byte[] key = ((KeyParameter)params).getKey();
if (key.length > blockLength)
{
digest.update(key, 0, key.length);
digest.doFinal(inputPad, 0);
for (int i = digestSize; i < inputPad.length; i++)
{
inputPad[i] = 0;
}
}
else
{
System.arraycopy(key, 0, inputPad, 0, key.length);
for (int i = key.length; i < inputPad.length; i++)
{
inputPad[i] = 0;
}
}
outputPad = new byte[inputPad.length];
System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
for (int i = 0; i < inputPad.length; i++)
{
inputPad[i] ^= IPAD;
}
for (int i = 0; i < outputPad.length; i++)
{
outputPad[i] ^= OPAD;
}
digest.update(inputPad, 0, inputPad.length);
}
public int getMacSize()
{
return digestSize;
}
public void update(
byte in)
{
digest.update(in);
}
public void update(
byte[] in,
int inOff,
int len)
{
digest.update(in, inOff, len);
}
public int doFinal(
byte[] out,
int outOff)
{
byte[] tmp = new byte[digestSize];
digest.doFinal(tmp, 0);
digest.update(outputPad, 0, outputPad.length);
digest.update(tmp, 0, tmp.length);
int len = digest.doFinal(out, outOff);
reset();
return len;
}
public void reset()
{
digest.reset();
digest.update(inputPad, 0, inputPad.length);
}
}