Read an Excerpt
Java Cryptography ExtensionsPractical Guide for Programmers
By Jason Weiss
MORGAN KAUFMANN PUBLISHERSCopyright © 2004 Elsevier Inc.
All right reserved.
Chapter OneUnderstanding Java's Cryptographic Architecture
Cryptography has its roots in very complex (and often theoretical) mathematics. As a result, computers and cryptography complement each other well. Today's advanced cryptographic operations involve mind-boggling amounts of mathematical calculations, and computers perform these calculations exponentially faster than a human can perform them by hand. The Java language includes a well-defined architecture that allows you to include cryptographic services in your designs without fully comprehending the mathematical proofs or calculations behind the algorithms. However, this does not mean that it is not important to understand the algorithms (i.e., the cryptographic tools) at your disposal. As an analogy, a screwdriver is a wonderful tool for driving a wood screw into a piece of wood; however, that same screwdriver would not be effective if the object being driven was a finishing nail.
Performing cryptographic operations with Java does not involve hundreds of lines of code or require a Ph.D. in mathematics from MIT. Perhaps the most visible aspect of cryptography is encryption, which can be accomplished in Java using as little as seven lines of code, not counting proper exception handling. Here is a brief example demonstrating a simple encryption operation. Don't worry about comprehending every aspect of the program just yet—we have the whole book to explore Java's cryptographic capabilities!
NOTE: Please review the preface for code style information and download instructions.
This example demonstrates some of the core tenets of cryptography with Java in action. It shows the creation of a secret key that is used to translate an unencrypted message into an encrypted one. The output of this sample will differ each time it is run because the key is essentially random; when I ran it the output looked like this:
Resulting Cipher Text:
106 93 20 33 -86 -110 109 87 57 31 95 5 -67 36 -39 -7 117 -50 119 -26 -51 -40 118 105 68 5 -29 -47-90 -89 -70 84
The example also demonstrates the use of engine classes, classes that are not instantiated directly. Alas, we do not want to get ahead of ourselves, so we will rewind and start by defining Java's cryptographic infrastructure.
1.1 Java and Cryptography
From its humble birth through its present day incarnation, the Java language continues to offer developers a computing platform that swells with cryptographic functionality. Because of U.S. export laws at the time, the functionality is split between two different libraries, the JAVA Cryptography Architecture (JCA) and the Java Cryptography Extensions (JCE). Figure 1.1 shows the relationship between these two cryptographic libraries, displaying some of the capabilities covered throughout this book. The first library, JCA, is tightly integrated with the core Java APIs. The second library, JCE, builds off of the concepts and capabilities found in the JCA. The JCE houses many of the advanced cryptographic operations that were previously under U.S. export control. However, the political landscape has changed, and as of JDK 1.4, the JCA and JCE are present "out of the box" without requiring a separate download of the JCE. JCE 1.2.2 remains available as a separate download for JDK 1.2 and 1.3 installations, and it supports the same suite of engines found in JDK 1.4.
Cryptography is often associated with the sole process of encryption/decryption; however, the true scope of the field is actually much larger than this, encompassing a wide array of operations to include: * Message digests or hashing
* Message authentication codes
* Digital signatures
* Digital certificates
* Cryptographically secure random numbers
* Secret key generation and storage
* Key agreements
Clearly the field of cryptology spans much more than just encryption/decryption. One notable absence is Base64 encoding, which is not encryption and not considered part of the field of cryptography. The act of applying a Base64 encoding to a document does not suffice as a form of hiding sensitive data. Base64 encoding is documented in an RFC, and was designed to convert 8-bit binary data into a 6-bit printable representation. For more details on Base64 encoding, see Appendix A.
Before we can adequately discuss calling cryptography operations from within a Java class, it is imperative developers have a firm grasp on the infrastructure Java provides to make these operations possible. The JCA serves as the proverbial cornerstone of Java's cryptographic architecture, and it is the most logical place to start.
1.2 Java Cryptography Architecture
Security, in particular cryptography, has always been a core API of Java, located in and below the java. security package. The JCA was explicitly designed to provide and expose cryptographic operations to developers in need of such functionality. The advent of the Java2 SDK revealed a substantially improved JCA architecture, and we won't spend too much time living in the past discussing the way it used to be before the facelift. The architects of the JCA were given several broad but guiding design principles that had to be met.
* Algorithm independence
* Algorithm extensibility
* Implementation independence
* Implementation interoperability
Developers who require the use of cryptographic operations in their code dramatically benefit from these design principles. In fact, the elegance of the final design lies in its ability to let the developer decide what level of interaction they want to have with the underlying mechanics of the JCA, that is, a little or a lot. For example, developers can simply request a message digest, or they can be extremely specific and indicate that they require a specific message digest from an explicitly named cryptographic service provider, or simply a provider. A provider implements one or more Java packages that declare concrete implementations of well-known cryptographic features, like a key store that serves as the physical repository for secret keys and key pairs. While there will be the presence of Java classes included with the provider implementation, it is possible that their complete solution encompasses software and hardware. For example, the provider may use a Smart Card as the physical key store repository, and their key store implementation (software) knows how to interact with the Smart Card reader (hardware) attached to the computer.
The first guiding characteristic of the JCA architecture was Algorithm independence, which serves as a mechanism to classify cryptographic operations into well-known (read well-documented) categories. The JCA refers to each category as an engine, which is simply another name for a Java class. To ensure consistency between this book and the JCA documentation, we will use the engine nomenclature. The following is a complete list of engines found in the JCA:
* MessageDigest produces a hash value for a given message
* Signature produces a digital signature of a document
* KeyPairGenerator produces a pair of keys that, for example, could sign a document
* KeyFactory breaks down a key into its discrete parts and vice versa
* KeyStore manages and stores various secret keys and key pairs
* SecureRandom produces random numbers suitable for use in cryptology
* AlgorithmParameters manages the encoding and decoding of the parameters for a given cryptographic algorithm
* AlgorithmParameterGenerator generates a complete set of parameters required for a given cryptographic algorithm
* CertificateFactory creates public key certificates and certificate revocation lists
* CertPathBuilder establishes relationship chains between certificates
* CertStore manages and stores certificates and certificate revocation lists
Each of these engines will be discussed in more detail and used throughout the text. To provide a high level of algorithm independence, each JCA engine uses the factory design pattern, as documented by Gamma et al in their landmark work. Essentially, each engine uses a factory method design, where the method is always declared static. Each factory method always returns back to the engine class itself (section 1.4 will briefly explore the Service Provider Interface [SPI] that provider's follow to see how this mechanism actually works). Here are two small code examples that demonstrate accessing the MessageDigest engine to obtain instances of different message digest algorithms (the algorithm parameter passed into any JCA or JCE engine is always case-insensitive):
MessageDigest md5Implementation = MessageDigest. getInstance("MD5"); MessageDigest sha1Implementation = MessageDigest.getInstance("SHA-1");
The decision by the JCA architects to use this design pattern in each engine class benefits developers and providers. As you read this, ongoing research on cryptographic operations is occurring at universities and cutting-edge companies around the globe. Providers can rest assured this research translates into newer, more powerful algorithms that can easily be accessed by Java developers around the globe. Developers benefit from the design because they do not have to worry about being locked into either single provider or obsolete algorithms. This leads into JCA's next design goal.
A by-product of the JCA's algorithm independence is its ability to support algorithm extensibility, which, simply stated, provides a mechanism for adding new algorithms that can be classified and exposed through one of the supported engines. Why should you be forced to use one and only one implementation of a cryptographic function? You should not. Algorithm extensibility can be thought of as capitalism for cryptographic algorithm engineers. If someone can successfully write a message digest that is five times faster and more collision-resistant to a greater bit-length than existing message digest implementations, then it should be extremely easy to access this new algorithm. Let's revisit the MessageDigest engine and see how we would access a new state-of-the-art message digest:
MessageDigest fastImplementation = MessageDigest. getInstance("SuperYastHash") ;
Implementation independence represents the notion that developers should be free to simply say "I need an MD5 message digest" and immediately get an instance of a class that provides such functionality without requiring the invocation of a slue of provider specific methods. Implementation independence essentially offers the developer a choice of how to handle the presence of providers. Each of the earlier MessageDigest engine examples was implementation independent, but in some rare cases the developer may choose to waive this property and explicitly request a named provider. This example requests that the BC provider's MD5 message digest implementation be returned:
MessageDigest bcMdSImplementation = MessageDigest. getInstance("MD5", "BC");
The Sun Java Runtime Environment (JRE) includes the SUN provider that implements one or more solutions for each of the JCA engines. However, it can't be stressed enough that the very nature of the JCA's architecture gives developers the opportunity to plug-in additional providers. Each provider determines what physical cryptographic implementations they wish to include in their solution. Theoretically, a provider may decide to only provide a single logical implementation of a random number generator, or they may opt to include a full spectrum of solutions for every engine.
NOTE: Throughout the rest of the text the term "developer" will refer to the downstream software engineer, that is, you or I. The term "provider" will refer to the upstream software engineer, that is, the engineers who developed the SUN provider that comes with the JCA.
There are numerous third party providers on the market; some are open source and others are commercial frameworks that require licensing. In the open source community, two popular choices include implementations from The Legion of the Bouncy Castle (http://www.bouncycastle.org) and Cryptix (http://www.cryptix.org). I will stop short of recommending a specific provider here, and the book's code examples will use a mixture of implementations from open source providers. Sun's web site also publishes a list of providers at http://java.sun.com/products/jce/jce122_providers.html.
Excerpted from Java Cryptography Extensions by Jason Weiss Copyright © 2004 by Elsevier Inc. . Excerpted by permission of MORGAN KAUFMANN PUBLISHERS. All rights reserved. No part of this excerpt may be reproduced or reprinted without permission in writing from the publisher.
Excerpts are provided by Dial-A-Book Inc. solely for the personal use of visitors to this web site.