BUY THIS BOOK
Add to Cart

Print Book $39.99


Safari Books Online

What is this?

Add to UK Cart

Print Book £20.95

What is this?

Looking to Reprint this content?


Java Cryptography
Java Cryptography

By Jonathan Knudsen
Price: $39.99 USD
£20.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction
This book is about cryptographic programming in Java. This chapter presents the "big picture" of secure systems and quickly moves to the specifics of cryptography. I begin by describing secure systems design. Next I explain what cryptography is and describe its role in secure systems development. This chapter concludes with a pair of "teaser" examples: two short Java applications that will whet your appetite for the rest of the book.
Computer applications enable people to do work. Applications are parts of a larger system (a business, usually) that also involves people, fax machines, white boards, credit cards, paper forms, and anything else that makes the whole system run. Secure systems make it hard for people to do things they are not supposed to do. For example, a bank is designed as a secure system. You shouldn't be able to withdraw money from someone else's account, whether you try at the teller window, or by using the bank machine, or by telephone. Of course, you could bribe the teller or disassemble the bank machine, but these things are usually not worth the cost.
Secure systems are designed so that the cost of breaking any component of the system outweighs the rewards. Cost is usually measured in money, time, and risk, both legal and personal. The benefits of breaking systems are generally control, money, or information that can be sold for money. The security of the system should be proportional to the resources it protects; it should be a lot harder to break into a brokerage than a magazine subscription list, for example.
The term "secure systems" is a little misleading; it implies that systems are either secure or insecure. In truth, there is no absolute security. Every system can be broken, given enough time and money. Let me say that again, every system can be broken. There are more secure and less secure systems, but no totally secure systems. When people talk about secure systems, they mean systems where security is a concern or was considered as part of the design.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Secure Systems
Computer applications enable people to do work. Applications are parts of a larger system (a business, usually) that also involves people, fax machines, white boards, credit cards, paper forms, and anything else that makes the whole system run. Secure systems make it hard for people to do things they are not supposed to do. For example, a bank is designed as a secure system. You shouldn't be able to withdraw money from someone else's account, whether you try at the teller window, or by using the bank machine, or by telephone. Of course, you could bribe the teller or disassemble the bank machine, but these things are usually not worth the cost.
Secure systems are designed so that the cost of breaking any component of the system outweighs the rewards. Cost is usually measured in money, time, and risk, both legal and personal. The benefits of breaking systems are generally control, money, or information that can be sold for money. The security of the system should be proportional to the resources it protects; it should be a lot harder to break into a brokerage than a magazine subscription list, for example.
The term "secure systems" is a little misleading; it implies that systems are either secure or insecure. In truth, there is no absolute security. Every system can be broken, given enough time and money. Let me say that again, every system can be broken. There are more secure and less secure systems, but no totally secure systems. When people talk about secure systems, they mean systems where security is a concern or was considered as part of the design.
The job of the application programmer is to make an application that costs as much to break as any other component in the system. Building a secure application usually involves a three-way balancing act. The cost of having your application broken must be balanced against both the application's cost and the application's ease of use. You could spend a million dollars to build a very secure application, but it wouldn't make sense if the cost of a break-in would be measured only in thousands. You might build a moderately secure application instead, but it won't do you any good if it's too hard to use.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Cryptography
Cryptography is the science of secret writing. It's a branch of mathematics, part of cryptology . Cryptology has one other child, cryptanalysis , which is the science of breaking (analyzing) cryptography.
The main security concerns of applications are addressed by cryptography. First, applications need assurance that users are who they say they are. Proving identity is called authentication . In the physical world, a driver's license is a kind of authentication. When you use a computer, you usually use a name and password to authenticate yourself. Cryptography provides stronger methods of authentication, called signatures and certificates. I'll talk about these in Chapter 6.
Computer applications need to protect their data from unauthorized access. You don't want people snooping on your data (you want confidentiality ), and you don't want someone changing data without your knowledge (you want to be assured of your data's integrity). Data stored on a disk, for example, may be vulnerable to being viewed or stolen. Data transmitted across a network is subject to all sorts of nefarious attacks. Again, cryptography provides solutions; I'll discuss them in detail in Chapter 6 and Chapter 7.
So what can you do with cryptography? Plenty. Here are just a few examples:
Secure network communications
Cryptography can protect your data from thieves and impostors. Most web browsers now support SSL, a cryptographic protocol that encrypts information before it is transmitted over the Internet. SSL allows you to buy things, using your credit card number, without worrying too much that the number will be stolen.
Secure hard disk
You can encrypt the files on your hard disk so that even if your enemies gain physical access to your computer, they won't be able to access its data.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Platform Security
One of the things that makes Java so interesting is the security features that are built in to the platform itself. Java was designed to enable small programs, applets, to be downloaded and run without danger. Applets are nifty, but without the right precautions they would be very dangerous. Java's bytecode verifier, ClassLoader, and SecurityManager work in tandem to safely execute downloaded classes.
The Java Development Kit (JDK) 1.2 (in beta as this book goes to press) includes some interesting security enhancements, including the concepts of protection domains, permissions, and policies. I won't rehash Java's platform security features here. For a good summary, see Exploring Java by Pat Niemeyer and Joshua Peck (O'Reilly). For a more thorough treatment, including the new JDK 1.2 features, see Java Security by Scott Oaks (O'Reilly). The security that the Java platform provides comes "for free" to application developers. Application-level security, however, needs to be developed into the application. This book is about programming application-level security through the use of cryptography.
Application-level security can compensate for an insecure platform, in some cases. Internet Protocol (IP) networks, for example, are insecure. It's impossible to prevent packet snooping, Domain Name System (DNS) spoofing, or foul-ups like misdelivered email. A carefully crafted application, however, can compensate for an insecure platform like the IP network. If the body of your email is encrypted, for example, it won't do anyone any good to view a message. If you encrypt all data that you send over the network, then a packet sniffer won't be able to pick up much useful information.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Astute Inequalities
At the 1997 JavaOne conference, the Java Security Architect, Li Gong, gave a presentation on Java security. One of his slides is particularly useful for understanding Java security and cryptography. It contains a list of five inequalities, to which I've added explanations.
Security != cryptography
Adding cryptography to an application will not make it secure. Security is determined by the overall design and implementation of a system; cryptography is a tool for building secure systems.
Correct security model != bug-free implementation
Even if you have a great design (model), bugs in your implementation can be exploited by attackers. With a correct design, however, you can focus on debugging the implementation. If your design is not secure, you have to go all the way back to the drawing board before you even think about debugging.
Testing != formal verification
Although testing is a great idea, it won't prove to anyone that a system is secure. In the real world, "formal verification" means extensive reviews of your system's design and implementation by knowledgeable security people. A cheap way to do this is to post your application's source code to the Internet and invite people to poke holes in it.
Component security != overall system security
System security is a chain, and any link can be broken. Even if the components of a system are secure, they may interact in insecure ways.
Java security != applet containment
A lot of the buzz about Java security has centered around the applet "sandbox" and the security of applets running in browsers. (Go look at
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Hello, zoT1wy1njA0=!
Let's jump right into Java cryptography with some examples. The first example can be run by anyone who has the Java Development Kit (JDK) 1.1 or later installed. The second example uses classes from the Java Cryptography Extension (JCE). To run it, you will need to download and install the JCE, which is available in the United States and Canada only at http://java.sun.com/products/jdk/1.2/jce/. Chapter 3, discusses these pieces of software and how they fit together.
Don't worry if you don't understand everything in these programs. They are demonstrations of what you can do with cryptography in Java, and everything in them will be explained in more detail elsewhere in the book.
Our first example demonstrates how a message digest works. A message digest takes an arbitrary amount of input data and creates a short, digested version of the data, sometimes called a digital fingerprint, secure hash, or cryptographic hash. Chapter 2 and Chapter 6 contain more detail about message digests. This program creates a message digest from a file:
import java.io.*;
import java.security.*;

import sun.misc.*;

public class Masher {
  public static void main(String[] args) throws Exception {
    // Check arguments.
    if (args.length != 1) {
      System.out.println("Usage: Masher filename");
      return;
    }

    // Obtain a message digest object.
    MessageDigest md = MessageDigest.getInstance("MD5");

    // Calculate the digest for the given file.
    FileInputStream in = new FileInputStream(args[0]);
    byte[] buffer = new byte[8192];
    int length;
    while ((length = in.read(buffer)) != -1)
      md.update(buffer, 0, length);
    byte[] raw = md.digest();

    // Print out the digest in base64.
    BASE64Encoder encoder = new BASE64Encoder();
    String base64 = encoder.encode(raw);
    System.out.println(base64);
  }
}
To use this program, just compile it and give it a file to digest. Here, I use the source code, Masher.java, as the file:
C:\ java Masher Masher.java
nfEOH/5M+yDLaxaJ+XpJ5Q==
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Concepts
At the application programming level, there are many options for making a program secure. Cryptography is the biggest, baddest tool in the application programmer's arsenal. But it is important to realize that a cryptographically enabled program is not necessarily a secure one. Without a carefully planned and constantly scrutinized security strategy, cryptography won't do you much good.
Correctly used, cryptography provides these standard security features:
  • Confidentiality assures you that data cannot be viewed by unauthorized people.
  • Integrity assures you that data has not been changed without your knowledge.
  • Authentication assures you that people you deal with are not imposters.
Random numbers are used in many cryptographic algorithms. I'll talk a little bit about computer-generated random numbers at the end of the chapter. I'll wrap up by discussing the cryptographic algorithms used in this book.
Most of us don't want other people to read our mail, which is why we use letters instead of postcards. Almost all information on the Internet is transmitted on the equivalent of postcards. Even if nobody is deliberately spying on you, electronic mail is frequently misdelivered. If you mistype a recipient's address, your mail might get sent to a system administrator somewhere. It's surprisingly easy for information you thought was confidential to be available to hundreds of thousands of people on the Internet.
Even data on your computer's hard disk is surprisingly available to your coworkers, the people who clean your office, and anyone else who might have physical access to your computer. If you are considering leaving your current job, you probably wouldn't feel comfortable leaving a copy of your résumé on your office computer; someone might find it.
To protect your information from prying or curious eyes, you need to take extra precautions. A common way to protect information is to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Confidentiality
Most of us don't want other people to read our mail, which is why we use letters instead of postcards. Almost all information on the Internet is transmitted on the equivalent of postcards. Even if nobody is deliberately spying on you, electronic mail is frequently misdelivered. If you mistype a recipient's address, your mail might get sent to a system administrator somewhere. It's surprisingly easy for information you thought was confidential to be available to hundreds of thousands of people on the Internet.
Even data on your computer's hard disk is surprisingly available to your coworkers, the people who clean your office, and anyone else who might have physical access to your computer. If you are considering leaving your current job, you probably wouldn't feel comfortable leaving a copy of your résumé on your office computer; someone might find it.
To protect your information from prying or curious eyes, you need to take extra precautions. A common way to protect information is to encrypt it at the sending end and decrypt it at the receiving end. Encryption is the process of taking data, called plaintext , and mathematically transforming it into an unreadable mess, called ciphertext . Decryption takes the ciphertext and transforms it back into plaintext. The mathematical algorithm that performs the transformations is called a cipher . Figure 2.1 shows how this works.
Figure 2.1: Operation of a cipher
To protect data on a hard disk, you would encrypt it before writing it on the disk. You could decrypt the ciphertext whenever you wanted to look at the information (or to print copies of your résumé).
A trivial cipher is rot13 . The algorithm for rot13 simply rotates each character of a text message through 13 positions. One application of rot13 transforms plaintext to ciphertext, and a second application of rot13 transforms the ciphertext to plaintext. Rot13 was originally developed to render potentially offensive jokes unreadable in Internet newsgroups. Anyone who inadvertently stumbled upon one of these jokes would just see a jumble of rot13 ciphertext. Those who really wanted to see the jokes had to decrypt them first.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Integrity
When you download a file over the Internet, you'd like to be sure that the file you get is the one you wanted; you'd like to be assured of the file's integrity. Many people make the following assumptions, consciously or unconsciously, when they download a file from a server:
  • The file is not a malicious program.
  • The file has not been replaced, unbeknownst to the server's owners, by a malicious program.
  • There is not another computer between you and the server, sending you a different file than the one you want or modifying the file that gets sent to you. This is the "man-in-the-middle" attack.
This is a hefty batch of assumptions, not stuff that gives you a warm fuzzy feeling. Although these assumptions are geared toward executable files, any type of download is at risk. You want to be sure that you get what you thought you were getting.
For example, Maid Marian runs an FTP server. One of the files she puts on it, for public consumption, is her schedule for the next couple of weeks. Journalists and paparazzi check this schedule regularly, as does Robin Hood. Robin Hood is always suspicious, so he'd like some assurance that the schedule file he downloads is not a counterfeit.
A message digest can be used to verify data integrity. A message digest is a special number calculated from a set of input data. Figure 2.5 shows how this works.
Figure 2.5: A message digest
Let's try to use the message digest in our previous example to ensure data integrity. It involves a few steps:
  1. Marian calculates the message digest of her schedule file and places the digest value on the server.
  2. Robin Hood downloads both the file and the message digest.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Authentication
At some fundamental level, you want to be sure that the people you deal with are really who they say they are. The process of proving identity is called authentication.
When you call someone on the telephone, you identify yourself by saying your name. The sound of your voice authenticates you to the person on the other end of the line. When you use an automated bank machine, your bank card identifies you and your secret code authenticates you. Someone else using your bank card would presumably not know your code and thus could not pretend to be you.
Most computer systems use a user ID and password combination for identity and authentication. You identify yourself using a user ID and authenticate your identity with a password.
An asymmetric cipher can be used for authentication. Suppose Marian encrypts her schedule file using her private key. When Robin Hood downloads Marian's schedule file, he decrypts it using her public key. He can be sure that the file is from Marian because only Marian's private key could have encrypted the file in the first place.
Asymmetric ciphers are computationally expensive, a nice computer science synonym for slow. Unfortunately, it's not practical to use an asymmetric cipher for entire conversations. Typically, an asymmetric cipher is used to authenticate the participants of a conversation; the conversation itself is encrypted with a symmetric cipher, using a special one-time key called a session key. Now the challenge is exchanging the session key without having anyone else find out about it. The Secure Sockets Layer (SSL) does exactly this; I'll look at it in detail in Chapter 7.
Let's consider another scenario. Will Scarlet also runs an FTP server, and Robin Hood wants to download a file from that server. Will has signed the file. Unfortunately, Robin Hood does not have Will's public key on hand. He could download the public key from Will's server, but how would he know that the public key hadn't been tampered with?
If Marian already knows Will's public key, she can help Robin Hood, using something called a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Random Numbers
Random numbers are crucial in cryptography. They are used to create cryptographic keys and, in some cases, to encrypt or sign data. A random number is one whose value cannot be predicted. A random number generator (RNG) is a device that produces random numbers.
It's fairly easy for humans to generate random numbers. You can sit down with a pair of dice or a deck of cards, and generate as many random numbers as you want. It's much harder to convince a computer to generate random numbers. Computers are designed to be methodical and deterministic. Some computers can use specialized hardware to generate random numbers, by measuring an unstable electronic circuit or radioactive decay or some other random process. Most of us, however, don't have this kind of hardware. Furthermore, such solutions tend to be very platform-specific, which is not good for Java programmers.
As with horseshoes and hand grenades, "close" has to be good enough. Computers, therefore, use a pseudo-random number generator (PRNG) as a source of "random" data. A PRNG uses an algorithm to generate an endless sequence of ostensibly random numbers. Usually a message digest function is used iteratively to make it difficult to determine the past or future output of the PRNG. The PRNG is initialized, or seeded , using a small set of truly random data.
That's the way it's supposed to work. Programmers who are not familiar with cryptography usually seed the PRNG with the current value of the system clock. Anyone with access to the same PRNG can use the same seed, which allows them to make good guesses of keys and other random data that has been generated. Let's say, for example, that Marian generates a key pair using a PRNG seeded with the system clock. The Sheriff of Nottingham, if he knows approximately when Marian generated the key pair, can easily guess the seed value for the PRNG. He can then generate the same key pair and cause Marian all sorts of trouble. Even if he doesn't know exactly when Marian generated the key pair, just knowing an approximate time makes his life a lot easier. He can write a program to try a whole range of seed values until he manages to generate the same key pair that Marian generated.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Algorithms
In this section, I'll briefly discuss the impact of key size on security. Then I'll introduce the algorithms that will be used in this book.
Key size affects the security of signatures and ciphers. In general, the longer the key, the harder it will be for an attacker to decrypt your ciphertext or forge a signature. Basically, longer keys have more possible values. If your attacker is trying every possible key to find the right one (a brute-force attack), a longer key gives the attacker more work. Keep in mind, however, that key size is only part of the story. A long key won't do you much good if the algorithm itself is weak.
Asymmetric ciphers and signatures have a variable key size. It's up to your application or users to choose an appropriate key length. Although longer keys are more secure, they are also slower. Picking the right key size is a trade-off between finding a comfortable level of security and having your application run too slowly.
Symmetric ciphers can either have a fixed or variable key length; it depends on the algorithm.
Table 2.1 summarizes the algorithms that I'll use in this book. We'll implement the ElGamal signature and cipher algorithms in Chapter 9. All the other algorithms have been implemented as part of software supplied by Sun.
Table 2.1: Algorithms Used in This Book
Name
Type
Reference
MD5
Message digest
RFC 1321 ftp://ds.internic.net/rfc/rfc1321.txt
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Architecture
Java cryptography software comes in two pieces. One piece is the JDK itself, which includes cryptographic classes for authentication. The other piece, the Java Cryptography Extension (JCE), includes so-called "strong cryptography." In this chapter I'll talk about these two pieces of software and the architecture that houses them. In particular, I'll cover:
  • The separation of cryptographic concepts and implementations (algorithms)
  • The separation of the public methods of a concept class from its inner workings
  • The use of factory methods in the cryptography classes
  • The provider architecture
The Java Security API is a set of packages that are used for writing secure programs in Java. In particular, the classes and interfaces in the following packages are part of the Security API:
  • java.security
  • java.security.cert
  • java.security.interfaces
  • java.security.spec
  • javax.crypto
  • javax.crypto.interfaces
  • javax.crypto.spec
Here are the major pieces and their acronyms:
JCA
The overall design of the cryptography classes is governed by the Java Cryptography Architecture (JCA). The JCA specifies design patterns and an extensible architecture for defining cryptographic concepts and algorithms. The JCA is designed to separate cryptographic concepts from implementations. The concepts are encapsulated by classes in the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Alphabet Soup
The Java Security API is a set of packages that are used for writing secure programs in Java. In particular, the classes and interfaces in the following packages are part of the Security API:
  • java.security
  • java.security.cert
  • java.security.interfaces
  • java.security.spec
  • javax.crypto
  • javax.crypto.interfaces
  • javax.crypto.spec
Here are the major pieces and their acronyms:
JCA
The overall design of the cryptography classes is governed by the Java Cryptography Architecture (JCA). The JCA specifies design patterns and an extensible architecture for defining cryptographic concepts and algorithms. The JCA is designed to separate cryptographic concepts from implementations. The concepts are encapsulated by classes in the java.security and javax .crypto packages. Implementations are supplied by cryptographic providers. (There's more on this later, in the section on the provider architecture.) The JDK 1.2 comes with a default provider, named SUN, that implements a few cryptographic algorithms.
JCE
The U. S. government considers certain types of cryptographic software to be weapons and limits their export. Sun, therefore, split its cryptography classes into two groups. The first group is included in the java.security.* packages that are part of JDK 1.2. These classes can be exported without restriction. The second group, the Java Cryptography Extension, is for U.S. and Canadian distribution only. The JCE is an extension of the JCA and includes another cryptographic provider, called SunJCE.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Concept Classes
The java.security and javax.crypto packages have classes and interfaces that represent the cryptographic concepts that were introduced in Chapter 2. Table 3.2 summarizes the cryptographic concepts represented in the classes included in JDK 1.2 and JCE 1.2.
Table 3.2: Cryptographic Concept Classes
Class or Interface
Description
java.security.cert.Certificate
A cryptographic certificate
javax.crypto.Cipher
A cipher
java.security.Key , java.security.PrivateKey , java.security.PublicKey , javax.crypto.SecretKey
A key, used for signing or encryption
javax.crypto.KeyAgreement
A secret key exchange protocol
java.security.KeyFactory
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
API and SPI
The methods in the cryptographic concept classes are divided into two groups. The first group of methods is the Application Programming Interface, or API. It consists of all public methods that you can use to work with an instance of a concept class. The second group of methods is the Service Provider Interface, or SPI. This is the set of methods that subclasses must implement. By convention, SPI method names all begin with engine.
In JDK 1.1, the SPI and API methods were mixed together in the cryptographic concept classes. The java.security.Signature class, for example, contained API methods like initSign() and verify() as well as SPI methods like engineInitSign() and engineVerify(). To implement a signature algorithm, you would create a subclass of Signature and define all the SPI methods.
In JDK 1.2, API methods and SPI methods are split into separate classes. Signature, for example, now contains only API methods. A separate class, java .security.SignatureSpi, contains all the SPI methods. To implement a signature algorithm now, create a subclass of SignatureSpi and define the SPI methods. Whenever you implement a cryptographic algorithm, you'll need to follow a similar process. In Chapter 7, and Chapter 9, we'll create implementations for KeyPairGenerator, Signature, and other concept classes by implementing the SPI of those classes.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Factory Methods
The JCA makes extensive use of factory methods to supply instances of its classes. The basic model is to ask a concept class for an instance that implements a particular algorithm. For example, the following code produces a MessageDigest instance that uses the MD5 algorithm:
MessageDigest md5;
md5 = MessageDigest.getInstance("MD5");
Like all the factory methods in the JCA, this one will throw a NoSuchAlgorithmException if the requested algorithm is not available.
The instance that is returned to you from a factory method is some descendant of the class you asked for. But it doesn't really matter; this is one of the perks of object-oriented programming. The preceding code might return a sun.security.provider.MD5, but you can do everything you need to do by treating it as a MessageDigest.
The following concept classes have getInstance() methods:
  • javax.crypto.Cipher
  • javax.crypto.KeyAgreement
  • java.security.KeyFactory
  • javax.crypto.KeyGenerator
  • java.security.KeyPairGenerator
  • javax.crypto.Mac
  • java.security.MessageDigest
  • javax.crypto.SecretKeyFactory
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Standard Names
Asking for algorithms by name implies that there is a standard name for each cryptographic algorithm. Table 3.3 shows the standard algorithm names that are supported by the SUN provider (supplied with JDK 1.2) and the SunJCE provider (part of the JCE). For more information on the algorithms themselves, refer back to Chapter 2.
Table 3.3: Standard Algorithm Names
Concept class
Algorithms supported by Sun
Algorithms supported by SunJCE
Cipher
DES, DESede, PBEWithMD5AndDES
KeyAgreement
DH
KeyFactory
DSA
KeyGenerator
DES, DESede
KeyPairGenerator
DSA
Mac
HmacMD5, HmacSHA1
MessageDigest
MD5, SHA-1
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Provider Architecture
At the root of the JCA is the idea of security providers. A provider supplies algorithms for the cryptographic concept classes. In practice, a provider is a collection of algorithm classes headed up by a java.security.Provider object. This is confusing terminology; provider (small p) refers to the concept, while Provider refers to a specific class.
When you use a factory method to request a specific algorithm, it is the provider architecture, behind the scenes, that supplies the algorithm. The java.security.Security class manages security providers. When a program calls one of the factory methods to obtain a useful cryptographic object, the factory method asks the Security class to provide the object. The Security class, in turn, examines its providers to find a class that matches the requested cryptographic concept and algorithm.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Key Management
To exchange data securely, you'll need to keep track of your own private and public keys as well as the public keys of all the people with whom you wish to converse securely. What you need is something like an address book that correlates individuals to their keys and certificates. The JCA contains support for exactly this, based around the Identity and KeyStore classes. For more information about this, take a look at Chapter 5.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
The JCA is more a state of mind than a concrete set of classes. Most importantly, it separates cryptographic concepts from their implementations. The concepts are represented by the classes in the java.security and javax.crypto packages, while implementations are supplied by cryptographic providers. Using cryptography in a Java program is wonderfully simple. Because the API exposes concepts, rather than implementation details, it's easy to change the algorithms or providers that your program uses. Under the hood, there's a more complicated picture, but you won't have to worry about this unless you want to do something tricky, like develop your own provider.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Random Numbers
Random numbers are important for cryptography. As we discussed in Chapter 2, computers are not very good at producing truly random data. Instead, they rely on a pseudo-random number generator (PRNG). A cryptographically strong PRNG, seeded with truly random values, is a PRNG that does a good job of spewing out unpredictable data. But if the PRNG is not cryptographically strong, or if the seed data is not random, the security of your application can be compromised.
In this chapter, I'll talk about a cryptographically strong PRNG that was introduced in JDK 1.1, java.security.SecureRandom. The rest of the chapter discusses how to produce random seed data from keyboard events.
The JDK includes a class, java.util.Random, that implements a PRNG. Although it's fine for light-duty use, it has the following shortcomings:
  • It uses an algorithm that produces a predictable sequence of numbers.
  • If you don't give Random a seed value, it uses the value of the system clock. This is a predictable seed. Let's say that you create a random number in order to create a cryptographic key. If an attacker knows when you created the random number, even approximately, he or she can guess at likely values of the random number seed. With a relatively small amount of guessing, the attacker can guess which random number seed you've used. From this, the attacker can generate the same supposedly random cryptographic key that you just generated. Now the attacker can impersonate you or read your secret messages.
A stronger PRNG, java.security.SecureRandom, was introduced in JDK 1.1. This class is based around a message digest. SecureRandom uses the SHA-1 (Secure Hash Algorithm) message digest algorithm, which produces a 20-byte digest. Here's how it works:
  • The SecureRandom is created using a seed. The seed value is digested, and the resulting value is stored as part of the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
SecureRandom
The JDK includes a class, java.util.Random, that implements a PRNG. Although it's fine for light-duty use, it has the following shortcomings:
  • It uses an algorithm that produces a predictable sequence of numbers.
  • If you don't give Random a seed value, it uses the value of the system clock. This is a predictable seed. Let's say that you create a random number in order to create a cryptographic key. If an attacker knows when you created the random number, even approximately, he or she can guess at likely values of the random number seed. With a relatively small amount of guessing, the attacker can guess which random number seed you've used. From this, the attacker can generate the same supposedly random cryptographic key that you just generated. Now the attacker can impersonate you or read your secret messages.
A stronger PRNG, java.security.SecureRandom, was introduced in JDK 1.1. This class is based around a message digest. SecureRandom uses the SHA-1 (Secure Hash Algorithm) message digest algorithm, which produces a 20-byte digest. Here's how it works:
  • The SecureRandom is created using a seed. The seed value is digested, and the resulting value is stored as part of the SecureRandom's internal state. An internal counter is initialized to zero.
  • Every time SecureRandom needs to create more pseudo-random numbers, the message digest is updated with the internal state and the counter, which is incremented. This data is digested and returned as the new pseudo-random data.
Because of the irreversible nature of the message digest, it's very hard to predict the past and future values of the PRNG even if you know its present output.
In practice, you don't have to worry about the details. Just create a SecureRandom instance and call its nextBytes() method to get pseudo-random data. In the example that follows, a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Self-Seeding
If you don't specify a seed value when you construct a SecureRandom, one will be generated for you. This is where it gets confusing. The SecureRandom class has a static member variable, also a SecureRandom, called the seed generator. It is used to generate seed values for new SecureRandom instances. Every time you create a SecureRandom using new SecureRandom(), the seed generator is used to seed your SecureRandom instance.
So how does the seed generator get seeded? SecureRandom uses an algorithm based on the timing of threads on the system to generate some supposedly random data. It uses this data to seed the seed generator itself.
Thus, real random seed generation occurs only once, the first time you construct a SecureRandom. It has two disadvantages:
  • It takes a few seconds (5-10 seconds on my Pentium 90).
  • The thread timing algorithm is not thoroughly tested. It may have weaknesses that cryptanalysts could exploit.
As Sun says in the SecureRandom documentation,
This empty constructor automatically seeds the generator. We attempt to provide sufficient seed bytes to completely randomize the internal state of the generator (20 bytes). Note, however, that our seed generation algorithm has not been thoroughly studied or widely deployed. It relies on counting the number of times that the calling thread can yield while waiting for another thread to sleep for a specified interval.
The first time this constructor is called in a given Virtual Machine, it may take several seconds of CPU time to seed the generator, depending on the underlying hardware. Successive calls run quickly because they rely on the same (internal) pseudo-random number generator for their seed bits.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Keyboard Timing
In this section, I'll develop an alternate method of seeding a SecureRandom. This method is based on measuring the timing of keyboard events, a method that has been used for years in PGP (Pretty Good Privacy, a popular cryptography application). The basic idea is to measure the time between successive keystrokes using a fast timer (a resolution of 1 millisecond or better is preferable). For each keystroke, one or two low-order bits of timing information will appear random. Take as many bits as you need to seed your PRNG. Even a very good, very consistent typist will probably not be able to type with millisecond precision, which means the seed bits are truly random.
This method does require that the user type data for a few seconds, which is not particularly user friendly. In contrast, the self-seeding algorithm in SecureRandom has no impact on your user interface, except that it will hang up your application for a few seconds the first time it is run. The method presented here, however, is under your control.
The Seeder class listens to KeyEvents and builds up a seed value of a certain length. When the seed is completed, Seeder will fire off an ActionEvent. Seeder doesn't care where the keyboard events come from; it just implements the KeyListener interface. We'll make Seeder part of the oreilly.jonathan.util package, so that we can easily use it later.
package oreilly.jonathan.util;

import java.awt.AWTEventMulticaster;
import java.awt.event.*;

public class Seeder
    implements KeyListener {
Internally, Seeder stores the seed value in a byte array, called mSeed. An integer, mBitIndex, serves as the current bit index. The mDone member variable indicates whether the Seeder is done gathering seed bits. Seeder also keeps track of the last key character it received. It rejects repeating keys because the timing of repeated keys may be predictable, and this would mess up our supposed random seed value. Seeder uses an ActionListener
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
SeederDialog
Content preview·Buy PDF of this chapter|