/*
 * GNU.FREE 2002
 *
 * Copyright (c) 1999, 2000, 2001, 2002
 * The Free Software Foundation (www.fsf.org)
 *
 * GNU.FREE Co-ordinator: Jason Kitcat <jeep@free-project.org>
 *
 * GNU site: http://www.gnu.org/software/free/
 * 
 * FREE e-democracy site: http://www.free-project.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program (COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
  
package Free.util;

import java.security.*;
import xjava.security.Parameterized;

import cryptix.provider.mac.*;

/**
 * The AuthSys Class implements a Message Authentication Code system (MAC).
 *
 * AuthSys creates its MAC based on the SHA-1 algorithm included as part of
 * <code>java.security</code> which comes with all Java implementations and
 * is not subject to restrictions. Essentially a message digest of a packet's
 * data portion is created. Then a new message digest of the previous digest
 * concatenated with a passphrase is created. This is returned to be added to
 * packets elsewhere.
 *
 * @version 0.7  29 August 2001
 * @author Jason Kitcat
 */
public class AuthSys {

	/** Passphrase for creating MAC */
//#ifdef INSTALL
	private static final String phrase = "democracy";
	/* SECURITY NOTE: VERY IMPORTANT! */
	// This passphrase *MUST* be changed before you implement GNU.FREE
	// for your election. Otherwise the message digests used as
	// part of the security system to prevent vote tampering will
	// be undermined.
	
	
	/**
	 * creates a MAC to detect tampering
	 *
	 * @param data  The data being sent in the packet
	 * @return    A string containing the MAC
	 */
	 public static String makeDigest(String data) throws Exception {
	 
	 	MessageDigest md = MessageDigest.getInstance("SHA-1");
	 	
	 	byte dataBytes[] = StringByteTools.asciiGetBytes(data);
	 	byte passBytes[] = StringByteTools.asciiGetBytes(phrase);
	 	
	 	md.update(passBytes);
	 	md.update(dataBytes);
	 	byte digest1[] = md.digest();
	 	
	 	md.update(passBytes);
	 	md.update(digest1);
	 	byte mac[] = md.digest();
	 		 	
		/* convert to hex */
	 	StringBuffer hexString = new StringBuffer(100);
	 	for (int i=0;i<mac.length;i++) {
	 		hexString.append(Integer.toHexString(0xFF & mac[i]));
	 	}
	 	
	 	return hexString.toString();
	 
	 } //EOF makeDigest


	/**
	 * analyses MAC to ensure packets haven't been tampered.
	 *
	 * Simply calls <code>makeDigest</code> and compares the result with
	 * the digest portion of the <code>Packet</code> supplied.
	 *
	 * @param  pack  The packet, including message digest
	 * @return    A boolean depending on whether the packet is ok.
	 */
	 public static boolean checkDigest(Packet pack) throws Exception {
	 
	 	boolean ok=false;
	 	
	 	String origDigest = pack.getDigest();
	 	
	 	String mac = makeDigest(pack.getMACMessage());		

	 	if (mac.equals(origDigest)) {
	 		ok = true;
	 	}
	 	
	 	return ok;
	 
	 } //EOF checkDigest
	 
	 
	 /**
	  * creates a HMAC to detect tampering.
	  *
	  * @param data  The data being sent in the packet
	  * @param key   Key to be used in creating the HMAC
	  * @param seq_no  Sequence number of the packet
	  * @return  A string containing the HMAC
	  */
	  public static String makeHMAC(String data, String key, int seq_no) throws Exception {
	  
	 	MessageDigest md = MessageDigest.getInstance("HMAC-SHA-1");
	 	
	 	byte dataBytes[] = StringByteTools.asciiGetBytes(data);  // Convert to bytes
	 	byte keyBytes[] = StringByteTools.asciiGetBytes(key);
	 	byte seqBytes[] = StringByteTools.asciiGetBytes(new Integer(seq_no).toString());
	 	
		((Parameterized) md).setParameter("key", keyBytes);  // Set key

	 	md.update(seqBytes);
	 	md.update(dataBytes);
	 	byte digest1[] = md.digest();
	 	
	 	md.update(seqBytes);
	 	md.update(digest1);
	 	byte mac[] = md.digest();
	 		 	
		/* convert to hex */
	 	StringBuffer hexString = new StringBuffer(100);
	 	for (int i=0;i<mac.length;i++) {
	 		hexString.append(Integer.toHexString(0xFF & mac[i]));
	 	}
	 	
	 	return hexString.toString();

	  } //EOF makeHMAC


	/**
	 * analyses HMAC to ensure packets haven't been tampered.
	 *
	 * Simply calls <code>makeHMAC</code> and compares the result with
	 * the digest portion of the <code>Packet</code> supplied.
	 *
	 * @param  pack  The packet, including message digest
	 * @param key  Key used in making the HMAC
	 * @param seq_no  Sequence number of the packet
	 * @return    A boolean depending on whether the packet is ok.
	 */
	 public static boolean checkHMAC(Packet pack, String key, int seq_no) throws Exception {
	 
	 	boolean ok=false;
	 	
	 	String origDigest = pack.getDigest();
	 	
	 	String mac = makeHMAC(pack.getMACMessage(),key,seq_no);		

	 	if (mac.equals(origDigest)) {
	 		ok = true;
	 	}
	 	
	 	return ok;
	 
	 } //EOF checkHMAC
	 
	 
	 /**
	  * Turns seed into a key for HMAC
	  *
	  * @param  seed  String holding the seed-value
	  * @return  A string holding the HMAC key
	  */
	  public static String seedToKey(String seed) throws Exception {
	  
	 	MessageDigest md = MessageDigest.getInstance("SHA-1");
	 	
	 	byte seedBytes[] = StringByteTools.asciiGetBytes(seed);
	 	byte passBytes[] = StringByteTools.asciiGetBytes(phrase);
	 	
	 	md.update(seedBytes);
	 	md.update(passBytes);
	 	byte digest1[] = md.digest();
	 	
	 	md.update(passBytes);
	 	md.update(digest1);
	 	byte mac[] = md.digest();
	 		 	
		/* convert to hex */
	 	StringBuffer hexString = new StringBuffer(100);
	 	for (int i=0;i<mac.length;i++) {
	 		hexString.append(Integer.toHexString(0xFF & mac[i]));
	 	}
	 	
	 	return hexString.toString();
	  
	  } //EOF seedToKey
	 
} //EOF Class