aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/utils/HMAC.java
blob: 5eb5afdba79557e023bf3c2ba32dc7857ba07589 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)

package org.xbill.DNS.utils;

import java.util.Arrays;
import java.security.*;

/**
 * An implementation of the HMAC message authentication code.
 *
 * @author Brian Wellington
 */

public class HMAC {

private MessageDigest digest;
private int blockLength;

private byte [] ipad, opad;

private static final byte IPAD = 0x36;
private static final byte OPAD = 0x5c;

private void
init(byte [] key) {
	int i;

	if (key.length > blockLength) {
		key = digest.digest(key);
		digest.reset();
	}
	ipad = new byte[blockLength];
	opad = new byte[blockLength];
	for (i = 0; i < key.length; i++) {
		ipad[i] = (byte) (key[i] ^ IPAD);
		opad[i] = (byte) (key[i] ^ OPAD);
	}
	for (; i < blockLength; i++) {
		ipad[i] = IPAD;
		opad[i] = OPAD;
	}
	digest.update(ipad);
}

/**
 * Creates a new HMAC instance
 * @param digest The message digest object.
 * @param blockLength The block length of the message digest.
 * @param key The secret key
 */
public
HMAC(MessageDigest digest, int blockLength, byte [] key) {
	digest.reset();
	this.digest = digest;
  	this.blockLength = blockLength;
	init(key);
}

/**
 * Creates a new HMAC instance
 * @param digestName The name of the message digest function.
 * @param blockLength The block length of the message digest.
 * @param key The secret key.
 */
public
HMAC(String digestName, int blockLength, byte [] key) {
	try {
		digest = MessageDigest.getInstance(digestName);
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalArgumentException("unknown digest algorithm "
						   + digestName);
	}
	this.blockLength = blockLength;
	init(key);
}

/**
 * Creates a new HMAC instance
 * @param digest The message digest object.
 * @param key The secret key
 * @deprecated won't work with digests using a padding length other than 64;
 *             use {@code HMAC(MessageDigest digest, int blockLength,
 *             byte [] key)} instead.
 * @see        HMAC#HMAC(MessageDigest digest, int blockLength, byte [] key)
 */
public
HMAC(MessageDigest digest, byte [] key) {
	this(digest, 64, key);
}

/**
 * Creates a new HMAC instance
 * @param digestName The name of the message digest function.
 * @param key The secret key.
 * @deprecated won't work with digests using a padding length other than 64;
 *             use {@code HMAC(String digestName, int blockLength, byte [] key)}
 *             instead
 * @see        HMAC#HMAC(String digestName, int blockLength, byte [] key)
 */
public
HMAC(String digestName, byte [] key) {
	this(digestName, 64, key);
}

/**
 * Adds data to the current hash
 * @param b The data
 * @param offset The index at which to start adding to the hash
 * @param length The number of bytes to hash
 */
public void
update(byte [] b, int offset, int length) {
	digest.update(b, offset, length);
}

/**
 * Adds data to the current hash
 * @param b The data
 */
public void
update(byte [] b) {
	digest.update(b);
}

/**
 * Signs the data (computes the secure hash)
 * @return An array with the signature
 */
public byte []
sign() {
	byte [] output = digest.digest();
	digest.reset();
	digest.update(opad);
	return digest.digest(output);
}

/**
 * Verifies the data (computes the secure hash and compares it to the input)
 * @param signature The signature to compare against
 * @return true if the signature matches, false otherwise
 */
public boolean
verify(byte [] signature) {
	return verify(signature, false);
}

/**
 * Verifies the data (computes the secure hash and compares it to the input)
 * @param signature The signature to compare against
 * @param truncation_ok If true, the signature may be truncated; only the
 * number of bytes in the provided signature are compared.
 * @return true if the signature matches, false otherwise
 */
public boolean
verify(byte [] signature, boolean truncation_ok) {
	byte [] expected = sign();
	if (truncation_ok && signature.length < expected.length) {
		byte [] truncated = new byte[signature.length];
		System.arraycopy(expected, 0, truncated, 0, truncated.length);
		expected = truncated;
	}
	return Arrays.equals(signature, expected);
}

/**
 * Resets the HMAC object for further use
 */
public void
clear() {
	digest.reset();
	digest.update(ipad);
}

/**
 * Returns the length of the digest.
 */
public int
digestLength() {
	return digest.getDigestLength();
}

}