/**
 *
 * JAVA FILE ENCRYPTION (JCE USAGE)
 *
 * @author Matthew W. Coan
 * @version Sat May 18 19:57:22 EDT 2013
 *
 */
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import java.io.*;
public class fcrypt
{    
	public static final int BUFFER_SIZE = 1024 * 10;

	public static void main(String[] argv) {
		try{
                    boolean genKey = false;
                    boolean doEncrypt = false;
                    boolean gotEncrypt = false;
                    String infile = "";
                    String outfile = "";
                    String keyfile = "";
                    String cypherName = "des3";
                    for(int i = 0; i < argv.length; i++) {
                       if(argv[i].compareTo("-encrypt") == 0) {
                          doEncrypt = true;
                          gotEncrypt = true;
                       }
                       else if(argv[i].compareTo("-decrypt") == 0) {
                          doEncrypt = false;
                          gotEncrypt = true;
                       }
                       else if(argv[i].compareTo("-genkey") == 0) {
                          genKey = true;
                          if(i+1 < argv.length) {
                             keyfile = argv[i+1];
                             i++;
                          }
                       }
                       else if(argv[i].compareTo("-i") == 0) {
                          if(i+1 < argv.length) {
                             infile = argv[i+1];
                             i++;
                          }
                       }
                       else if(argv[i].compareTo("-o") == 0) {
                          if(i+1 < argv.length) {
                             outfile = argv[i+1];
                             i++;
                          }
                       }
                       else if(argv[i].compareTo("-key") == 0) {
                          if(i+1 < argv.length) {
                             keyfile = argv[i+1];
                             i++;
                          }
                       }
                       else if(argv[i].compareTo("-c") == 0) {
                          if(i+1 < argv.length) {
                             cypherName = argv[i+1];
                             i++;
                          }
                       }
                       else if(argv[i].compareTo("-help") == 0 || argv[i].compareTo("-h") == 0) {
                          System.out.println("usage: des3 [ -genkey keyfile ] [ -c des|des3|blowfish ] "
                                             + "-key keyfile -i infile -o outfile -encrypt | -decrypt");
                          System.exit(0);
                       }
                    }
                    if(genKey) {
                       if(keyfile.equals("")) {
                          System.err.println("Please supply a key file...");
                          System.exit(0);
                       }
                    }
                    else {
                       if(keyfile.equals("")) {
                          System.err.println("Please supply a key file...");
                          System.exit(0);
                       }
                       if(infile.equals("")) {
                          System.err.println("Please supply a input file...");
                          System.exit(0);
                       }
                       if(outfile.equals("")) {
                          System.err.println("Please supply an output...");
                          System.exit(0);
                       }
                    }
                    if(!gotEncrypt && !genKey) {
                       System.err.println("Please specify: -encrypt | -decrypt");
                       System.exit(1);
                    }
                    String cn = ""; 
                    String cn2 = "";
                    if(cypherName.equals("des")) {
                       cn = "DES";
                       cn2 = "DES";
                    }
                    else if(cypherName.equals("des3") || cypherName.equals("3des")) {
                       cn = "TripleDES";
                       cn2 = "TripleDES/ECB/PKCS5Padding";
                    }
                    else if(cypherName.equals("blowfish")) {
                       cn = "Blowfish";
                       cn2 = "Blowfish";
                    }
                    else {
                          System.err.println("Bad cypher name...");
                          System.exit(0);
                    }
		    KeyGenerator keygenerator = KeyGenerator.getInstance(cn);
		    SecretKey myDesKey;
                    if(genKey) {
		    	myDesKey = keygenerator.generateKey();
                        new File(keyfile).delete();
                        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(keyfile));
                        out.writeObject(myDesKey);
                        out.flush();
                        out.close();
                        System.exit(0);
                    }
                    else {
                        ObjectInputStream in = new ObjectInputStream(new FileInputStream(keyfile));
                        myDesKey = (SecretKey)in.readObject();
                        in.close();
                    }
		    Cipher desCipher;
		    // Create the cipher 
		    desCipher = Cipher.getInstance(cn2);
                    if(doEncrypt) {
		       // Initialize the cipher for encryption
		       desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);
		       //sensitive information
                       File theFile = new File(infile);
                       FileInputStream in = new FileInputStream(theFile);
                       long length = theFile.length();
                       byte[] text;
                       ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(outfile));
                       while(length > 0) {
                          if(length < BUFFER_SIZE) {
                             text = new byte[(int)length];
                          }
                          else {
                             text = new byte[BUFFER_SIZE];
                          }
                          in.read(text); 
		          // Encrypt the text
		          byte[] textEncrypted = desCipher.doFinal(text);
                          out.writeObject(textEncrypted);
                          out.flush();
                          length -= BUFFER_SIZE;
                       }
                       in.close();
                       out.close();
                    }
                    else {
		       // Initialize the same cipher for decryption
		       desCipher.init(Cipher.DECRYPT_MODE, myDesKey);
		       // Decrypt the text
                       ObjectInputStream in = new ObjectInputStream(new FileInputStream(infile));
                       FileOutputStream out = new FileOutputStream(outfile);
                       try {
                          while(true) {
                             byte[] textEncrypted = (byte[])in.readObject();
		             byte[] textDecrypted = desCipher.doFinal(textEncrypted);
                             out.write(textDecrypted);
                             out.flush();
                          }
                       }
                       catch(EOFException eof) {

                       }
                       in.close();
                       out.close();
                    }
		}catch(NoSuchAlgorithmException e){
			e.printStackTrace();
		}catch(NoSuchPaddingException e){
			e.printStackTrace();
		}catch(InvalidKeyException e){
			e.printStackTrace();
		}catch(IllegalBlockSizeException e){
			e.printStackTrace();
		}catch(BadPaddingException e){
			e.printStackTrace();
		}catch(IOException e){
			e.printStackTrace();
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		} 
	}
}
