Developer

Protect your network traffic using Java's encryption features

Security and encryption are standard Java features provided by way of the Java Cryptography Extension (JCE). Learn how to integrate these features in your next project.


The Java Development Kit (JDK) has strong encryption and security support. One of the nicer features is its built-in support for socket communication. As we will see here, it's easy to write a client and a server that talk to each other securely with encrypted streams.

A little background
For a look at the JDK's security support, check out "Mastering the Basics of the Java Cryptography Extension (JCE)."

Streams
Java streams are a powerful programming tool. The java.io package offers several standard stream types, and it's easy to create your own. One interesting and useful feature of streams is a simple process known as chaining. Listing A shows how you can use chaining to read in a text file. This code chains a FileReader to a BufferedReader. The same concept is used in our sample client/server application.

Keys
Keys are important for identification. Listing B (KeyGen.java) provides a static method called getSecretKey that all of our classes use. To generate a test key, run KeyGen once with no arguments. Since we are still using a synchronous algorithm, both the client and the server are required to have access to the same key.

Secret socket
We begin by providing a simple wrapper class. It provides our encryption on top of an ordinary socket object. Listing C (SecretSocket.java) accepts two parameters, a Socket and a Key object. Our constructor sets the instance variables and initializes the cipher:
outCipher = Cipher.getInstance(algorithm);
outCipher.init(Cipher.ENCRYPT_MODE, key);
inCipher = Cipher.getInstance(algorithm);
inCipher.init(Cipher.DECRYPT_MODE, key);

Since sockets provide two-way communication, we use two ciphers. We encrypt on the way out and decrypt on the way in. Next, we have two methods, getInputStream() and getOutputStream(), which provide the appropriate encryption or decryption streams wrapped around the normal input and output streams of the socket. We do this via chaining. (See Listing D).

CipherInputStream and CipherOutputStream are two stream types found in the javax.crypto package in the JCE. They accept a stream object (input or output) and a cipher object.

Keep your Java skills sharp
Java opened up the Web's interactive possibilities, and developers continue to use Java to create complete applications. To stay current with Java development, start each Monday and Thursday with our Java e-newsletter. Sign up now!

Socket server
We begin by writing our socket server class. See Listing E (SecretSocketServer.java) for the full listing. SecretSocketServer opens up a ServerSocket on a port, and as it accepts connections, it spawns a thread to handle the connections using a SocketHandler.

Socket handler
Listing F (SocketHandler.java) accepts a socket object, locates a key using KeyGen, and creates a SecretSocket object.
Key key = KeyGen.getSecretKey();
this.ss = new SecretSocket(s, key);

Note that ss in Listing F is an instance variable for SocketHandler. All socket manipulation is now done via the SecretSocket, not the Socket object. Next, we set another instance variable, in (an InputStream), using the following code:
in = ss.getInputStream();

Remember, in SecretSocket, getInputStream is now a chained stream using the CipherInputStream and the socket's InputStream. Since SocketHandler implements the runable interface, we provide a run() method for it. This method simply creates a loop and listens on the socket:
boolean bool = true;
while (bool) {
bool = listen();
}

The listen method does the work of listening to the socket and doing something with it.
int aByte;
while ((aByte = in.read()) >= 0) {
system.out.println((char)aByte);
}

In this case, we simply display the character conversion of the bytes to the screen as they are read in.

Socket client
Now we move on to the client. (See Listing G.) The client works in much the same way as the server, only backward. First, we create a socket that connects to our socket server. Using the KeyGen to look up our key, we create a SecretSocket. We then use the SecretSocket’s OutputStream to send some data to our server:
Key key = KeyGen.getSecretKey();
Socket s = new Socket("localhost", 4444);
SecretSocket ss = new SecretSocket(s, key);
OutputStream os = ss.getOutputStream();
os.write("Hello World!".getBytes());
os.flush();
os.close();
s.close();

Summary
By using the JCE, along with Java streams and chaining, we can easily provide encryption to our socket-based network communication.

Download the code


 

Editor's Picks