[ Team LiB ] Previous Section Next Section

7.4 Cryptography

Although the message digest and digital signature techniques shown in the previous section use cryptographic techniques, note that they do not actually perform any encryption or decryption. Prior to Java 1.4, strict U.S. export regulations for encryption technology prevented Sun from releasing the Java platform with built-in encryption, and programmers instead had to download and install the separate Java Cryptography Extension (JCE). U.S. regulations have since been relaxed and Java 1.4 now includes the JCE classes in the javax.crypto package and its subpackages.

Example 7-5 is a program that allows you to encrypt and decrypt files using the TripleDES encryption algorithm and to generate TripleDES keys that are stored in files. It uses the JCE classes in javax.crypto and its subpackages. The key classes are Cipher, which represents an encryption or decryption algorithm, and SecretKey, which represents the encryption and decryption key used by the algorithm. You can find an API quick-reference for the JCE classes in Java in a Nutshell. You can also learn more about cryptography and the JCE from Java Cryptography by Jonathan Knudsen (O'Reilly).

Example 7-5. TripleDES.java
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( );

            // 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("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("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.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.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 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,
        // 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( );
    [ Team LiB ] Previous Section Next Section