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
354c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // BEGIN android-removed
364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("GOST3411", Integer.valueOf(32));
374c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        //
384c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("MD2", Integer.valueOf(16));
394c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("MD4", Integer.valueOf(64));
404c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // END android-removed
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("MD5", Integer.valueOf(64));
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
434c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // BEGIN android-removed
444c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("RIPEMD128", Integer.valueOf(64));
454c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("RIPEMD160", Integer.valueOf(64));
464c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // END android-removed
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-1", Integer.valueOf(64));
494c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // BEGIN android-removed
504c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("SHA-224", Integer.valueOf(64));
514c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // END android-removed
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-256", Integer.valueOf(64));
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-384", Integer.valueOf(128));
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        blockLengths.put("SHA-512", Integer.valueOf(128));
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
564c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // BEGIN android-removed
574c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("Tiger", Integer.valueOf(64));
584c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // blockLengths.put("Whirlpool", Integer.valueOf(64));
594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // END android-removed
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static int getByteLength(
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest)
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (digest instanceof ExtendedDigest)
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return ((ExtendedDigest)digest).getByteLength();
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Integer  b = (Integer)blockLengths.get(digest.getAlgorithmName());
71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (b == null)
73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return b.intValue();
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Base constructor for one of the standard digest algorithms that the
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * byteLength of the algorithm is know for.
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param digest the digest.
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public HMac(
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest)
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this(digest, getByteLength(digest));
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private HMac(
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Digest digest,
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int    byteLength)
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.digest = digest;
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digestSize = digest.getDigestSize();
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.blockLength = byteLength;
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        inputPad = new byte[blockLength];
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        outputPad = new byte[blockLength];
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String getAlgorithmName()
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digest.getAlgorithmName() + "/HMAC";
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Digest getUnderlyingDigest()
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digest;
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void init(
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        CipherParameters params)
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.reset();
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] key = ((KeyParameter)params).getKey();
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (key.length > blockLength)
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            digest.update(key, 0, key.length);
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            digest.doFinal(inputPad, 0);
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            for (int i = digestSize; i < inputPad.length; i++)
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                inputPad[i] = 0;
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            System.arraycopy(key, 0, inputPad, 0, key.length);
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            for (int i = key.length; i < inputPad.length; i++)
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                inputPad[i] = 0;
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        outputPad = new byte[inputPad.length];
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < inputPad.length; i++)
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            inputPad[i] ^= IPAD;
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < outputPad.length; i++)
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            outputPad[i] ^= OPAD;
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(inputPad, 0, inputPad.length);
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int getMacSize()
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return digestSize;
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void update(
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte in)
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(in);
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void update(
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] in,
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int inOff,
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int len)
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(in, inOff, len);
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int doFinal(
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] out,
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int outOff)
178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] tmp = new byte[digestSize];
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.doFinal(tmp, 0);
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(outputPad, 0, outputPad.length);
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(tmp, 0, tmp.length);
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     len = digest.doFinal(out, outOff);
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        reset();
188b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
189b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return len;
190b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
191b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
192b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
193b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Reset the mac generator.
194b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
195b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void reset()
196b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
197b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
198b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * reset the underlying digest.
199b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
200b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.reset();
201b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
202b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
203b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * reinitialize the digest.
204b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
205b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        digest.update(inputPad, 0, inputPad.length);
206b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
207b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
208