/*	-----------------------------------------------------------------------------
	TestBlowfish.java
	
	Copyright ©1997, Type & Graphics Pty Limited. All rights reserved.
	----------------------------------------------------------------------------- */
 
package cryptix.test;


import cryptix.security.ByteArrayKey;
import cryptix.util.Util;

import java.security.Cipher;

/**
 *	Tests the output of the Blowfish cipher algorithm implementation against
 *	certified pre-computed output for a given set of reference input.
 *
 *	@revision	1.0 --June 97
 *	@author		Raif S. Naffah
 */
public final class TestBlowfish
{

// Variables and constants
//................................................................................

	private static Cipher alg;

	private static final String[][]
	testData1 = {
	//	 key				 plain text		  	 cipher text (ECB)
	//   ..................  ..................  ..................
		{"0000000000000000", "0000000000000000", "4EF997456198DD78"},
		{"FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"},
		{"3000000000000000", "1000000000000001", "7D856F9A613063F2"},
		{"1111111111111111", "1111111111111111", "2466DD878B963C9D"},
		{"0123456789ABCDEF", "1111111111111111", "61F9C3802281B096"},
		{"1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7"},
		{"0000000000000000", "0000000000000000", "4EF997456198DD78"},
		{"FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D"},
		{"7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B"},
		{"0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"},
		{"07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4"},
		{"3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB"},
		{"04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A"},
		{"0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918"},
		{"0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98"},
		{"43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5"},
		{"07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79"},
		{"04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3"},
		{"37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969"},
		{"1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B"},
		{"584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E"},
		{"025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD"},
		{"49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019"},
		{"4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3"},
		{"49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5"},
		{"018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778"},
		{"1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201"},
		{"0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2"},
		{"1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE"},
		{"E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D"},
		{"0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4"},
		{"FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC"},
		{"0123456789ABCDEF", "0000000000000000", "245946885754369A"},
		{"FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A"}
	},
	testData2 = {
	//	 cipher text (ECB)	 key
	//   ..................  ......................................
		{"F9AD597C49DB005E", "F0"},
		{"E91D21C1D961A6D6", "F0E1"},
		{"E9C2B70A1BC65CF3", "F0E1D2"},
		{"BE1E639408640F05", "F0E1D2C3"},
		{"B39E44481BDB1E6E", "F0E1D2C3B4"},
		{"9457AA83B1928C0D", "F0E1D2C3B4A5"},
		{"8BB77032F960629D", "F0E1D2C3B4A596"},
		{"E87A244E2CC85E82", "F0E1D2C3B4A59687"},
		{"15750E7A4F4EC577", "F0E1D2C3B4A5968778"},
		{"122BA70B3AB64AE0", "F0E1D2C3B4A596877869"},
		{"3A833C9AFFC537F6", "F0E1D2C3B4A5968778695A"},
		{"9409DA87A90F6BF2", "F0E1D2C3B4A5968778695A4B"},
		{"884F80625060B8B4", "F0E1D2C3B4A5968778695A4B3C"},
		{"1F85031C19E11968", "F0E1D2C3B4A5968778695A4B3C2D"},
		{"79D9373A714CA34F", "F0E1D2C3B4A5968778695A4B3C2D1E"},
		{"93142887EE3BE15C", "F0E1D2C3B4A5968778695A4B3C2D1E0F"},
		{"03429E838CE2D14B", "F0E1D2C3B4A5968778695A4B3C2D1E0F00"},
		{"A4299E27469FF67B", "F0E1D2C3B4A5968778695A4B3C2D1E0F0011"},
		{"AFD5AED1C1BC96A8", "F0E1D2C3B4A5968778695A4B3C2D1E0F001122"},
		{"10851C0E3858DA9F", "F0E1D2C3B4A5968778695A4B3C2D1E0F00112233"},
		{"E6F51ED79B9DB21F", "F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344"},
		{"64A6E14AFD36B46F", "F0E1D2C3B4A5968778695A4B3C2D1E0F001122334455"},
		{"80C7D7D45A5479AD", "F0E1D2C3B4A5968778695A4B3C2D1E0F00112233445566"},
		{"05044B62FA52D080", "F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677"}
	};

// Constructor
//................................................................................
	
