By Jonathan Knudsen
Price: $39.99 USD
£20.95 GBP
Cover | Table of Contents | Colophon
ClassLoader, and
SecurityManager work in tandem to safely execute
downloaded classes.http://java.sun.com/products/jdk/1.2/jce/.
Chapter 3, discusses these pieces of software and
how they fit together.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);
}
}
C:\ java Masher Masher.java
nfEOH/5M+yDLaxaJ+XpJ5Q==
|
Name
|
Type
|
Reference
|
|---|---|---|
|
MD5
|
Message digest
|
RFC 1321
ftp://ds.internic.net/rfc/rfc1321.txt
|
java.security
java.security.cert
java.security.interfaces
java.security.spec
javax.crypto
javax.crypto.interfaces
javax.crypto.spec
java.security
java.security.cert
java.security.interfaces
java.security.spec
javax.crypto
javax.crypto.interfaces
javax.crypto.spec
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.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.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.|
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
|
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.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.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.MessageDigest instance
that uses the MD5 algorithm:MessageDigest md5;
md5 = MessageDigest.getInstance("MD5");
NoSuchAlgorithmException if the requested
algorithm is not available.sun.security.provider.MD5, but you can do
everything you need to do by treating it as a
MessageDigest.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
|
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
| |
|
|
java.security.Provider object. This is confusing
terminology; provider (small p) refers to the
concept, while Provider refers to a specific
class.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.Identity and
KeyStore classes. For more information about this,
take a look at Chapter 5.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.java.security.SecureRandom. The rest of the
chapter discusses how to produce random seed data from keyboard
events.java.util.Random, that
implements a PRNG. Although it's fine for light-duty use, it
has the following shortcomings: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.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:SecureRandom
is created using a seed. The seed value
is digested, and the resulting value is stored as part of the
java.util.Random, that
implements a PRNG. Although it's fine for light-duty use, it
has the following shortcomings: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.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: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.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.SecureRandom instance and call its
nextBytes() method to get pseudo-random data. In
the example that follows, 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.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.SecureRandom. It has two
disadvantages: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.
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.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.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 {
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