Hi Brad,
The HMAC-MD5 has been provided by Michael Lecuyer as freely available
source at:
http://www.theorem.com/java/Free.htm#HMAC-MD5
The full source code from the above resource has been reproduced here
for your convenience, but you can alternatively just download the java
source file available at the above URL.
/* BEGIN SOURCE CODE */
package com.theorem.misc;
import com.theorem.misc.MD5;
/**
* JAVA translation of the hmac_md5() function from RFC 2104.
* <P>
* HMAC: Keyed-Hashing for Message Authentication.
* <P>
* Copyright (C) Michael Lecuyer (1999). All Rights Reserved.
* <P>
* This source code and extensions of it may be used freely as long as
the
* copyright notice above and this paragraph are included in all
copies and
* derivative works.
* <P>
* A notice about the original C code:
* Copyright (C) The Internet Society (1999). All Rights Reserved.
* <P>
* This document and translations of it may be copied and furnished to
* others, and derivative works that comment on or otherwise explain
it
* or assist in its implementation may be prepared, copied, published
* and distributed, in whole or in part, without restriction of any
* kind, provided that the above copyright notice and this paragraph
are
* included on all such copies and derivative works. However, this
* document itself may not be modified in any way, such as by removing
* the copyright notice or references to the Internet Society or other
* Internet organizations, except as needed for the purpose of
* developing Internet standards in which case the procedures for
* copyrights defined in the Internet Standards process must be
* followed, or as required to translate it into languages other than
* English. The limited permissions granted above are perpetual and
will
* not be revoked by the Internet Society or its successors or
assigns.
* This document and the information contained herein is provided on
an
* "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
* TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
* HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
* <P>
*
* @author Michael Lecuyer <mjl@theorem.com>.
* @version 1.0 December 26, 1999
*/
public class HMAC_MD5
{
/**
* Run standard tests from the RFC:
*/
public static void main(String arg[])
{
String expectedHash;
byte digest[];
HMAC_MD5 hm;
System.out.println("Test Vectors from RFC 2104 - HMAC:
Keyed-Hashing for Message Authentication");
System.out.println("This test uses HMAC-MD5.");
System.out.println();
System.out.println("Test #1:");
// Test #1:
byte key1[] = {
(byte)0x0b, (byte)0x0b, (byte)0x0b, (byte)0x0b, (byte)0x0b,
(byte)0x0b, (byte)0x0b, (byte)0x0b,
(byte)0x0b, (byte)0x0b, (byte)0x0b, (byte)0x0b, (byte)0x0b,
(byte)0x0b, (byte)0x0b, (byte)0x0b
};
String text1 = "Hi There";
expectedHash = "0X9294727A3638BB1C13F48EF8158BFC9D";
hm = new HMAC_MD5(key1);
hm.addData(text1.getBytes());
digest = hm.sign();
System.out.println("Calculated hash 0X" + hm);
System.out.println(" Expected hash " + expectedHash);
// Test #2
System.out.println();
System.out.println("Test #2:");
byte key2[] = "Jefe".getBytes();
String text2 = "what do ya want for nothing?";
expectedHash = "0X750C783E6AB0B503EAA86E310A5DB738";
hm = new HMAC_MD5(key2);
hm.addData(text2.getBytes());
digest = hm.sign();
System.out.println("Calculated hash 0X" + hm);
System.out.println(" Expected hash " + expectedHash);
// Test #3
System.out.println();
System.out.println("Test #3:");
byte key3[] = {
(byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa,
(byte)0xaa, (byte)0xaa, (byte)0xaa,
(byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa, (byte)0xaa,
(byte)0xaa, (byte)0xaa, (byte)0xaa
};
byte text3[] = {
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd, (byte)0xdd,
(byte)0xdd, (byte)0xdd
};
expectedHash = "0X56BE34521D144C88DBB8C733F0E8B3F6";
byte eh[] = {
(byte)0x56, (byte)0xBE, (byte)0x34, (byte)0x52, (byte)0x1D,
(byte)0x14, (byte)0x4C, (byte)0x88,
(byte)0xDB, (byte)0xB8, (byte)0xC7, (byte)0x33, (byte)0xF0,
(byte)0xE8, (byte)0xB3, (byte)0xF6
};
hm = new HMAC_MD5(key3);
hm.addData(text3);
digest = hm.sign();
System.out.println("Calculated hash 0X" + hm);
System.out.println(" Expected hash " + expectedHash);
System.out.println("Signature Verification: " + hm.verify(eh));
}
/**
* Digest to be returned upon completion of the HMAC_MD5.
*/
private byte digest[];
/**
* Inner Padding.
*/
private byte kIpad[];
/**
* Outer Padding.
*/
private byte kOpad[];
/**
* Inner MD5 object.
*/
private MD5 innerMD5;
/**
* Constructor
*/
HMAC_MD5(byte key[])
{
int kLen = key.length;
// if key is longer than 64 bytes reset it to key=MD5(key)
if (kLen > 64)
{
MD5 md5 = new MD5();
md5.update(key);
key = md5.digest();
}
kIpad = new byte[64]; // inner padding - key XORd with ipad
kOpad = new byte[64]; // outer padding - key XORd with opad
// start out by storing key in pads
System.arraycopy(key, 0, kIpad, 0, kLen);
System.arraycopy(key, 0, kOpad, 0, kLen);
// XOR key with ipad and opad values
for (int i = 0; i < 64; i++)
{
kIpad[i] ^= 0x36;
kOpad[i] ^= 0x5c;
}
clear(); // Initialize the first digest.
}
/**
* Clear the HMAC_MD5 object.
*/
public void clear()
{
innerMD5 = new MD5();
innerMD5.update(kIpad); // Intialize the inner pad.
digest = null; // mark the digest as incomplete.
}
/**
* HMAC_MD5 function.
*
* @param text Text to process
*
* @param key Key to use for HMAC hash.
*
* @return hash
*/
public void addData(byte text[])
{
addData(text, 0, text.length);
}
/**
* HMAC_MD5 function.
*
* @param text Text to process
*
* @param textStart Start position of text in text buffer.
* @param textLen Length of text to use from text buffer.
* @param key Key to use for HMAC hash.
*
* @return hash
*/
public void addData(byte text[], int textStart, int textLen)
{
innerMD5.update(text, textStart, textLen); // then text of
datagram.
}
public byte [] sign()
{
MD5 md5;
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
// Perform inner MD5
digest = innerMD5.digest(); // finish up 1st pass.
// Perform outer MD5
md5 = new MD5(); // Init md5 for 2nd pass.
md5.update(kOpad); // Use outer pad.
md5.update(digest); // Use results of first
pass.
digest = md5.digest(); // Final result.
return digest;
}
/**
* Validate a signature against the current digest.
* Compares the hash against the signature.
*
* @param signature
*
* @return True if the signature matches the calculated hash.
*/
public boolean verify(byte signature[])
{
// The digest may not have been calculated. If it's null, force
a calculation.
if (digest == null)
sign();
int sigLen = signature.length;
int digLen = digest.length;
if (sigLen != digLen)
return false; // Different lengths, not a good sign.
for (int i = 0; i < sigLen; i++)
if (signature[i] != digest[i])
return false; // Mismatch. Misfortune.
return true; // Signatures matched. Perseverance furthers.
}
/**
* Return the digest as a HEX string.
*
* @return a hex representation of the MD5 digest.
*/
public String toString()
{
// If not already calculated, do so.
if (digest == null)
sign();
StringBuffer r = new StringBuffer();
final String hex = "0123456789ABCDEF";
byte b[] = digest;
for (int i = 0; i < 16; i++)
{
int c = ((b[i]) >>> 4) & 0xf;
r.append(hex.charAt(c));
c = ((int)b[i] & 0xf);
r.append(hex.charAt(c));
}
return r.toString();
}
}
/* END SOURCE CODE */
The class listing above goes beyond your initial request in that it is
able to generate an encrypted key as well as convert it back to the
fields initially input into the function. I believe you will require
this as well in order to decrypt your data at a later point. The
main() program gives you an idea of how to use the enclosed methods to
encrypt/decrypt your information.
Hope that serves your purpose....if you require any clarification,
please do not hesitate to ask :)
------------------------------------
Search Terms (Google):
"HMAC-MD5" hash function algorithm
------------------------------------
Cheers!
answerguru-ga |