//package 

/*
 * @(#)HmacUtils.java	0.51 1999/07/14
 *
 * Copyright (c) 2000, Pat Farrell and friends.  All rights reserved.
 *  This code is free for anyone to use, provided this copyright and       
 *  statement are left attached.                                           
 *                                   
 */
 
import java.security.*;
/**
 * this class implements the HMAC code
 * defined by RFC 2104
 */
abstract public class HmacUtils {
/** block length specified by the RFC */
    public static final int RFC_B_len = 64;
    
    /**
     *  toHexes the given bytes array, and returns it as a String.
     * @param bug an array of bytes (eight bit octets) 
     * @return hex encoded equivalent
     */ 
    public static String hexify (byte [] buf)
    {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++)
        {
            Byte b= new Byte(buf[i]);                        
            String s = Integer.toHexString(b.intValue());
            if (s.length() == 1)
                s = "0" + s;
            if (s.length()>2)    
                s= s.substring(s.length()-2);                    
            sb.append(s);
        }
        return sb.toString();
    }
    
    
    /**
     * calculate an HMAC using the SHA1 algorithm.
     *  Given a secret and message, returns a sha1 hash of the message.
     * @param secret string known to both parties
     * @param message to sign
     * @return hexified result
     */ 
    public static String hmac (String secret, String message) {
        return hmac(secret, message.getBytes());
    }
    
    /**
     * calculate an HMAC using the SHA1 algorithm.
     *  Given a secret and message, returns a sha1 hash of the message.
     * @param secret string known to both parties
     * @param message byte array of message to sign
     * @return hexified result
     */ 
    public static String hmac (String secret, byte[] message)
    {
        byte[][] paddedKeys = fixupKey(secret);
        byte[] gas = null;
        try
        {
            MessageDigest digest = MessageDigest.getInstance("SHA1");
            digest.update (paddedKeys[0]);
            digest.update (message);
            byte[] innerHash = digest.digest();
            digest.update (paddedKeys[1]);
            digest.update (innerHash);
            gas = digest.digest();
            
        } catch (Exception e) {
            System.out.println ("WebUtils.sha1 - caught exception: " + e.toString());       
        }
        return hexify(gas);        
    }         
/**
 * create the properly padded arrays of bytes from the input secret.
 * the RFC hints that these may be saved, but the code looks like it
 * will be quick on any modern CPU
 * @param secret the incomming key
 * @return a matric of bytes, [0] contains the ipad and [1] contains the opad
 */
    private static byte[][] fixupKey(String secret) {
        // shorten too long key here if you want to be by the book
        if ( secret.length() > RFC_B_len) throw new IllegalArgumentException();
        
        byte[] ipad = new byte[RFC_B_len];
        byte[] opad = new byte[RFC_B_len];

        for ( int i = 0; i < RFC_B_len; i++) {
            if ( i < secret.length() ) {
                byte b = (byte)secret.charAt(i);
                ipad[i] = (byte)( b ^ 0x36);
                opad[i] = (byte)( b ^ 0x5c);
            } 
            else {
                ipad[i] = 0x36;
                opad[i] = 0x5c;
            } 
            
        }
        byte[][] rval = new byte[2][];
        rval[0] = ipad;
        rval[1] = opad;
        return rval;
    }
/**
 * usual test program
 * Test data comes from RFC2202, available {@link "http://www.faqs.org/rfcs/rfc2202.html"}
 */
    public static void main(String[] args) {
        
        try {
            byte [][] keybytes = { {0x0b,0x0b,0x0b,0x0b,0x0b, 0x0b,0x0b,0x0b,0x0b,0x0b, /* rfc test 1 */
                                    0x0b,0x0b,0x0b,0x0b,0x0b, 0x0b,0x0b,0x0b,0x0b,0x0b}, 
                                    "Jefe".getBytes(), /* rfc test 2 */
                                   {0x0c,0x0c,0x0c,0x0c,0x0c, 0x0c,0x0c,0x0c,0x0c,0x0c, /* rfc test 5 */
                                    0x0c,0x0c,0x0c,0x0c,0x0c, 0x0c,0x0c,0x0c,0x0c,0x0c} 
                                    };

            String key = new String(keybytes[0]);
            String data =          "Hi There";
            String digest =        "b617318655057264e28bc0b6fb378c8ef146be00";
            String testval = hmac(key, data);
            System.out.println("1= " + testval);
            System.out.println("   " + digest);
            
            key = new String(keybytes[1]);
            data =            "what do ya want for nothing?";
            String digest2 =  "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79";
            testval = hmac(key, data);
            System.out.println("2= " + testval);
            System.out.println("   " + digest2);
            
            data =          "Test With Truncation";
            key = new String(keybytes[2]);
            testval = hmac(key, data);

            String digest5 = "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04";
            System.out.println("5= " + testval);
            System.out.println("   " + digest5);

            
        } catch (Exception e) {
            System.err.println("main caught " + e);
            e.printStackTrace();
        }
        System.exit(0);
    }
 
}

