Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API

Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

In Java we trust

Find out how the Java Security API can help you secure your applications

Trust everyone? Trust no one? Sounds a bit like the X-Files, but when it comes to confidential information, knowing who it is you're trusting is as important as knowing what you trust them with. This concept is as important for applications as it is for people. After all, we've made applications the custodians of our information and the stewards of our resources. It's true across the enterprise -- applications hold critical information about our business and our customers -- and it's true on the desktop. I can't tell you how many times I've been asked how to write an applet that scans a user's drive so that one user can commandeer another user's browser or capture private information.

Java, being the network development platform that it is, has had to tackle the problem of trust head on. The result is the Java Security API and the Java Cryptography Architecture.

A brief glance backward

Before I dive headlong into APIs, code, and commentary, I'd like to briefly revisit last month's discussion. If you're joining us for the first time, you might want to back up a month and read " Signed and delivered: An introduction to security and authentication ." This column provides a thorough introduction to all the terms and concepts I'll be using this month.

Security and authentication address two crucial concerns: that of proving a message was created by a particular entity, and that of proving a message wasn't tampered with after it was created. One way of meeting both of these goals is by the use of digital signatures.

Digital signatures depend heavily on a branch of cryptography known as public-key cryptography. Public-key algorithms are characterized by the fact that they rely on a matched pair of keys (one private and one public) rather than a single key. An entity keeps its private key secret, but makes its public key available.

A digital signature algorithm takes as input a message and an entity's private key, and generates a digital signature. The digital signature is created in such a way that anyone can take the entity's public key and use it to verify that the entity in fact signed the message in question. Furthermore, if the original message has been tampered with, the signature can no longer be verified. Digital signatures provide one additional benefit: once an entity has signed and distributed a message, it's impossible for its originator to deny having signed the message (without claiming his or her private key was stolen, anyway).

Of engines and providers

The Java Cryptography API defines the Java toolkit for security and authentication. The Java Cryptography Architecture (JCA) describes how to use the API. To ensure the highest degree of flexibility for both the developer and the end user, the JCA embraces two guiding principles:

  1. The architecture should support algorithm independence and extensibility. A developer must be able to write applications without tying them too closely to a particular algorithm. In addition, as new algorithms are developed, they must be easily integrated with existing algorithms.

  2. The architecture should support implementation independence and interoperability. A developer must be able to write applications without tying them to a particular vendor's implementation of an algorithm. In addition, implementations of an algorithm provided by different vendors must interoperate.



To satisfy these two requirements, the developers of the Java Cryptography API based their design on a system of engines and providers.

Engines produce instances of message-digest generators, digital-signature generators, and key-pair generators. Each instance is used to carry out its corresponding function.

The canonical engine in the JCA is a class that provides a static method (or methods) named getInstance(), which returns an instance of a class that implements a cryptographically significant algorithm. The getInstance() method comes in both a one-argument and a two-argument form. In both cases, the first argument is the name of the algorithm. The JCA provides a list of standard names, though not all will be provided in any particular release. The second argument selects a provider.

The SUN provider

Only one provider -- SUN -- is supplied in JDK 1.1. SUN provides both an implementation of the NIST Digital Signature Algorithm (DSA), and an implementation of the MD5 and NIST SHA-1 message digest algorithms.

Class MessageDigest

We'll begin by looking at code that generates a message digest from a message.

   MessageDigest messagedigest = MessageDigest.getInstance("SHA");



   MessageDigest messagedigest = MessageDigest.getInstance("SHA", "SUN");



As I mentioned just a moment ago, the getInstance() method comes in two flavors. The first requires only the algorithm to be specified. The second requires both the algorithm and the provider to be specified. Both return an instance of a class that implements the SHA algorithm.

Next, we pass the message through the message-digest generator.

   int n = 0;
   byte [] rgb = new byte [1000];
   while ((n = inputstreamMessage.read(rgb)) > -1)
   {
      messagedigest.update(rgb, 0, n);
   }



Here, we assume the message is available as an input stream. This code works well for large messages of unknown length. The update() method also accepts a single byte as an argument for messages of a few bytes in length, and a byte array for messages of a fixed or predictable size.

   rgb = messagedigest.digest();



The final step involves generating the message digest itself. The resulting digest is encoded in an array of bytes.

As you can see, the JCA conveniently hides all the low-level implementation and algorithm-specific details, allowing you to work at a higher, more abstract level.

Of course, one of the risks of such an abstract approach is the increased likelihood that we won't recognize erroneous output resulting from bugs. Given the role of cryptography, this can be a significant problem.

Consider the "off-by-one" bug in the update line below:

   int n = 0;
   byte [] rgb = new byte [1000];
   while ((n = inputstreamMessage.read(rgb)) > -1)
   {
      messagedigest.update(rgb, 0, n - 1);
   }



C, C++, and Java programmers use the limit-minus-one idiom so frequently that typing it becomes almost automatic -- even when it's not appropriate. The code above will compile, and the executable will run without error or warning, but the resulting message digest will be wrong.

Luckily, the JCA is well thought out and well designed, making potential pitfalls like the one above relatively rare.

Before we move on to key-pair generators, take a look at

1 | 2 | 3 |  Next >
Resources
  • Download the complete source code http://www.javaworld.com/jw-01-1999/howto/jw-01-howto.zip
  • Java Security API Overview http://www.javasoft.com/products/jdk/1.1/docs/guide/security/JavaSecurityOverview.html
  • Java Cryptography Architecture http://www.javasoft.com/products/jdk/1.1/docs/guide/security/CryptoSpec.html
  • Sun's Java Security Page http://java.sun.com/security/index.html
  • RSA's FAQ on Cryptography http://www.rsa.com/rsalabs/faq/
  • Cryptographic Policy and Information http://www.crypto.com/
  • Read Todd's previous How-To Java columns http://www.javaworld.com/topicalindex/jw-ti-howto.html