• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2 
3 package org.xbill.DNS.utils;
4 
5 import java.util.Arrays;
6 import java.security.*;
7 
8 /**
9  * An implementation of the HMAC message authentication code.
10  *
11  * @author Brian Wellington
12  */
13 
14 public class HMAC {
15 
16 private MessageDigest digest;
17 private int blockLength;
18 
19 private byte [] ipad, opad;
20 
21 private static final byte IPAD = 0x36;
22 private static final byte OPAD = 0x5c;
23 
24 private void
init(byte [] key)25 init(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  */
51 public
HMAC(MessageDigest digest, int blockLength, byte [] key)52 HMAC(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  */
65 public
HMAC(String digestName, int blockLength, byte [] key)66 HMAC(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  */
86 public
HMAC(MessageDigest digest, byte [] key)87 HMAC(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  */
100 public
HMAC(String digestName, byte [] key)101 HMAC(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  */
111 public void
update(byte [] b, int offset, int length)112 update(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  */
120 public void
update(byte [] b)121 update(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  */
129 public byte []
sign()130 sign() {
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  */
142 public boolean
verify(byte [] signature)143 verify(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  */
154 public boolean
verify(byte [] signature, boolean truncation_ok)155 verify(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  */
168 public void
clear()169 clear() {
170 	digest.reset();
171 	digest.update(ipad);
172 }
173 
174 /**
175  * Returns the length of the digest.
176  */
177 public int
digestLength()178 digestLength() {
179 	return digest.getDigestLength();
180 }
181 
182 }
183