Practical Cryptography

I was recently putting the finishing touches on an e-commerce site and found myself in possession of some very powerful keys, if you will. I'm talking about the information which permits you to communicate with an internet payment processor. If someone was to somehow obtain the sensitive information, conduct the necessary research and formulate acceptable requests to the gateway, they could certainly wreak havoc. The potential damage runs the gamut from using the gateway to confirm card details or available credit limits all the way to processing credits for friends and acquaintances.

I subscribe to prevailing wisdom and only process credit card transactions through a back-end system which has no direct connections to the Internet and is only accessible through unidirectional gateways and firewalls. No credit card information is retained on the webserver and all transactions are encrypted and logged such that sensitive information is retained on removable media. Even so, recent events have demonstrated that you can never have too much security.

So how do you go about protecting this sensitive information? The back-end server needs to access the information in order to construct the requests which are then sent via HTTPS to the payment processor. You don't want to have to manually enter the keys each time the application is started as this would be time consuming and error-prone. So you have to protect the information in a persistent store while making it accessible to the application at run-time. The obvious solution (at least these days) is encryption.

Up until fairly recently the only cryptography available on most *NIX systems was the crypt system call. This was an implementation of a trap-door algorithm in which the plain-text was run through a permuted hashing machine. The actual passwords were not stored, just the hash. Password confirmation was achieved by extracting the salt from the stored hash and combining it with a password entered by the user. If the output of the algorithm was the same as the stored hash then the user was authenticated.

Obviously we couldn't use such a mechanism for our scenario as it doesn't actually store the encrypted original data in a form suitable for subsequent retrieval. What was needed was some form of symmetric cipher, one in which the same key is used for the encryption and decryption. A quick search of the web will reveal a number of cryptographic packages which can be roughly divided into two classes: commercial products (read: expensive) and the public domain implementations. Trying to find a trustworthy "clean room" package can be tricky.

Fortunately, Sun Microsystems has legitimized cryptography for Java with the release of the Java Cryptography Extensions (JCE). Now that the Rivest, Shamir, Adelman (RSA) algorithm has been released from patent, it's relatively painless to implement robust, secure applications. There are now a number of algorithms available such as the DES (Data Encryption Standard) and DSA (Digital Signature Algorithm). Multiple variants are also available such as CBC (Cipher Block Chaining) and even OFB (Output Feedback) for some algorithms.

Since this document is not intended to serve as an introduction to cryptography (excellent texts abound), we'll just focus on the task at hand. I'm using a protocol of PBEWithMD5AndDES, which is Password-Based Encryption with Message Digest 5 and DES. Here's is a code snippet for encrypting our serializable object:

    String           String     protocol = "PBEWithMD5AndDES";

    PBEKeySpec       ks = new PBEKeySpec( passwd );
    PBEParameterSpec parms = new PBEParameterSpec( salt, count );
    SecretKeyFactory factory = SecretKeyFactory.getInstance( protocol );
    SecretKey        key = factory.generateSecret( ks );
    Cipher           cipher = Cipher.getInstance( protocol );
    byte             result[] = encrypt( cipher, key, parms, src );
In this code the passwd is a char array, the salt is a byte array with a length of 8, and count is just an int. The selection of the salt and the count is left as an implementation detail. It wouldn't pe particularly secure if I was to announce to everyone the values which I use. The collection of the password, serialization of the source and the encrypt implementation will be discussed. Note that I've excluded exception handling code.

To keep the code samples together, here is the implementation of encrypt:

    public byte[] encrypt( Cipher c, SecretKey key,
      AlgorithmParameterSpec parms, Serializable src ) throws Exception {
        ByteArrayOutputStream   bos = new ByteArrayOutputStream();
        ObjectOutputStream      oos = new ObjectOutputStream( bos );
        oos.writeObject( src );
        oos.flush();
        oos.close();
        c.init( Cipher.ENCRYPT_MODE, key, parms );
        return( c.doFinal( bos.toByteArray() ) );
    }
So why would I put this code in a separate method? Encapsulation using the super-classes as argument types promotes code re-use. I could use the same method with a SecretKey generated via an RSAPrivateKeySpec. Since I'm frequently going to be encrypting objects which implement java.io.Serializable then it makes sense to generate the byte array in this method as well.

I use the ByteArrayOutputStream as a destination for the serialized object as it is only stored in local memory and there is a convenient method (toByteArray) for extracting the data in the required format. The decryption code is identical insofar as generating the required elements. We just invoke the decrypt method like this:

    Object result = decrypt( cipher, key, parms, src );
And here is the corresponding decrypt method:
    public Object decrypt( Cipher c, SecretKey key,
      AlgorithmParameterSpec parms, byte src[] ) throws Exception {
        ObjectInputStream ois = null;
        Object            result = null;

        c.init( Cipher.DECRYPT_MODE, key, parms );
        ois = new ObjectInputStream( new ByteArrayInputStream( c.doFinal( src ) ) );
        result = ois.readObject();
        ois.close();
        return( result );
    }
The return from the method will need to be cast to the corresponding object class. I wanted to make the decryption method generic (re-use) so it returns an Object.

