Applications
Symmetric encryption can be applied in quite a number of areas. It is much faster than asymmetric, or
public-key encryption (sometimes by a factor of 1000) and for that reason it is recommended in situations
where lots of data must be transformed. File encryption, network encryption, and database encryption are
all good places to employ symmetric encryption. Its main weakness is the symmetry of the key. That same
key must be used to encrypt and decrypt, so anyone with the ability to encrypt also has the ability to
decrypt. If you are sending a symmetrically encrypted message, both sender and receiver must agree on a
key in advance. For that reason, it is often best to use symmetric encryption to encrypt a large amount of
data, and then encrypt the symmetric key with asymmetric encryption. We will investigate that further in
the next chapter. For now, let's begin with a simple example encrypting and decrypting a string.
The only JCE classes our code will use are the (javax.crypto.*) classes, which are used to handle
cryptography. This makes the programs portable to any provider that supports the algorithms we use.
We've discussed some of these classes in the previous chapter, but now let's investigate them in more depth
along with the java.security.Key class.
javax.crypto.Cipher
The cipher is essentially the engine that performs the encryption and decryption of data. The Cipher class
has four methods that we're interested in right now: getInstance(), init(), update(), and
doFinal(). Let's go over them one by one:
getInstance()
As we've mentioned before, most of the classes in the JCE use factory methods instead of normal
constructors. Rather than create an instance with the new keyword, we make a call to the class's
getInstance() method, with the name of the algorithm and some additional parameters like so:
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
The first parameter is the name of the algorithm, in this case, "DESede". The second is the mode the cipher
should use, "ECB", which stands for Electronic Code Book. The third parameter is the padding, specified
with "PKCS5Padding". We'll go into more detail about the mode and padding later. For now, just be aware
that even though it is possible to skip the declaration of the mode and padding they should be declared
anyway. If the mode and padding are skipped, the provider picks a mode and padding to use, which is
rarely what you want, and prevents the code from being ported to other providers.
init()
Once an instance of Cipher is obtained, it must be initialized with the init() method. This declares the
operating mode, which should be either ENCRYPT_MODE or DECRYPT_MODE, and also passes the cipher a
key (java.security.Key, described later). Assuming we had a key declared, initialized, and stored in the
variable myKey, we could initialize a cipher for encryption with the following line of code:
cipher.init(Cipher.ENCRYPT_MODE, myKey);
The JCE 1.2.1 specification adds two more possible operating modes, WRAP_MODE and
UNWRAP_MODE
.
These modes set up a cipher to encrypt or decrypt keys. We'll use these modes later, when we use
asymmetric encryption.
update()
In order to actually encrypt or decrypt anything, we need to pass it to the cipher in the form of a byte
array. If the data is in the form of anything other than a byte array, it needs to be converted. If we have a
string called myString and we want to encrypt it with the cipher we've initialized above, we can do so with
the following two lines of code:
byte[] plaintext = myString.getBytes("UTF8");
byte[] ciphertext = cipher.update(plaintext);
Ciphers typically buffer their output. If the input is large enough that it produces some ciphertext, it will be
returned as a byte array. If the buffer has not been filled, then null will be returned.
Note that in order to get bytes from a string, we should specify the encoding method. In most cases, it will
be UTF8.
If you don't specify the encoding type, you will get the underlying platform's default encoding. This
is almost never what you want, and can cause bizarre errors when encryption takes place on one
platform, and decryption on another. Always specify the encoding.
doFinal()
Now we can actually get the encrypted data from the cipher. doFinal() will produce a byte array, which
is the encrypted data.
byte[] ciphertext = cipher.doFinal();
A number of the methods we've talked about can be overloaded with different arguments, like start and end
indices for the byte arrays passed in. We're not going to go into detail covering them, as they are presented
clearly in the JCE's JavaDoc.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.