1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) 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 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 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 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 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 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 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 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 [] 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 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 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 169 clear() { 170 digest.reset(); 171 digest.update(ipad); 172 } 173 174 /** 175 * Returns the length of the digest. 176 */ 177 public int 178 digestLength() { 179 return digest.getDigestLength(); 180 } 181 182 } 183