I haven't included the code but the output of encrypt would be used as the argument to write on a FileOutputStream. Similarly, the source for decrypt would be a byte array obtained from a read on a FileInputStream. I intentionally avoided the FileWriter and FileReader classes as those are oriented towards character data whereas we are dealing with binary data.

A discussion of practical cryptography would be lacking if it didn't address password entry. We want to ensure that nobody has the opportunity to view the screen and see the password in "clear text". Someone close enough to be watching your key presses would almost certainly be detected. It's the "over the shoulder" glances which can provide others with the password if it's echoed to the screen.

Java is designed to be a cross-platform language and so doesn't include some of the features programmers of lower-level languages like C have come to expect. In this case, there's no general-purpose mechanism for turning off echo at the command line. It would be simple if we were using a GUI but that approach seems excessive when all we need to do is collect a single piece of information, namely a password. If we were to offer real-time transaction display then the effort would no doubt be worthwhile.

My target platform is Java 1.3 running on Linux so there's a fairly straight-forward mechanism for turning off console echo. I've used it frequently in applications written in C. Since the echo bit is contained within a character containing other flags, I've always saved the initial contents before clearing the echo flag. I then replace the entire character when I want to revert to the original state. As such, the Java native method for turning off echo should return an int which should also be passed as an argument to the reset method.

Another twist is that the newline character obeys the no echo rule as well, i.e. when you hit Enter, a newline is not echoed to the display. When we accept password input, we should also send a newline to the console output stream at end-of-line. I solve the problem by providing a method which requires InputStream and PrintStream arguments. These are typically passed by the caller as System.in and System.out. I invoke the set/reset echo methods within read in order to provide a clean interface to the caller. Here's the code:

import	java.io.InputStreamReader;
import	java.io.BufferedReader;
import	java.io.InputStream;
import	java.io.PrintStream;

public class SecureInput {

	static {
		System.loadLibrary( "SecureInput" );
	}

	public static String read( InputStream is, PrintStream ps ) {
		BufferedReader	br = null;
		String		result = null;
		int		flags = 0;

		try {
			br = new BufferedReader( new InputStreamReader( is ) );
			flags = setNoEcho();
			result = br.readLine();
			resetNoEcho( flags );
			ps.println();
		}
		catch( Exception e ) {
			return( null );
		}
		return( result );
	}

	public static native int setNoEcho();
	public static native void resetNoEcho( int flags );
}
A number of comments are necessary. First of all, we load the library which contains the native code in a class static block. This ensures that the code is executed only once, when the class is first loaded. Note also that the actual location of the library (libSecureInput.so in this case) will have to be specified using a local mechanism. In Linux this just means that the directory containing the library must be specified in the LD_LIBRARY_PATH environment variable. Finally, note that we don't close the BufferedReader. Due to the way that this class is implemented, closing it would also close the underlying stream. This would be disastrous if we needed to read additional input from System.in in the caller.

Compile the source and then run javah on the class file in order to generate the include file for the native methods. I cut-and-paste my method headers directly from the include file; you just need to add variable names after the variable types. Here's the C source:

#include	<termios.h>
#include	<unistd.h>
#include	"SecureInput.h"

JNIEXPORT jint JNICALL Java_SecureInput_setNoEcho( JNIEnv *env, jclass cls ) {
	struct	termios	termio;
	tcflag_t	flags;

	tcgetattr( 0, &termio );
	flags = termio.c_lflag;
	termio.c_lflag &= ~ECHO;
	tcsetattr( 0, TCSANOW, &termio );
	return( flags );
}

JNIEXPORT void JNICALL Java_SecureInput_resetNoEcho( JNIEnv *env, jclass cls,
  jint flags ) {
	struct	termios	termio;

	tcgetattr( 0, &termio );
	termio.c_lflag = (tcflag_t) flags;
	tcsetattr( 0, TCSANOW, &termio );
}
The specifics regarding the use of tcgetattr/tcsetattr are beyond the scope of this discussion. Suffice it to say the the code achieves the stated goal of turning off echo and reverting to the original state. Now we just have to create the library. I use this sequence:
$ cc -c SecureInput.c
$ ld -olibSecureInput.so -shared SecureInput.o
Again, make sure that the location of this generated library is specified in your LD_LIBRARY_PATH environment variable. Now we can make a simple call to the static SecureInput.read method when we need to invisibly capture a password. One word of advice: since the user can't visually confirm the keyed information, it's common practice to ask for the data twice. If the two strings don't match then provide the user with the opportunity to try again. It would be more than frustrating to find that you had unwittingly encrypted the information with an unknown password! Here's an example:
    String pw1 = null;
    String pw2 = null;

    for(;;) {
        System.out.print( "Enter password: " );
        System.out.flush();
        pw1 = SecureInput.read( System.in, System.out );
        if( ( pw1 == null ) || ( pw1.length() == 0 ) )
            // user abort
        System.out.print( "Reenter password: " );
        System.out.flush();
        pw2 = SecureInput.read( System.in, System.out );
        if( ( pw2 == null ) || ( pw2.length() == 0 ) )
            // user abort
        if( ! pw1.equals( pw2 ) ) {
            System.err.println( "passwords don't match" );
            continue;
        }
        break;
    }
More information on PKCS #5.

July 10th, 2003