Home | History | Annotate | Download | only in utils
      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