FileDocCategorySizeDatePackage
TripleDES.javaAPI DocExample6526Sat Jan 24 10:44:30 GMT 2004je3.security

TripleDES.java

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
package je3.security;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.*;
import java.io.*;

/**
 * This class defines methods for encrypting and decrypting using the Triple
 * DES algorithm and for generating, reading and writing Triple DES keys.
 * It also defines a main() method that allows these methods to be used 
 * from the command line.
 **/
public class TripleDES {
    /**
     * The program.  The first argument must be -e, -d, or -g to encrypt,
     * decrypt, or generate a key.  The second argument is the name of a file
     * from which the key is read or to which it is written for -g.  The
     * -e and -d arguments cause the program to read from standard input and
     * encrypt or decrypt to standard output.
     **/
    public static void main(String[] args) {
	try {
	    // Check to see whether there is a provider that can do TripleDES
	    // encryption.  If not, explicitly install the SunJCE provider.
	    try { Cipher c = Cipher.getInstance("DESede"); }
	    catch(Exception e) {
		// An exception here probably means the JCE provider hasn't
		// been permanently installed on this system by listing it 
		// in the $JAVA_HOME/jre/lib/security/java.security file.
		// Therefore, we have to install the JCE provider explicitly.
		System.err.println("Installing SunJCE provider.");
		Provider sunjce = new com.sun.crypto.provider.SunJCE();
		Security.addProvider(sunjce);
	    }

	    // This is where we'll read the key from or write it to
	    File keyfile = new File(args[1]);

	    // Now check the first arg to see what we're going to do
	    if (args[0].equals("-g")) {        // Generate a key
		System.out.print("Generating key. This may take some time...");
		System.out.flush();
		SecretKey key = generateKey();
		writeKey(key, keyfile);
		System.out.println("done.");
		System.out.println("Secret key written to " + args[1] + 
				   ". Protect that file carefully!");
	    }
	    else if (args[0].equals("-e")) {  // Encrypt stdin to stdout
		SecretKey key = readKey(keyfile);
		encrypt(key, System.in, System.out);
	    }
	    else if (args[0].equals("-d")) {  // Decrypt stdin to stdout
		SecretKey key = readKey(keyfile);
		decrypt(key, System.in, System.out);
	    }
	}
	catch(Exception e) {
	    System.err.println(e);
	    System.err.println("Usage: java " + TripleDES.class.getName() +
			       " -d|-e|-g <keyfile>");
	}
    }

    /** Generate a secret TripleDES encryption/decryption key */
    public static SecretKey generateKey() throws NoSuchAlgorithmException {
	// Get a key generator for Triple DES (a.k.a DESede)
	KeyGenerator keygen = KeyGenerator.getInstance("DESede");
	// Use it to generate a key
	return keygen.generateKey();
    }

    /** Save the specified TripleDES SecretKey to the specified file */
    public static void writeKey(SecretKey key, File f)
	throws IOException, NoSuchAlgorithmException, InvalidKeySpecException
    {
	// Convert the secret key to an array of bytes like this
	SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
	DESedeKeySpec keyspec =
	    (DESedeKeySpec)keyfactory.getKeySpec(key, DESedeKeySpec.class);
	byte[] rawkey = keyspec.getKey();

	// Write the raw key to the file
	FileOutputStream out = new FileOutputStream(f);
	out.write(rawkey);
	out.close();
    }

    /** Read a TripleDES secret key from the specified file */
    public static SecretKey readKey(File f)
	throws IOException, NoSuchAlgorithmException,
	       InvalidKeyException, InvalidKeySpecException
    {
	// Read the raw bytes from the keyfile
	DataInputStream in = new DataInputStream(new FileInputStream(f));
	byte[] rawkey = new byte[(int)f.length()];
	in.readFully(rawkey);
	in.close();
	
	// Convert the raw bytes to a secret key like this
	DESedeKeySpec keyspec = new DESedeKeySpec(rawkey);
	SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
	SecretKey key = keyfactory.generateSecret(keyspec);
	return key;
    }

    /** 
     * Use the specified TripleDES key to encrypt bytes from the input stream
     * and write them to the output stream.  This method uses 
     * CipherOutputStream to perform the encryption and write bytes at the
     * same time.
     **/
    public static void encrypt(SecretKey key, InputStream in, OutputStream out)
        throws NoSuchAlgorithmException, InvalidKeyException,
	       NoSuchPaddingException, IOException
    {
	// Create and initialize the encryption engine
	Cipher cipher = Cipher.getInstance("DESede");
	cipher.init(Cipher.ENCRYPT_MODE, key);

	// Create a special output stream to do the work for us
	CipherOutputStream cos = new CipherOutputStream(out, cipher);

	// Read from the input and write to the encrypting output stream
	byte[] buffer = new byte[2048];
	int bytesRead;
	while((bytesRead = in.read(buffer)) != -1) {
	    cos.write(buffer, 0, bytesRead);
	}
	cos.close();

	// For extra security, don't leave any plaintext hanging around memory.
	java.util.Arrays.fill(buffer, (byte) 0);
    }

    /** 
     * Use the specified TripleDES key to decrypt bytes ready from the input 
     * stream and write them to the output stream.  This method uses 
     * uses Cipher directly to show how it can be done without 
     * CipherInputStream and CipherOutputStream.
     **/
    public static void decrypt(SecretKey key, InputStream in, OutputStream out)
        throws NoSuchAlgorithmException, InvalidKeyException, IOException,
	       IllegalBlockSizeException, NoSuchPaddingException,
	       BadPaddingException
    {
	// Create and initialize the decryption engine
	Cipher cipher = Cipher.getInstance("DESede");
	cipher.init(Cipher.DECRYPT_MODE, key);

	// Read bytes, decrypt, and write them out.
	byte[] buffer = new byte[2048];
	int bytesRead;
	while((bytesRead = in.read(buffer)) != -1) {
	    out.write(cipher.update(buffer, 0, bytesRead));
	}

	// Write out the final bunch of decrypted bytes
	out.write(cipher.doFinal());
	out.flush();
    }
}