blob: 5eb5afdba79557e023bf3c2ba32dc7857ba07589 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS.utils;
4
5import java.util.Arrays;
6import java.security.*;
7
8/**
9 * An implementation of the HMAC message authentication code.
10 *
11 * @author Brian Wellington
12 */
13
14public class HMAC {
15
16private MessageDigest digest;
17private int blockLength;
18
19private byte [] ipad, opad;
20
21private static final byte IPAD = 0x36;
22private static final byte OPAD = 0x5c;
23
24private void
25init(byte [] key) {
26 int i;
27
28 if (key.length > blockLength) {
29 key = digest.digest(key);
30 digest.reset();
31 }
32 ipad = new byte[blockLength];
33 opad = new byte[blockLength];
34 for (i = 0; i < key.length; i++) {
35 ipad[i] = (byte) (key[i] ^ IPAD);
36 opad[i] = (byte) (key[i] ^ OPAD);
37 }
38 for (; i < blockLength; i++) {
39 ipad[i] = IPAD;
40 opad[i] = OPAD;
41 }
42 digest.update(ipad);
43}
44
45/**
46 * Creates a new HMAC instance
47 * @param digest The message digest object.
48 * @param blockLength The block length of the message digest.
49 * @param key The secret key
50 */
51public
52HMAC(MessageDigest digest, int blockLength, byte [] key) {
53 digest.reset();
54 this.digest = digest;
55 this.blockLength = blockLength;
56 init(key);
57}
58
59/**
60 * Creates a new HMAC instance
61 * @param digestName The name of the message digest function.
62 * @param blockLength The block length of the message digest.
63 * @param key The secret key.
64 */
65public
66HMAC(String digestName, int blockLength, byte [] key) {
67 try {
68 digest = MessageDigest.getInstance(digestName);
69 } catch (NoSuchAlgorithmException e) {
70 throw new IllegalArgumentException("unknown digest algorithm "
71 + digestName);
72 }
73 this.blockLength = blockLength;
74 init(key);
75}
76
77/**
78 * Creates a new HMAC instance
79 * @param digest The message digest object.
80 * @param key The secret key
81 * @deprecated won't work with digests using a padding length other than 64;
82 * use {@code HMAC(MessageDigest digest, int blockLength,
83 * byte [] key)} instead.
84 * @see HMAC#HMAC(MessageDigest digest, int blockLength, byte [] key)
85 */
86public
87HMAC(MessageDigest digest, byte [] key) {
88 this(digest, 64, key);
89}
90
91/**
92 * Creates a new HMAC instance
93 * @param digestName The name of the message digest function.
94 * @param key The secret key.
95 * @deprecated won't work with digests using a padding length other than 64;
96 * use {@code HMAC(String digestName, int blockLength, byte [] key)}
97 * instead
98 * @see HMAC#HMAC(String digestName, int blockLength, byte [] key)
99 */
100public
101HMAC(String digestName, byte [] key) {
102 this(digestName, 64, key);
103}
104
105/**
106 * Adds data to the current hash
107 * @param b The data
108 * @param offset The index at which to start adding to the hash
109 * @param length The number of bytes to hash
110 */
111public void
112update(byte [] b, int offset, int length) {
113 digest.update(b, offset, length);
114}
115
116/**
117 * Adds data to the current hash
118 * @param b The data
119 */
120public void
121update(byte [] b) {
122 digest.update(b);
123}
124
125/**
126 * Signs the data (computes the secure hash)
127 * @return An array with the signature
128 */
129public byte []
130sign() {
131 byte [] output = digest.digest();
132 digest.reset();
133 digest.update(opad);
134 return digest.digest(output);
135}
136
137/**
138 * Verifies the data (computes the secure hash and compares it to the input)
139 * @param signature The signature to compare against
140 * @return true if the signature matches, false otherwise
141 */
142public boolean
143verify(byte [] signature) {
144 return verify(signature, false);
145}
146
147/**
148 * Verifies the data (computes the secure hash and compares it to the input)
149 * @param signature The signature to compare against
150 * @param truncation_ok If true, the signature may be truncated; only the
151 * number of bytes in the provided signature are compared.
152 * @return true if the signature matches, false otherwise
153 */
154public boolean
155verify(byte [] signature, boolean truncation_ok) {
156 byte [] expected = sign();
157 if (truncation_ok && signature.length < expected.length) {
158 byte [] truncated = new byte[signature.length];
159 System.arraycopy(expected, 0, truncated, 0, truncated.length);
160 expected = truncated;
161 }
162 return Arrays.equals(signature, expected);
163}
164
165/**
166 * Resets the HMAC object for further use
167 */
168public void
169clear() {
170 digest.reset();
171 digest.update(ipad);
172}
173
174/**
175 * Returns the length of the digest.
176 */
177public int
178digestLength() {
179 return digest.getDigestLength();
180}
181
182}