PrintWriter pw = new PrintWriter new OutputStreamWritercos;
pw.printlnStand and unfold yourself; pw.close ;
oos.writeObjectc.getIV ; oos.close ;
} catch Exception e { System.out.printlne;
} }
}
There are two steps involved here. First, we must create the cipher object, which means that we must have a secret key available. Bypassing the secret key management examples weve used before, were just going to
save the key object to a file that can later be read by whomever needs the key. Note that weve gone through the usual steps of writing the data produced by the secret key factory so that the recipient of the key need not
use the same provider we use.
After we generate the key, we must create the cipher object, initialize it with that key, and then use that cipher object to construct our output stream. Once the data is sent to the stream, we close the stream, which flushes
the cipher object, performs any necessary padding, and completes the encryption.
In this case, weve chosen to use CFB8 mode, so there is no need for padding. But in general, this last step is important: if we dont explicitly close the
PrintWriter stream, when the program exits, data that is
buffered in the cipher object itself will not get flushed to the file. The resulting encrypted file will be unreadable, as it wont have the correct amount of data in its last block.
[1]
[1]
Closing the output stream is necessary whenever the stream performs buffering, but it is particularly important to remember in this context.
13.2.2 The CipherInputStream Class
The output stream is only half the battle; in order to read that data, we must use the CipherInputStream
class javax.crypto.CipherInputStream
: public class CipherInputStream extends FilterInputStream
Create a filter stream capable of decrypting data as it is read from the underlying input stream. A cipher input stream is constructed with this method:
public CipherInputStreamInputStream is, Cipher c Create a cipher input stream that associates the existing input stream with the given cipher. The cipher
must previously have been initialized. All the points we made about the
CipherOutputStream class are equally valid for the
CipherInputStream class. You can operate on it with any of the methods in its superclass, although
youll typically want to wrap it in something like a buffered reader, and the cipher object that is associated with the input stream needs to perform automatic padding or use a mode that does not require padding in fact,
it must use the same padding scheme and mode that the output stream that is sending it data used.
The CipherInputStream
class does not directly support the notion of a mark. The markSupported
method returns false
unless youve wrapped the cipher input stream around another class that supports a mark.
Heres how we could read the data file that we created above:
package javasec.samples.ch13; import java.io.;
import java.security.; import javax.crypto.;
import javax.crypto.spec.; public class Receive {
public static void mainString args[] { try {
ObjectInputStream ois = new ObjectInputStream new FileInputStreamkeyfile;
DESKeySpec ks = new DESKeySpecbyte[] ois.readObject ; SecretKeyFactory skf = SecretKeyFactory.getInstanceDES;
SecretKey key = skf.generateSecretks; Cipher c = Cipher.getInstanceDESCFB8NoPadding;
c.initCipher.DECRYPT_MODE, key, new IvParameterSpecbyte[] ois.readObject ;
CipherInputStream cis = new CipherInputStream new FileInputStreamciphertext, c;
BufferedReader br = new BufferedReader new InputStreamReadercis;
System.out.printlnGot message; System.out.printlnbr.readLine ;
} catch Exception e { System.out.printlne;
} }
}
In this case, we must first read the secret key from the file where it was saved, then create the cipher object initialized with that key. Then we can create our input stream and read the data from the stream, automatically
decrypting it as it goes.
13.3 Sealed Objects
The final class in JCE that well investigate is the SealedObject
class javax.crypto.SealedObject
. This class is very similar to the SignedObject
class we examined in Chapter 12, except that the stored, serialized object is encrypted rather than signed:
public class SealedObject A class that can embed within it a serializable object in an encrypted form.
You can construct a sealed object as follows: public SealedObjectSerializable obj, Cipher c
Construct a sealed object. The sealed object serializes the given object to an embedded byte array, effectively making a copy of the object. It then uses the given cipher to encrypt the embedded byte
array. If the object is unable to be serialized, an IOException
is thrown; an error in encrypting the byte array results in an
IllegalBlockSizeException . If the cipher object has not been
initialized, an IllegalStateException
is generated. To retrieve the object, we use this method:
public Object getObjectCipher c Decrypt the embedded byte array and deserialize it, returning the reconstituted object. The cipher
must have been initialized with the same mode and key as the cipher that was passed to the constructor when the object was first created, otherwise a
BadPaddingMethodException or an
IllegalBlockSizeException is thrown. If the cipher was not initialized, an
IllegalStateException is generated; failure to find the serialized class results in a
ClassNotFoundException , and generic deserialization errors result in an
IOException .
These are the only two operations that may be performed upon a sealed object. Keep in mind that the embedded object in this class is a serialized instance of the original object: the technique the object uses to
perform serialization may affect the resulting object that is retrieved from the sealed object. This class can help us prevent someone from tampering with our serialized object, but the reconstituted object may be
lacking transient fields or other information depending, of course, on the implementation of the object itself.
13.4 Comparison with Previous Releases
The classes discussed in this chapter are available in version 1.2.1 of JCE. Version 1.2.1 is the first exportable release of JCE; previous versions may be used only within the United States and Canada. However, there are
third−party implementations of earlier versions of JCE that were written by entities outside of the United States, and those implementations may be used outside of the United States.
Version 1.2 does not support key wrapping. The init
methods to the Cipher
class that require a certificate are not available in 1.2.
Version 1.1 of JCE supports only the DES, DESede, and PBEWithMD5AndDES encryption algorithms.
13.5 Summary
In this chapter, we explored cipher−based encryption engines. These engines perform encryption of arbitrary chunks or streams of data according to various algorithms. Cipher−based encryption engines separate the
encryption of data from its transmission, so they are suitable for many purposes. They can be used to encrypt data to be sent over a socket, but they may also be used to encrypt data to be stored in a file, on a Java smart
card, or even held in memory on an insecure machine.
In the next chapter, well look at another method of performing encryption: SSL, the secure sockets layer protocol, which automatically encrypts data sent over network sockets.
Chapter 14. SSL and HTTPS
In this chapter, we will explore how the Java Secure Socket Extension JSSE can be used to perform Secure Sockets Layer SSL encryption. SSL provides data encryption over TCP sockets and is the basis of the
HTTPS protocol. JSSE provides a means to create and use SSL sockets as well as protocol handlers to support the HTTPS protocol. Because it is tightly coupled with TCP sockets, SSL is not a general−purpose encryption
engine, but it is probably the most popular form of encryption used on the Internet. Its design has many advantages for network−based encryption as well.
14.1 An Overview of SSL and JSSE
On the Internet, data encryption is often performed using the Secure Sockets Layer protocol. This protocol was originally designed by Netscape for use in its browsers and secure servers; its most popular
implementation is SSL 3.0. As SSL became a key technology on the Internet, its development and maintenance were taken over by the Internet Engineering Task Force IETF, which made some slight
modifications to SSL 3.0 and established the Transport Layer Security TLS Internet standard presently version 1.0. Dont be confused by the names here: SSL and TLS are essentially the same protocol; TLS 1.0 is
really just SSL version 3.1 which has very few changes from version 3.0. TLS 1.0 is backward−compatible with SSL 3.0, so a program that uses the TLS protocol will be able to talk to other programs that use SSL 3.0.
SSL 3.0 is used by most browsers, including Netscape 4.x and 6, Internet Explorer 4.x and 5.x, the AOL browser, and the Opera browser. Some earlier versions of these browsers used SSL 2.0. SSL servers almost
universally use 3.0 or later, partly because they are expected to talk to the newest browsers and partly because SSL 3.0 is considered more secure than SSL 2.0.
JSSE defines an API for SSL sockets. Sun provides a default implementation of that API in the reference implementation of JSSE. In theory, you can obtain third−party implementations of JSSE that plug into the
JSSE framework, although as well see later in this chapter, you must use Suns implementation−specific classes to perform certain operations. Hence, programs that use JSSE are not always
implementation−independent. Suns reference implementation of JSSE supports only SSL 3.0 and TLS 1.0. See Chapter 1, for details on how to obtain and install JSSE.
SSL, as its name implies, is designed to be used over sockets; there is no way within its protocol to separate the encryption from the data transmission. If you use SSL, you must use TCP sockets to transmit your data;
UDP sockets and other transmission modes are not supported. Despite this, there are three key advantages to using SSL:
It is ubiquitous. There are a number of existing services built on top of SSL such as HTTPS, and to communicate with or implement such services, you must use SSL.
• It provides a simple interface to secret key encryption. Essentially, SSL performs two operations: a
secret key exchange like the Diffie−Hellman exchange we looked at in Chapter 10 and data encryption with the exchanged key. SSL hides most of the details of the key exchange and encryption,
allowing developers to focus on their applications logic. •
It is designed for an environment in which there are relatively few servers and many, many clients. SSL servers must provide credentials i.e., a certificate to authenticate themselves to their clients, but
the clients do not need to provide credentials to the server unless the server requires them to do so. Hence, the client in an SSL conversation does not need to go to the trouble of obtaining a certificate.
This allows, for example, an Internet shopper to make purchases without obtaining a certificate.
This makes sense on two levels. First, given the complexity of distributing certificates to thousands of clients, it prevents what might otherwise be a major roadblock in consumer acceptance of
•
e−commerce. Second, the client already has other credentials that it gives to the server, such as a credit card number, an address, a promise to send a check, and so on. Its easier for the client to
provide these credentials than to obtain a digital certificate in order to operate with an SSL server.
The SSL protocol exchanges several pieces of information between the client and server when the client first connects to the server. This process, known as an SSL handshake , is illustrated in Figure 14−1.
Figure 14−1. Sample SSL handshake
Although there are variations on the way this proceeds and there may be intermediate messages in the protocol, the basic flow of information goes like this:
The client initiates the connection to the server and tells the server which SSL cipher suites the client supports.
1. The server responds with the cipher suites that it supports.
2. The server sends the client a certificate that verifies its identity.
3. The server initiates a key exchange algorithm, based in part on the information contained in the
certificate it has just sent, and sends the necessary key exchange information to the client. 4.
The client completes the key exchange algorithm and sends the necessary key exchange information to the server. Along the way, it verifies the certificate.
5. Based on the type of key exchange algorithm which in turn is based on the type of key in the servers
certificate, the client selects an appropriate cipher suite and tells the server which suite it wants to use.
6. The server makes a final decision as to which cipher suite to use.
7. If the server desires, it can ask for the clients certificate so that it can be assured of who it is talking to; the
client certificate is sent before the client key exchange information if required. Once all this information has been established, the client and server can communicate normally over the socket; data that flows over the
socket will be encrypted automatically.
Programatically, these steps are transparent: a developer asks for an SSL socket, and when the SSL socket is created, the protocol handshake is complete. This is one of the advantages of using SSL. We could have
written all the code to establish the connection, perform the key exchange using code based on the key exchange example we saw in Chapter 10, and encrypt the data using code based on the examples from
Chapter 13, but SSL hides all those details from us. 262