The Java Cryptography Extension (JCE
) is now a core part
of Java SDK 1.4
. Basically, it's a set
of packages that provide a framework and implementations for encryption, key
generation and agreement, and Message Authentication Code (MAC) algorithms. This
article will explore the installation and utilization of JCE.
Note that although the JCE is now a core package in Java SDK 1.4, we'll
demonstrate how to configure it using Java SDK 1.2 or higher (static
installation). Also, I'll cover how to use security providers with no setup at
all (dynamic installation). Finally, I'll demonstrate how to create a key and a
cipher and how to perform basic data encryption and decryption.
Static installation<java-home>\jre\lib\security\java.security (Win32) <java-home>/jre/lib/security/java.security (UNIX)
Before using or installing JCE, you must first obtain the library from the Sun
Web site. JCE contains
Sun’s own security provider, SunJCE. To statically add SunJCE to your list of
default providers, you need to edit the security properties file:
For instance, if you installed the JDK on a Windows machine in the folder C:\jdk1.3, you'd need to edit this file:
To install the SunJCE, you'd add the following line to the above file:
Substitute n with the priority for this provider.
Listing A demonstrates how you can view information about
installed providers. The output displayed in Listing B shows information the provider supports, such as the available algorithms.
Listing C shows how to dynamically load a provider at
runtime. It should be noted that when you invoke Security.addProvider(…),
the provider is available to the entire JVM.
As stated previously, when you install a provider, you provide a number to indicate its priority. When an implementation is called for, the JVM will search through all installed security providers according to their priority and use the first provider it finds that implements the requested algorithm. You can also explicitly call for a given provider by including additional arguments to certain method calls, as we will see later.
The JCE API consists of numerous classes and interfaces for working with several kinds of algorithms and security features. In this first installment, we'll deal with using a popular symmetric algorithm, Data Encryption Standard (DES).
Listing D shows how to initialize a
KeyGenerator and generate a key.
To generate a key, we must first get an instance of a KeyGenerator
is accomplished by invoking the static method getInstance
class. We use a plain vanilla DES algorithm with no mode or
padding scheme. Optionally, you could pass in something like this:
This provides a DES algorithm, with the Electronic Codebook (ECB) mode and PKCS#5 style padding. A second String parameter can be passed to specify provider implementation to use, but it is not necessary:
KeyGenerator kg = KeyGenerator.getInstance("DES");
Once we have our KeyGenerator, we invoke the generateKey method to
get our key:
Key key = kg.generateKey();
Generating a cipher
We generate a cipher in much the same way that we generate a key. We must invoke
the static method getInstance in the Cipher class. The parameters
for this method work exactly as with KeyGenerator:
Cipher cipher = Cipher.getInstance(“DES”);
Listing E shows how to do this.
Encrypting and decrypting data
Encryption works at the byte level, so almost anything can be encrypted. Once
you have a key and a cipher, you're ready to go. It should be noted that the
same algorithm must be used for both the key and cipher. You cannot have a key
initialized with DESede and a cipher initialized with DES. The Cipher
object uses the same methods to encrypt and decrypt data, so you must initialize
it first to let it know what you want done with the data:
This call initializes the Cipher object and gets it ready to encrypt
data. The simplest way to encrypt data is invoking the doFinal method on
the Cipher object passing in a byte array:
byte data = “Hello World!”.getBytes();
byte result = cipher.doFinal(data);
The result will now contain the encrypted representation of the passed-in
data. It's just as easy to decrypt the same data. But before we can do that, we
must reinitialize the Cipher object and get it ready for decryption:
Once we do this, we are ready to decrypt:
byte original = cipher.doFinal(result);
Now, original should now be identical to data. See Listing F for the full source code.
JCE is a powerful API, allowing numerous types of encryption, as well as several other security-related tasks. We've seen how to install the JCE both statically and dynamically, as well as use a symmetric encryption algorithm to encrypt and decrypt a simple message. In part two of this series, we'll take what we have learned in this article and apply it to a real-world scenario. I'll show you how to write a simple wrapper that can be used with sockets to encrypt all network traffic for your applications.