/*
 * 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 ERServer;

import cryptix.provider.key.RawSecretKey;
import cryptix.provider.padding.OneAndZeroes;
import cryptix.provider.cipher.Blowfish;
import cryptix.util.core.Hex;

import xjava.security.Cipher;
import xjava.security.FeedbackCipher;
import xjava.security.SecretKey;

import java.security.*;

import Free.util.StringByteTools;

/**
 * AuthKey calculates and communicates the GNU.FREE authorisation key which
 * helps to secure the system against attacks through reverse engineering the
 * client program. It also is used to improve the reliability so that we can
 * reduce the number of users who lose the chance to vote through crashes on
 * their computers.
 *
 * Encryption is done with a symmetric cipher provided by <a href="http://www.cryptix.org">The
 * Cryptix Foundation</a>.
 *
 * @version 0.3  7 February 2001
 * @author Jason Kitcat
 * @since 1.4
 */
public class AuthKey {

	/**
	 * IMPORTANT SECURITY ISSUE:
	 * The three constants below must be changed for each election. The easiest way to
	 * generate the correct keys and passphrases is to use the <code>FreeInstall</code>
	 * program included with FREE.
	 */

	// stores keys for the AuthKey system
//#ifdef INSTALL
	private static final String skey1 = "F1E1D2C2B4A5968778A95A4B3C221E0F003122";
//#ifdef INSTALL
	private static final String skey2 = "FB4A210D1D2C7840E1D2C3B4A5968778695A4B";

	// stores password for MAC portion of key
//#ifdef INSTALL
	private static final String MACpass = "p0rpleturn1p";

	/**
	 * Initialises crypto etc
	 */
	 protected static void init() {

	 	try {
			java.security.Security.addProvider(new cryptix.provider.Cryptix());
		} catch(Exception e) {
			ERServer.NORM.error("AuthSys initialistion error: " + e.toString());
		}
		
	 } //eof init()
	 
	 
	/**
	* Builds an <code>AuthKey</code> from the user data provided. The following
	* process is used to build a FREE AuthKey:
	*
	* A message digest of the <code>Roll</code> entry (i.e. the three String parameters to
	* this method) and the <code>MACpass</code> is created.
	*
	* Then a message digest of the first digest concatenated with the <code>MACpass</code>
	* password is created.
	*
	* The result is then encrypted with one of two secret keys as specified by <code>key</code>.
	*
	* Note the we minimise our reliance on the Cryptix tools - all possible security is done with
	* standard Sun algorithms. This is in case export restrictions make Cryptix removal necessary.
	*
	* @param name  The user's name as from the <code>Roll</code> database table
	* @param code  A unique pin code for the user, also from the database
	* @param pword  A password for the user, also from the database
	* @param whichKey  Indicates whether to use secret key 1 or 2
	* @returns String with a finished AuthKey
	*/
	protected static String build(String name, String code, String pword, int whichKey) throws Exception {
	  				
		RawSecretKey key;
	 	String digest;
	 	byte[] ect;
	 	
		Cipher blowalg = Cipher.getInstance(new Blowfish(),null,new OneAndZeroes());
	 	
	 	MessageDigest md = MessageDigest.getInstance("SHA-1");
	 	
	 	byte dataBytes[] = StringByteTools.asciiGetBytes(name + code + pword);
	 	byte passBytes[] = StringByteTools.asciiGetBytes(MACpass);
	 	md.update(passBytes);
	 	md.update(dataBytes);
	 	byte digest1[] = md.digest();
	 	
	 	md.update(passBytes);
	 	md.update(digest1);
	 	byte mac[] = md.digest();
	 		 		 	
		/* build a Blowfish (16-round) key using ECB */
		// ECB is ok to use as this data is random(ish) as it's been through a
		// message digest. No repeating groups to help cryptanalysis.
		if (whichKey==1) {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey1));
		} else {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey2));
        }
        
		blowalg.initEncrypt(key);
		ect = blowalg.crypt(mac);
		
		return Hex.toString(ect);
	  
	} //eof build()
	

	/**
	* Decrypts a key - but note doesn't reveal full origins as the decrypted key is merely the MAC
	* and not plain text.
	*
	* @param akey  The key to decrypt
	* @param whichKey  Indicates whether to use secret key 1 or 2
	* @returns String with a decrypted AuthKey
	*/
	protected static String decrypt(String akey, int whichKey) throws Exception {

		RawSecretKey key;
	 	byte[] dect;
		Cipher blowalg = Cipher.getInstance(new Blowfish(),null,new OneAndZeroes());
	 	
		/* build a Blowfish (16-round) key using ECB */
		if (whichKey==1) {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey1));
		} else {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey2));
        }
        
		blowalg.initDecrypt(key);
		dect = blowalg.crypt(Hex.fromString(akey));

		return Hex.toString(dect);

	} //eof decrypt()
	
	
	/**
	* Encrypts a key - for use when exporting the keys
	*
	* @param akey  The key to encrypt
	* @param whichKey  Indicates whether to use secret key 1 or 2
	* @returns String with a encrypted AuthKey
	*/
	protected static String encrypt(String akey, int whichKey) throws Exception {

		RawSecretKey key;
	 	byte[] ect;
		Cipher blowalg = Cipher.getInstance(new Blowfish(),null,new OneAndZeroes());
	 	
		/* build a Blowfish (16-round) key using ECB */
		// ECB is ok to use as this data is random(ish) as it's been through a
		// message digest. No repeating groups to help cryptanalysis.
		if (whichKey==1) {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey1));
		} else {
			key = new RawSecretKey("Blowfish", Hex.fromString(skey2));
        }
        
		blowalg.initEncrypt(key);
		ect = blowalg.crypt(Hex.fromString(akey));

		return Hex.toString(ect);

	} //eof encrypt()
	
	
} //eof AuthKey