package pt.link.crypto;

import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import sun.misc.BASE64Decoder;

public class CryptoUtils {
	static Log log = LogFactory.getLog(CryptoUtils.class);

	/**
	 * 
	 */
	public static String cipher(String text, byte[] keyBytes) throws CryptoException{
		try {
			Cipher ecipher = Cipher.getInstance("DES");
			
			SecretKey key = new SecretKeySpec(keyBytes, "DES");
			ecipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] enc = ecipher.doFinal(text.getBytes("UTF8"));
			return new sun.misc.BASE64Encoder().encode(enc);
		} catch (Exception e) {
			String errorMessage = "Exception cauhth while deCiphering";
			log.error(errorMessage, e);
			throw new CryptoException();
		} 
	}
	
	public static String deCipher(String text, byte[] keyBytes) throws CryptoException{
		try {
			byte enc[] = new BASE64Decoder().decodeBuffer(text);
			Cipher ecipher = Cipher.getInstance("DES");
			SecretKey key = new SecretKeySpec(keyBytes, "DES");
			ecipher.init(Cipher.DECRYPT_MODE, key);
			byte[] unEnc = ecipher.doFinal(enc);
			return new String(unEnc, "UTF8");
		} catch (Exception e) {
			String errorMessage = "Exception cauhth while deCiphering";
			log.error(errorMessage, e);
			throw new CryptoException();
		} 
	}
	
	
	public static void generateSecretKey() throws CryptoException{
		try {
			KeyGenerator keyGen = KeyGenerator.getInstance("DES");
			keyGen.init(56); // 56 is the keysize. Fixed for DES
			SecretKey key = keyGen.generateKey();
			byte []encoded = key.getEncoded(); 
			
			System.out.println(stringArrayToString(toHexStringArray(encoded)));

		} catch (NoSuchAlgorithmException e) {
			String errorMessage = "Exception cauhth while producing digest";
			log.error(errorMessage, e);
			throw new CryptoException();
		}
	}

	public static byte[] keyBytes = {-0x39,-0x27,0x73,-0x20,-0x4a,0x4,0x61,-0x9};
	
	private static String byteToString(int b, int radix){
		char mapping[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
		int mask = 0x0F;
	
		StringBuffer buf = new StringBuffer();
		
		byte firstBlock = (byte) ( (b >>> 4) & mask);
		buf.append(mapping[firstBlock]);
		byte secondBlock = (byte) ( (b) & mask);
		buf.append(mapping[secondBlock]);
		if(buf.length() > 2)
			System.out.println("Alert");
		return buf.toString();
	}
	
	public static String[] toHexStringArray(byte hex[]){
		String strArray[] = new String[hex.length];
		for(int i=0;i<hex.length;i++){
				strArray[i] = byteToString(hex[i], 16);
		}
		return strArray;
	}
	
	public static byte[] hexStringToByteArray(String hexString){
		byte b[] = new byte[hexString.length()/2];
		for(int i=0;i<hexString.length();i+=2){
			byte high = (byte) Character.digit(hexString.charAt(i), 16);
			byte low = (byte) Character.digit(hexString.charAt(i + 1), 16);
			//System.out.println("" + high + "." + low);
			b[i/2] = (byte) ((high << 4) + low);
			//System.out.println("b[" + i/2 + "]="+ b[i/2]);
		}
		return b;
	}
	
	public static String dumpHexString(String hex[]){
		StringBuffer buf=new StringBuffer();
		buf.append("byte generatedKey[] = {");
		
		for(int i=0;i<hex.length;i++){
			if(hex[i].indexOf("-")==-1){
				buf.append("0x");
				buf.append(hex[i]);
			}
			else{
				buf.append("-0");
				buf.append(hex[i].replace('-', 'x'));
			}
			if(i+1!=hex.length)
				buf.append(",");
			else
				buf.append("}");
		}
		return(buf.toString());
	}
	
	public static String stringArrayToString(String array[]){
		StringBuffer buf = new StringBuffer();
		for(int i=0;i<array.length;i++){
			buf.append(array[i]);
		}
		return buf.toString();
	}
	
//	public static void main(String[] args) {
//		String hexString = "7F77DB3331C541064957DE42343140A0A7DDDFF9";
//		System.out.println(hexString);
//		System.out.println(stringArrayToString(CryptoUtils.toHexStringArray(CryptoUtils.hexStringToByteArray(hexString))));
//	}

	public static void main(String[] args) throws CryptoException {
		if (args.length < 1) {
			System.out.println("usage: java CryptoUtils genKey");
			System.out.println("       java CryptoUtils cipher <text>");
		}
		String text = args[0];
		if(text.equalsIgnoreCase("genKey")){
			System.out.println(text);
			generateSecretKey();
		}
		if(text.equalsIgnoreCase("cipher") && args.length >=2){
			StringBuffer buf = new StringBuffer();
			for(int i = 1;i<args.length;i++){
				buf.append(args[i]);
			}
			String textToCipher = buf.toString();
			System.out.println("textToCipher: " + textToCipher);
			String inHex[] = toHexStringArray(textToCipher.getBytes());
			System.out.println(stringArrayToString(inHex));
			String enc = cipher(textToCipher, keyBytes);
			System.out.println("enc: " + enc);
		}
		
		if(text.equalsIgnoreCase("decipher") && args.length >=2){
			String deciphered = deCipher(args[1], keyBytes);
			System.out.println("deciphered = " + deciphered);
		}
		
		byte generatedKey[] = {-0x4d,-0x80,-0x14,-0x6f,0x31,0x16,-0xe,0x52, 0xA, 0x00};
		System.out.println("--");
		System.out.println(stringArrayToString(toHexStringArray(generatedKey)));
		System.out.println(dumpHexString(toHexStringArray(generatedKey)));
	}
}
