- Cryptography Basics
- SSL—Secure Sockets Layer
- Encrypting and Decrypting Data
SSLSecure Sockets Layer
The Secure Sockets Layer (SSL) lets you send encrypted data over a network with a minimum of effort. SSL uses a combination of public key and private key encryption to avoid the common problem of key distribution. Public key encryption, because it involves mathematical operations on very large numbers, is generally much slower than private, symmetric-key encryption. SSL uses public key encryption only to set up a private key, at which point it switches over to private key encryption.
If you know how to use the Sockets API, you already know how to use SSLan SSL socket is a subclass of Socket. The only real difference between SSLSocket and Socket is how you create the socket. JDK 1.4 introduces a new javax.net package that provides a new way to create Socket and ServerSocket objects. The SocketFactory class has a createSocket method to create a new Socket instance. Likewise, the ServerSocketFactory class has a createServerSocket method to create ServerSocket instances.
To create a regular Socket using SocketFactory, use getDefault to create the factory and then use createSocket to create the Socket like this:
SocketFactory fact = SocketFactory.getDefault(); Socket sock = fact.createSocket("somehost", 80);
Now, to use SSL, you simply use SSLSocketFactory.getDefault to create the factory like this:
SocketFactory fact = SSLSocketFactory.getDefault(); Socket sock = fact.createSocket("somehost", 80);
To create a regular ServerSocket using ServerSocketFactory, you again use getDefault like this:
ServerSocketFactory fact = ServerSocketFactory.getDefault(); ServerSocket server = fact.createServerSocket(123);
Again, the only difference between creating an SSLServerSocket and a ServerSocket is the factory you create:
ServerSocketFactory fact = SSLServerSocketFactory.getDefault(); ServerSocket server = fact.createServerSocket(123);
JDK 1.4 still allows you to create Socket and ServerSocket classes with the new operator, but the factory gives you more flexibility.
The following program creates an SSLServerSocket and then listens for incoming connections. It creates a separate thread that reads data from the connection, and prints it to System.out.
import javax.net.*; import javax.net.ssl.*; import java.net.*; import java.io.*; public class SSLServer implements Runnable { Socket clientSocket; // Each instance of SSLServer handles a client connection public SSLServer(Socket aClientSocket) { clientSocket = aClientSocket; } public void run() { try { // Create a DataInputStream to read data one line at a time DataInputStream in = new DataInputStream( new BufferedInputStream(clientSocket.getInputStream())); String line; // Read lines from the socket until there are no more while ((line = in.readLine()) != null) { System.out.println(line); } in.close(); clientSocket.close(); } catch (Exception exc) { } } public static void main(String[] args) { try { // Create a server socket factory ServerSocketFactory fact = SSLServerSocketFactory.getDefault(); // Create the server socket ServerSocket server = fact.createServerSocket(1234); for (;;) { // Wait for a connection Socket sock = server.accept(); // Create a new instance of SSLServer to handle the connection SSLServer client = new SSLServer(sock); Thread serverThread = new Thread(client); serverThread.start(); } } catch (Exception exc) { exc.printStackTrace(); } } }
Before you can run this program, you must do a bit of housekeeping first. Remember that SSL uses a public key in order to establish a private key. You must use the keytool command to create a public key for SSL to use. Here is an example keytool command line:
keytool -genkey -alias ssltest -keyalg RSA keystore keystore
When you create the key, keytool will ask you for various information, such as your name, company and location. This information is stored in the digital certificate accompanying your key. The keytool program will create a keystore file called "keystore" (or whatever name you supply in the keystore argument). You must supply a password for the keystore, which will be used when you run the server program. I used "changeit" as the password, which is the default for certain keystores that ship with the JDK. Also, when keytool asks you for a password for your new key, just hit Return.
Now, to run SSLServer using your newly created keystore, use the following command:
java -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.keyStore=keystore SSLServer
Creating an SSL client socket isn't much different from creating a normal socket. Once again, you must use a factory instead of the socket constructor. The following program connects to the SSLServer program you have just seen:
import javax.net.*; import javax.net.ssl.*; import java.net.*; import java.io.*; public class SSLClient { public static void main(String[] args) { try { // Create the socket factory SocketFactory fact = SSLSocketFactory.getDefault(); // Create the socket Socket sock = fact.createSocket("localhost", 1234); PrintStream out = new PrintStream( new BufferedOutputStream(sock.getOutputStream())); // Print the command-line articles to the socket for (int i=0; i < args.length; i++) { if (i > 0) out.print(" "); out.print(args[i]); } out.println(); out.flush(); } catch (Exception exc) { exc.printStackTrace(); } } }
The whole public-private key situation can be a little complicated. A server needs a key store that contains its private key and corresponding public key (in the form of a digital certificate). A client needs a way to verify the authenticity of a server's certificate. Typically, in a production environment, you use a well-known certificate authority (CA) to authenticate your digital certificates. When a client sees that your certificate has been signed by a well-known CA, it automatically trusts your certificate. Most security packages have a number of CA identities preinstalled.
For the purposes of this example, however, you don't need to go through the trouble of going to a CA for your digital certificate. When you used keytool to create your key, it created a digital certificate. You just need to export the certificate from your keystore and create a trusted CA store.
First, use keytool to export the certificate:
keytool export alias ssltest file ssltest.cert keystore keystore
You should now see a file called "ssltest.cert" in your directory. Now, create a new trusted CA store by importing this certificate into a new keystore:
keytool import alias ssltest file ssltest.cert keystore castore
Again, you will need to supply a password for the new keystore. I used "changeit" again. Now, run the client program, supplying the filename and password of the CA storeas well as some command-line arguments that the server prints out to the screen:
java -Djavax.net.ssl.trustStore=castore -Djavax.net.ssl.trustStorePassword=changeit SSLClient foo bar baz