Signed and delivered: An introduction to security and authentication

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

The Declaration of Independence hangs in the National Archive in Washington, D.C. At the bottom of the document appears John Hancock's flamboyant signature.

John Hancock did not pen his signature merely for artistic effect, however. Rather, he added it to certify to all who might read the declaration that he endorsed the document and its contents.

In a sense, John Hancock's signature welded his name, his reputation, and his person to the words in this momentous document. Whatever the future might have brought for the nascent state, his signature on the document ensured that his fortunes, good or bad, would follow suit. Had the American Revolution gone less favorably for the Americans, his signature might have cost him his life.

The simple act of placing our signature on a document is so much a part of modern life that its significance is often overlooked. Every day we routinely write our name on a variety of documents -- we write checks, we sign credit card receipts, we sign our children out of school -- in much the same manner as John Hancock did over 200 years ago with pen, paper, and ink.

But how do you sign something that doesn't exist in tangible form -- the stream of bytes making up a piece of e-mail, or an electronic credit card transaction? The receiver can ultimately trust the integrity of the information only to the extent that he can trust every hand the information has come in contact with. It seems the advent of the Information Age brought with it some thorny problems: High technology may make it easy to copy and distribute digital information, but it also makes it easy to modify or forge that same information. The solution to this problem lies in a branch of mathematics and computer science known as cryptography.

Cryptography

Most of us know that cryptography is associated with privacy. If I asked you to describe how cryptography is used, most of you would offer an explanation something like this: If a message's creator wants to ensure that the information contained in the message is kept private (that is, read by no one but the intended recipient), she encrypts her message and sends it across a (possibly) insecure channel to the recipient. The recipient then decrypts and reads the message.

While important, privacy is only one side of the cryptography coin. Less well known is cryptography's association with authentication. In case you aren't familiar with how authentication works, it goes something like this: The creator of a message wants to give the recipient a guarantee that the information within the message hasn't been tampered with. So the creator signs the message in such a way that any change to the information invalidates the signature. The recipient checks the signature against the information to verify the message.

These two areas of cryptography are orthogonal: Encryption can be used by itself, authentication can be used by itself, and both can be used together.

Even though the techniques used to encrypt information are interesting and well worth study, this month I'll focus on authentication.

A cryptographical lexicon

As is true of any field of study, cryptography has its own lexicon. What follows is a list of concepts and their meanings. If you've never studied cryptography before, take the time to read this section. If this isn't your first go 'round with cryptography, and you're now interested in learning about Java's implementation, you may want to skip this section and head right to A bit of history.

Key

In cryptographic circles, a key is a piece of information used to encrypt and/or decrypt information. Like a house key or a car key, a cryptographical key must be protected because anyone who has it can use it.

There are two types of key-based cryptography: secret-key and public-key.

Secret-key cryptography uses a single key that both encrypts and decrypts the information to be protected. Both the sender and the receiver must share the secret-key. Secret-key cryptography is also known as symmetric cryptography.

Public-key cryptography uses two keys: a public key and a private key. One key decrypts information encrypted with the other. Only the private key must be protected. Public key cryptography is used for authentication.

Message digest

A message digest algorithm computes a (typically shorter) fixed-size string from a message called the message digest (also known as a digital fingerprint). Any change to the original message will result in a different message digest, providing a way to verify the integrity (that is, check the fingerprint) of the original message.

The message digest algorithm creates a message digest from a message.

Digital signature

A digital signature is also generated from a message. It differs from a message digest because the private key of the message generator is incorporated into the computation. The result is a message that has been "signed" by the one who holds the private key. The computation is carried out in such a way that anyone can use the message generator's public key to verify that the entity signed it. A good digital signature algorithm guarantees that the digital signature can't be forged (assuming the private key is secret), that the signature is good for only the message from which it was generated, that the message cannot be changed without invalidating the signature, and that the message's authenticity can be verified.

The digital signature algorithm creates a digital signature from a message and a private key.

A bit of history

Applets provided the driving force that lead to the addition of authentication to the Java class library. In Java's pre-1.1 incarnation, applets (and other downloadable code) were kept within a virtual construct known as the "sandbox." From within the sandbox, applets were permitted only limited access (if any at all) to many system resources. This security model was egalitarian -- all applets were accorded the same rights and bound by the same limitations -- but ultimately too restrictive.

The problem with this politically correct approach to security was that not all applets are created equally; that is, not all applets deserved the untrustworthy moniker. Unfortunately, from the browser's point of view, there is no way to separate the wheat from the chaff. Specifically, the browser can't tell who created an applet, nor can it tell whether the applet was modified after it was created.

To address this problem, Sun created the Java Cryptography Architecture. The Java Security API is the piece of the architecture that deals with authentication.

Design Principles

Over the years, researchers have devised dozens of different ways to generate digital signatures. The algorithms they developed differ in speed, strength, and flexibility. If you look into the Java Security API, however, you won't find classes that implement these algorithms directly. To understand why not, you must first understand a bit about the principles that guided the development of the API.

The Java Cryptography Architecture was designed around two guiding principles. First, 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.

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

Let's look at why these are important.

Providers and engines

If the Java Security API had been designed in the same way as many class libraries, the library would contain classes that implement specific algorithms. For example, it might contain classes named DSA and RSA (for digital signatures) and MD5 and SHA (for message digests). The application developer would write the application around the available classes. If the developer later decided to use another algorithm (or another company's implementation of an algorithm), she would have to modify the source code.

The application's user would face a much larger problem though. In order to use the application, he would need access to the library the developer used. Unfortunately, the library may not be exportable (many countries restrict the exportation of cryptography), the library may not be usable (some countries restrict the use of cryptography), and/or the library may not perform as well as another library the user has access to. Worse, the user is unlikely to have access to the source code.

For reasons like these, the Java Cryptography Architecture was built upon the concept of providers and engines.

A Cryptography package provider (or provider) is a package or library that provides an implementation of some subset of the Java Security API. The Java Security API comes with a default provider. Other companies and individuals can implement their own versions of popular (or newly developed) cryptographic algorithms and package them as providers.

An engine provides a uniform interface to providers (including Sun's default provider). The MessageDigest class is an engine that generates message digest instances. The same is true of the Signature class. These classes are not meant to be instantiated directly. Instead, the engines return instances of classes provided by the installed providers.

This approach frees developers of many algorithm-specific details, and the allows users to replace the standard provider with an alternative that meets their needs.

Here's a brief glimpse of what the code looks like:

   // The getInstance() method is a static method of the
   //  Signature class.  It returns an instance of the
   //  installed class that implements the SHA/DSA
   //  digital signature algorithm.
   Signature signature = Signature.getInstance("SHA/DSA");

Conclusion

Now that you understand the importance of signatures (both tangible and digital) and a little about how they work within the framework of the Java Cryptography Architecture, it's time to get our hands dirty. Next month I'll describe the APIs in detail and I'll shows you how to write code that signs and verifies data.

Todd Sundsted has been writing programs since computers became available in convenient desktop models. Though originally interested in building distributed object applications in C++, Todd moved on to the Java programming language when it became the obvious choice for that sort of thing. In addition to writing, Todd is President of Etcee which offers training, mentoring, consulting, and software development services.

Learn more about this topic

  • 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/
  • Yahoo directory for Security and Encryption http://dir.yahoo.com/Computers_and_Internet/Security_and_Encryption/
  • Cryptographic Policy and Information http://www.crypto.com/
  • See all of Todd's previous How-To Java columns http://www.javaworld.com/topicalindex/jw-ti-howto.html