HMac.java revision b61a96e7ef1a78acf013bbf08fe537e5b5f129ca
1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.crypto.macs;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.Hashtable;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.CipherParameters;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.Digest;
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.ExtendedDigest;
8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.Mac;
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.params.KeyParameter;
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * HMAC implementation based on RFC2104
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * H(K XOR opad, H(K XOR ipad, text))
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class HMac
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    implements Mac
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private final static byte IPAD = (byte)0x36;
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private final static byte OPAD = (byte)0x5C;
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private Digest digest;
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private int digestSize;
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private int blockLength;
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[] inputPad;
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[] outputPad;
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static Hashtable blockLengths;
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths = new Hashtable();
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("GOST3411", Integer.valueOf(32));
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("MD2", Integer.valueOf(16));
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("MD4", Integer.valueOf(64));
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("MD5", Integer.valueOf(64));
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("RIPEMD128", Integer.valueOf(64));
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("RIPEMD160", Integer.valueOf(64));
43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-1", Integer.valueOf(64));
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-224", Integer.valueOf(64));
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-256", Integer.valueOf(64));
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-384", Integer.valueOf(128));
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-512", Integer.valueOf(128));
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("Tiger", Integer.valueOf(64));
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("Whirlpool", Integer.valueOf(64));
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static int getByteLength(
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest)
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (digest instanceof ExtendedDigest)
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return ((ExtendedDigest)digest).getByteLength();
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Integer  b = (Integer)blockLengths.get(digest.getAlgorithmName());
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (b == null)
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return b.intValue();
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Base constructor for one of the standard digest algorithms that the
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * byteLength of the algorithm is know for.
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param digest the digest.
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public HMac(
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest)
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this(digest, getByteLength(digest));
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private HMac(
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest,
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int    byteLength)
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.digest = digest;
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digestSize = digest.getDigestSize();
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.blockLength = byteLength;
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        inputPad = new byte[blockLength];
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        outputPad = new byte[blockLength];
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String getAlgorithmName()
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digest.getAlgorithmName() + "/HMAC";
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Digest getUnderlyingDigest()
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digest;
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void init(
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        CipherParameters params)
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.reset();
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] key = ((KeyParameter)params).getKey();
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (key.length > blockLength)
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            digest.update(key, 0, key.length);
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            digest.doFinal(inputPad, 0);
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            for (int i = digestSize; i < inputPad.length; i++)
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                inputPad[i] = 0;
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            System.arraycopy(key, 0, inputPad, 0, key.length);
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            for (int i = key.length; i < inputPad.length; i++)
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                inputPad[i] = 0;
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        outputPad = new byte[inputPad.length];
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < inputPad.length; i++)
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            inputPad[i] ^= IPAD;
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < outputPad.length; i++)
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            outputPad[i] ^= OPAD;
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(inputPad, 0, inputPad.length);
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int getMacSize()
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digestSize;
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void update(
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte in)
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(in);
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void update(
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] in,
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int inOff,
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int len)
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(in, inOff, len);
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int doFinal(
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] out,
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int outOff)
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] tmp = new byte[digestSize];
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.doFinal(tmp, 0);
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(outputPad, 0, outputPad.length);
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(tmp, 0, tmp.length);
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     len = digest.doFinal(out, outOff);
178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        reset();
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return len;
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Reset the mac generator.
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void reset()
188b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
189b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
190b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * reset the underlying digest.
191b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
192b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.reset();
193b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
194b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
195b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * reinitialize the digest.
196b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
197b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(inputPad, 0, inputPad.length);
198b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
199b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
200