	public TestBlowfish () {
		System.out.println("*** Blowfish:\n");
		try {
			test1();
			test2();
			test3();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}


// main/test methods
//................................................................................
	
	public static final void main (String[] args) {
		Util.installDefaultProviders();
		try {
			alg = Cipher.getInstance("Blowfish", "Cryptix");
			TestBlowfish x = new TestBlowfish();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}
	
	private void test1 ()
	throws Exception {
		
		System.out.println("*** Blowfish (16-round) in ECB mode 1/2:\n");
		byte[] ect, dct;
		String a, b;

		for (int i = 0; i < testData1.length; i++) {
			ByteArrayKey key = new ByteArrayKey(Util.fromHexString(testData1[i][0]));
		
			alg.initEncrypt(key);
			ect = alg.crypt(Util.fromHexString(testData1[i][1]));
			a = Util.toHexString(ect);
			alg.initDecrypt(key);
			dct = alg.crypt(ect);
			b = Util.toHexString(dct);
			
			System.out.print("  plain: " + testData1[i][1] +
				", cipher: " + a + ", cert: " + testData1[i][2]);

			if (a.equals(testData1[i][2]))
				System.out.println(" *** Enc. GOOD" );
			else
				System.out.println(" *** Enc. FAILED");
		
			System.out.print(" cipher: " + Util.toHexString(ect) +
				",  plain: " + b + ", cert: " + testData1[i][1]);
			
			if (b.equals(testData1[i][1]))
				System.out.println(" *** Dec. GOOD\n");
			else
				System.out.println(" *** Dec. FAILED\n");
		}
	}
	
	private void test2 ()
	throws Exception {
		
		System.out.println("\n*** Blowfish (16-round) in ECB mode 2/2:\n");
		byte[] ect, input = Util.fromHexString("FEDCBA9876543210");
		String a;

		for (int i = 0; i < testData2.length; i++) {
			ByteArrayKey key = new ByteArrayKey(Util.fromHexString(testData2[i][1]));
		
			alg.initEncrypt(key);
			ect = alg.crypt(input);
			a = Util.toHexString(ect);
			
			System.out.print("  plain: FEDCBA9876543210, cipher: " + a +
				" cert: " + testData2[i][0]);

			if (a.equals(testData2[i][0]))
				System.out.println(" *** GOOD" );
			else
				System.out.println(" *** FAILED");
		}
	}
	
	private void test3 ()
	throws Exception {

		String
			a,
			in = "37363534333231204E6F77206973207468652074696D6520666F722000",
			o1 = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC",
			o2 = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3",
			o3 = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA";
		byte[]
			ect,
			input = Util.fromHexString(in),
			iv = Util.fromHexString("FEDCBA9876543210"),
			key = Util.fromHexString("0123456789ABCDEFF0E1D2C3B4A59687");
		ByteArrayKey k = new ByteArrayKey(key);

		System.out.println("\n*** Blowfish (16-round) in CBC mode:\n");
		alg = Cipher.getInstance("Blowfish/CBC", "Cryptix");
		alg.setInitializationVector(iv);
		alg.initEncrypt(k);
		// for CBC we need an input array whose length is x8
		// implicetly we'll pad with 0x00
		byte[] newIn = new byte[32];
		System.arraycopy(input, 0, newIn, 0, input.length);
		ect = alg.crypt(newIn);
		a = Util.toHexString(ect);
		System.out.println("  plain: " + in);
		System.out.println(" cipher: " + a);
		System.out.println("   cert: " + o1);
		if (a.equals(o1))
			System.out.println(" *** GOOD" );
		else
			System.out.println(" *** FAILED");

		System.out.println("\n*** Blowfish (16-round) in CFB mode:\n");
		alg = Cipher.getInstance("Blowfish/CFB", "Cryptix");
		alg.setInitializationVector(iv);
		alg.initEncrypt(k);
		ect = alg.crypt(input);
		a = Util.toHexString(ect);
		System.out.println("  plain: " + in);
		System.out.println(" cipher: " + a);
		System.out.println("   cert: " + o2);
		if (a.equals(o2))
			System.out.println(" *** GOOD" );
		else
			System.out.println(" *** FAILED");

		System.out.println("\n*** Blowfish (16-round) in OFB mode:\n");
		alg = Cipher.getInstance("Blowfish/OFB", "Cryptix");
		alg.setInitializationVector(iv);
		alg.initEncrypt(k);
		ect = alg.crypt(input);
		a = Util.toHexString(ect);
		System.out.println("  plain: " + in);
		System.out.println(" cipher: " + a);
		System.out.println("   cert: " + o3);
		if (a.equals(o3))
			System.out.println(" *** GOOD" );
		else
			System.out.println(" *** FAILED");
	}	
}


