001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS.utils;
004:
005: import java.util.Arrays;
006: import java.security.*;
007:
008: /**
009: * A pure java implementation of the HMAC-MD5 secure hash algorithm
010: *
011: * @author Brian Wellington
012: */
013:
014: public class HMAC {
015:
016: MessageDigest digest;
017: private byte[] ipad, opad;
018:
019: private static final byte IPAD = 0x36;
020: private static final byte OPAD = 0x5c;
021: private static final byte PADLEN = 64;
022:
023: private void init(byte[] key) {
024: int i;
025:
026: if (key.length > PADLEN) {
027: key = digest.digest(key);
028: digest.reset();
029: }
030: ipad = new byte[PADLEN];
031: opad = new byte[PADLEN];
032: for (i = 0; i < key.length; i++) {
033: ipad[i] = (byte) (key[i] ^ IPAD);
034: opad[i] = (byte) (key[i] ^ OPAD);
035: }
036: for (; i < PADLEN; i++) {
037: ipad[i] = IPAD;
038: opad[i] = OPAD;
039: }
040: digest.update(ipad);
041: }
042:
043: /**
044: * Creates a new HMAC instance
045: * @param digest The message digest object.
046: * @param key The secret key
047: */
048: public HMAC(MessageDigest digest, byte[] key) {
049: digest.reset();
050: this .digest = digest;
051: init(key);
052: }
053:
054: /**
055: * Creates a new HMAC instance
056: * @param digestName The name of the message digest function.
057: * @param key The secret key.
058: */
059: public HMAC(String digestName, byte[] key) {
060: try {
061: digest = MessageDigest.getInstance(digestName);
062: } catch (NoSuchAlgorithmException e) {
063: throw new IllegalArgumentException(
064: "unknown digest algorithm " + digestName);
065: }
066: init(key);
067: }
068:
069: /**
070: * Adds data to the current hash
071: * @param b The data
072: * @param offset The index at which to start adding to the hash
073: * @param length The number of bytes to hash
074: */
075: public void update(byte[] b, int offset, int length) {
076: digest.update(b, offset, length);
077: }
078:
079: /**
080: * Adds data to the current hash
081: * @param b The data
082: */
083: public void update(byte[] b) {
084: digest.update(b);
085: }
086:
087: /**
088: * Signs the data (computes the secure hash)
089: * @return An array with the signature
090: */
091: public byte[] sign() {
092: byte[] output = digest.digest();
093: digest.reset();
094: digest.update(opad);
095: return digest.digest(output);
096: }
097:
098: /**
099: * Verifies the data (computes the secure hash and compares it to the input)
100: * @param signature The signature to compare against
101: * @return true if the signature matched, false otherwise
102: */
103: public boolean verify(byte[] signature) {
104: return Arrays.equals(signature, sign());
105: }
106:
107: /**
108: * Resets the HMAC object for further use
109: */
110: public void clear() {
111: digest.reset();
112: digest.update(ipad);
113: }
114:
115: }
|