
Professional Java.JDK.5.Edition (Wrox)
.pdf
Chapter 13
This class utilizes a specific random number generator, SHA1PRNG, from the SUN provider package. It is then seeded with the value specified in the call to generateKeyPair. If you take a look at the output, you will see a difference between the private and public key:
--Public Key ----
Algorithm=DSA
Encoded=[B@1a46e30
Format=X.509
--Private Key ----
Algorithm=DSA
Encoded=[B@3e25a5
Format=PKCS#8
The public key is encoded in the X.509 format, and the private key is encoded in the PKCS#8 format. PKCS stands for Public Key Cryptography Standards, and the eighth standard defines the format for private keys. The usage of X.509 for the public key means that a public key certificate was generated. A certificate allows the connecting of a trusted source with a public key, ensuring the public key is coming from the person that it claims it is.
Storing and Managing Keys
A keystore is a database of public keys, private keys, and certificates. By default, this database is stored in a file named keystore in the user’s home directory. The SUN provider package provides this behavior through a proprietary format named JKS. Each private key in this file is protected by a password, and the file itself is also protected by a password. The KeyStore engine class provides a robust interface for implementing a keystore provider. There are two types of entries that a KeyStore stores. The first, a key entry, contains sensitive key information such as private keys and the authenticating certificate chain, or a secret key. The second, a trusted certificate entry, contains a certificate authenticating the owner of a specific public key. The manner in which the keystore is persisted depends upon the implementation; thus, it is not specified by this engine class. The KeyStore engine class provides methods to load and save a keystore, access aliases of entries, determine entry types, manage the entries themselves, and retrieve information about the keystore. The standard getInstance methods are available to create a keystore:
final void load(InputStream stream, char[] password)
The load method loads a keystore from the specified input stream. The optional password is used as a way to verify the integrity of the keystore. If no password is specified, this integrity check is not performed. Pass in null in place of an input to create an empty keystore:
final void store(OutputStream stream, char[] password)
The store method saves the current keystore to the specified output stream. If a password is specified, it is used to calculate a checksum of the keystore data and is appended to the end of the output stream. This checksum is used by load to perform an integrity check:
final Enumeration aliases()
Each keystore entry has an associated alias that takes the form of a string. The aliases method returns an enumeration of the entry aliases in the keystore:
final boolean isKeyEntry(String alias)
final boolean isCertificateEntry(String alias)
596

Java Security
The isKeyEntry and isCertificateEntry methods provide a way to check the type of a keystore entry. The first, isKeyEntry, returns true if the entry specified by alias is a key entry, and returns false otherwise. The second, isCertificateEntry, returns true if the entry specified by alias is a certificate entry, and returns false otherwise:
final void setKeyEntry(String alias, Key key,
char[] password, Certificate[] chain)
final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
The setKeyEntry method adds a new key entry to the keystore (if alias does not correspond to an existing entry) or changes the key at the preexisting alias in the keystore. If the key is passed in as an array of bytes, the key should be in protected format, such as an EncryptedPrivateKeyInfo in the PKCS #8 standard. The alternate form of setKeyEntry uses a password to protect the key. The chain parameter is used to pass in a certificate chain as a trust source for the key:
final void setCertificateEntry(String alias, Certificate cert)
The setCertificateEntry method adds a new certificate entry to the keystore (if alias does not correspond to an existing entry) or changes the certificate at the entry named by alias (if a certificate entry already exists):
final void deleteEntry(String alias)
The deleteEntry method removes the entry associated with alias from the keystore:
final Key getKey(String alias, char[] password)
The getKey method returns the key entry from the keystore that is associated with alias. The password is used to retrieve the key:
final Certificate getCertificate(String alias)
final Certificate[] getCertificateChain(String alias)
The getCertificate and getCertificateChain methods return the certificate or certificate chain (array of Certificate) specified by alias in the keystore:
final String getCertificateAlias(Certificate cert)
The getCertificateAlias method returns the alias associated with a specified certificate from the keystore.
Algorithm Management
Algorithms have parameters associated with them, such as values of constants for the DSA algorithm. The actual values of these parameters are revealed in transparent representations through classes that implement the AlgorithmParameterSpec interface. This interface defines no methods, which thus makes it a tagging interface. Opaque representations of algorithm parameters are addressed by the AlgoithmParameters engine class. No direct access to the values of the algorithm parameters is available. The following methods, along with the expected getInstance methods, are defined in the AlgorithmParameters engine class. After object creation using getInstance, one of the init methods must be invoked to initialize the object:
597

Chapter 13
void init(AlgorithmParameterSpec paramSpec) void init(byte[] params)
void init(byte[] params, String format)
The byte array params contains the parameters in an encoded format. The form of init that only takes a byte array uses the default decoding format ASN.1 to decode the parameters. The last form of init accepts the byte array of parameters and format, the string representation of a decoding scheme. The first form accepts a reference to a transparent representation of the algorithm parameters. Note that initialization can only occur once. You cannot reuse an AlgorithmParameter object like you can a SecureSignature object:
byte[] getEncoded()
byte[] getEncoded(String format)
These methods return a byte array containing the encoded parameters. The default decoding used is ASN.1. You can specify a specific decoding format by passing its name in format. The default implementation of this engine class as provided in the SUN provider package disregards the format parameter:
AlgorithmParameterSpec getParameterSpec(Class paramSpec)
This returns a reference to a transparent representation of the encoded parameters. The paramSpec parameter is used to specify a particular AlgorithmParameterSpec class, such as passing in DSAParameterSpec.class to get a DSAParameterSpec object returned.
The AlgorithmParameterGenerator is an engine class to generate parameters for a particular algorithm. Creating an object of this class is the same as any other engine class. A particular algorithm and possibly a provider are passed to a getInstance method. After object creation, the object must be initialized using one of the init methods. After initialization, you can invoke generateParameters to actually generate the parameters for the specified algorithm:
void init(int size, SecureRandom random) void init(int size)
void init(AlgorithmParameterSpec genParamSpec, SecureRandom random) void init(AlgorithmParameterSpec genParamSpec)
Each algorithm uses two core pieces of information to generate parameters: a size and a way to create random numbers. This size could be a number of bits or a number of bytes, all depending on the specific algorithm. The use of SecureRandom shows the interoperability of the engine classes. Any provider’s random number generator can be used with any other provider’s AlgorithmParameterGenerator to generate parameters. If no random number generator is specified, a system-provided source of random numbers is used. The first two forms only allow the specification of a single size, so default values are used for other algorithm parameters. The last two forms provide for the specification of each algorithm’s parameter. Because there are no requirements made based on the AlgorithmParameterSpec, each algorithm has its own AlgorithmParameterGenerator that works with the algorithm’s AlgorithmParameterSpec to generate the parameters:
AlgorithmParameters generateParameters()
This generates and returns a set of algorithm parameters encoded in an AlgorithmParameters object.
598

Java Security
Random Number Generation
A random number generator (RNG) is a vital part of encryption algorithms. Because most random number generators start with a seed value, a value that causes a predictable string of numbers to get generated, random number generators are often termed pseudo-random because they are not truly random. The engine class for random number generators is SecureRandom and, as expected, has the standard set of getInstance methods.
The operations available on the random number generator are seeding the generator, obtaining a random number (or sequence of random numbers), and obtaining a random seed that can be used to seed a random number generator. These operations are accomplished via the following methods:
synchronized public void setSeed(byte[] seed)
public void setSeed(long seed)
Invoking a setSeed method isn’t strictly necessary. When the getInstance method is invoked, the random number generator should set itself to a random state. However, it is possible to increase the randomness by which the generator works by passing in a long value or a sequence of bytes as a seed. Each subsequent call to setSeed increases the randomness. A seed passed in later does not replace an earlier seed; it extends it into a more random organization:
synchronized public void nextBytes(byte[] bytes)
The byte array bytes is filled with a sequence of randomly generated bytes up to the array’s allocated length:
byte[] generateSeed(int numBytes)
This method returns a byte array of size numBytes. This byte array can then be used as a seed to the random number generator.
Here’s a brief example using the SecureRandom class to generate random numbers:
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
public class SecureRandomExample {
public static void main(String args[])
{
try {
SecureRandom rng = SecureRandom.getInstance(“SHA1PRNG”); rng.setSeed(711);
int numberToGenerate = new Integer(args[0]).intValue(); byte randNumbers[] = new byte[numberToGenerate];
rng.nextBytes(randNumbers);
for(int j=0; j<numberToGenerate; j++) { System.out.print(randNumbers[j] + “ “);
}
System.out.println(“”);
599

Chapter 13
} catch(NoSuchAlgorithmException nsae) { System.out.println(“Exception: “ + nsae); nsae.printStackTrace();
}
}
}
In this example, the user passes in how many numbers to generate on the command line as the first (and only) parameter. The same seed is used every time this program is executed, so the same sequence of numbers will always get generated. If you execute this program and ask for five numbers, you will get the same output as listed in the following example:
111 100 -92 -59 -49
Certificate Management
Certificates are a vital part of the security picture. Because public keys are, by definition, public, how can you verify that the public key truly belongs to the person that claims to own it? This is accomplished using a certificate. A trusted third party, such as Verisign or Entrust, issues a certificate to an entity (a person, an organization, and so forth) verifying that this entity is trusted. A public key associated with a certificate is then trusted to come from the owner of the associated certificate. A certification path is a sequence of trust from one authority to another. For example, one certificate authority (CA) can issue a certificate for one public key, and the subject of this certificate is then used as a CA for another public key. This establishes a path of trust, and each step must be validated for the entire trust relationship to stand up.
The Java Security Architecture provides classes in the java.secuity.cert package to manage and utilize certificates. The CertificateFactory creates certificates, certification paths, and certification revocation lists (CRLs) from their corresponding encodings. The CertPathBuilder builds certification paths (or chains). The CertPathValidator provides the functionality to validate the certification path stored in a CertPath object. The CertStore class provides a repository for storing both trusted and untrusted certifications and CRLs. All of these classes are engine classes and thus have the standard getInstance methods for creating an instance of one of these classes.
CertificateFactory
The CertificateFactory engine class is a factory class that can generate certificates, certificate paths, and CRLs. The standard getInstance methods are available for object creation.
To generate a certificate, one of the following methods is used:
final Certificate generateCertificate(InputStream inStream)
final Collection generateCertificates(InputStream inStream)
The first form creates a single certificate from a provided input stream, and the second creates a collection of zero or more certificates from a provided input stream.
Creating a CRL is similar to creating certificates:
final CRL generateCRL(InputStream inStream)
final Collection generateCRLs(InputStream inStream)
600

Java Security
The first form creates a single CRL from a provided input stream, and the second creates a collection of zero or more CRLs from a provided input stream. The CertificateFactory can also create a certification path from a provided input stream:
final CertPath generateCertPath(InputStream inStream)
final CertPath generateCertPath(InputStream inStream, String encoding)
These methods provide a way to create a certification path from the input stream. The second form allows you to specify the encoding used for the certification path:
final CertPath generateCertPath(List certificates)
This method creates a CertPath object and initializes it with the list of certificates passed in:
final Iterator getCertPathEncodings()
A list of certificate encodings supported by this factory is returned. The default encoding is listed first.
CertPathBuilder
The CertPathBuilder engine class is used to create a CertPath from a set of CertPathParameters. The nature of these parameters is algorithm-specific. The standard getInstance methods are provided for object creation. A single method is provided to build the CertPath:
public final CertPathBuilderResult build(CertPathParameters params)
throws CertPathBuilderException, InvalidAlgorithmParameterException
The CertPathBuilderResult contains a getCertPath method that returns the CertPath that is built using this method. Using this interface allows for ease of grouping and copying (via clone) of the path that is built.
CertPathValidator
The CertPathValidator is an engine class that validates a certiticate path. The standard getInstance methods are provided. A single method is provided to validate the certificate path:
public final CertPathValidatorResult validate(CertPath certPath, CertPathParameters params)
throws CertPathValidatorException, InvalidAlgorithmParameterException
If the validation succeeds, an instance of a class implementing the CertPathValidatorResult interface is returned. Otherwise, a CertPathValidatorException is thrown, signaling an invalid certificate path. The CertPath and CertPathParameters that are passed in must be compatible with the algorithm, or an InvalidAlgorithmParameterException is thrown.
CertStore
The CertStore is an engine class designed to store certificates and CRLs. The getInstance methods are augmented with a CertStoreParameters parameter. The revised getInstance methods are listed next:
601

Chapter 13
public static CertStore getInstance(String type, CertStoreParameters params)
public static CertStore getInstance(String type, CertStoreParameters params,
String provider) public static CertStore getInstance(String type,
CertStoreParameters params, Provider provider)
The type parameter represents the name of a repository type, such as LDAP or Collection for Java collections. The specific CertStoreParameters are specific to each repository type.
The parameters used to initialize the CertStore can be retrieved using the following method:
public final CertStoreParameters getCertStoreParameters()
To retrieve certificates and CRLs from a CertStore, the concept of a selector is introduced. This selector defines the criteria used to select a set of certificates or CRLs to return. The following methods are provided to select and return a set of certificates or CRLs:
public final Collection getCertificates(CertSelector selector) throws CertStoreException
public final Collection getCRLs(CRLSelector selector) throws CertStoreException
Each method returns a collection of their corresponding objects. The selector interfaces both define a single method named match that accepts a certificate or a CRL and returns true if the specified object matches some criteria, or false otherwise. There are concrete implementations of these interfaces that are available as part of the security library, such as X509CertSelector and X509CRLSelector, which verify whether a certificate or CRL matches the format of X509 certificates/CRLs.
Java Cryptography Extension
The Java Cryptography Extension (JCE) specifies other cryptographic services that are important for a more complete security package. The JCE is based on the same architecture as the JCA and is thus provider-based. The default provider package that comes with J2SDK 1.5 is named SunJCE. The services provided by the JCE are as follows:
Encryption/Decryption: Converts a nonencrypted plaintext (or cleartext) message into an encrypted form using a key or performing the opposite operation.
Password-Based Encryption (PBE): Derives an encryption key from a given password, sometimes based on a salt (a random number) to extend the time needed for a brute force attack, which thus makes a brute force attack more infeasible.
Cipher: An object that carries out the encryption and decryption of information based on a particular algorithm.
Key Agreement: A protocol that enables two or more parties to establish the same cryptographic keys without needing to share secret information.
Message Authentication Code (MAC): A short code that is used to verify the integrity/origination of information, similar to using a digital signature to verify data integrity/origination.
602

Java Security
The engine classes provided by the JCE are Cipher, KeyGenerator, KeyAgreement, and Mac. These engine classes and classes related to each are discussed in detail in this section.
The Cipher Engine Class
The Cipher engine class is the largest engine class in the JCE. It provides both encryption and decryption support. The JCE also introduces CipherInputStream and CipherOutputStream, which provide secure input and output streams when combined with a Cipher object. The getInstance methods available on the Cipher object differ from the getInstance methods of engine classes from the JCA:
public static Cipher getInstance(String transformation); public static Cipher getInstance(String transformation,
String provider);
The parameter transformation is used to specify a particular transforming and takes the form of algorithm/mode/padding or just algorithm. Specifying DES or DES/ECB/PKCS5Padding (the default algorithm/mode/padding provided by the SunJCE) are both valid. The provider parameter lets you specify which provider should be used. If no provider is specified, a provider is located that provides the requested transformation.
After object creation, the Cipher object must be initialized with an operating mode and other information. There are eight forms of the init method:
public void init(int opmode, Key key)
public void init(int opmode, Certificate certificate) public void init(int opmode, Key key, SecureRandom random) public void init(int opmode, Certificate certificate,
SecureRandom random) public void init(int opmode, Key key,
AlgorithmParameterSpec params) public void init(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random) public void init(int opmode, Key key,
AlgorithmParameters params) public void init(int opmode, Key key,
AlgorithmParameters params, SecureRandom random)
The opmode parameter can take one of four integer values that are defined as final integers in the Cipher class. These operating modes are listed in the following table.
Operating Mode Constant’s Name |
Description |
|
|
ENCRYPT_MODE |
Configures Cipher to encrypt data |
DECRYPT_MODE |
Configures Cipher to decrypt data |
WRAP_MODE |
Configures Cipher in key wrapping mode to con- |
|
vert a key to bytes that can be securely transported |
UNWRAP_MODE |
Configures Cipher to unwrap a previously |
|
wrapped key |
|
|
603

Chapter 13
You can pass in a key through the key or certificate parameters (for a certificate that contains a key). The params parameter contains parameters for the particular algorithm requested, and random is used to utilize a different random number generator than the system source of randomness.
If the mode is DECRYPT_MODE, the Cipher requires a key and appropriate parameters. If these are not specified, an InvalidKeyException or InvalidAlgorithmParameterException is thrown. If the Cipher is configured for ENCRYPT_MODE, these parameters are configured with already defined values unless explicitly passed in to the init method.
Encrypting/Decrypting Data
Data can be passed to a Cipher object in parts or all at once. The update method is used to pass in a chunk of data at a time, and the doFinal method is used to either pass in all of the data at a single time or signal the end of a sequence of data that was passed in through the update method:
public byte[] update(byte[] input)
public byte[] update(byte[] input, int inputOffset, int inputLen)
public int update(byte[] input, int inputOffset, int inputLen, byte[] output)
public int update(byte[] input, int inputOffset,
int inputLen, byte[] output, int outputOffset)
These methods allow you to pass a piece of data to the Cipher. Using these methods lets you process more data than you have at a single time. The last two forms store the encrypted/decrypted data in a buffer passed in, as opposed to returning the data in the first two forms:
public byte[] doFinal(byte[] input)
public byte[] doFinal(byte[] input, int inputOffset, int inputLen)
public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)
public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
public byte[] doFinal();
public int doFinal(byte[] output, int outputOffset)
These methods are used to either process all the input at once or signal the end of input after repeated calls to update. The first four forms let you combine the operation of passing in the rest of the data and retrieving the result. The last two forms signal the end and then obtain the result. The last form returns the length of the output.
Wrapping and Unwrapping Keys
public final byte[] wrap(Key key)
This method is used to take a key and convert it to a sequence of bytes that can be safely and easily transported. The key is encrypted using the Cipher so that secure transmission is possible. In order for the recipient to unwrap the key, you need to also transmit the name of the key algorithm and the type of the key (either SECRET_KEY, PRIVATE_KEY, or PUBLIC_KEY):
604

Java Security
public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
int wrappedKeyType)
This method takes a wrapped key and unwraps it using the specified algorithm and key type. The wrappedKeyType is either SECRET_KEY, PRIVATE_KEY, or PUBLIC_KEY:
public int getOutputSize(int inputLen)
This method is useful to determine the size of the output in order for the client code to allocate enough space in its buffer for the encrypted/decrypted data.
Two classes are provided for chaining a cipher in file input/output operations. The CipherInputStream inherits from the FilterInputStream class. The CipherOutputStream inherits from FilterOutputStream. Data passing through the each of these is encrypted or decrypted using an associated Cipher object. Usage of CipherInputStream and CipherOutputStream are straightforward. Take a look at the example to see them in action.
Here is a class that provides an interface to using the Cipher class by itself and also utilizing the CipherInputStream and CipherOutputStream classes. This example could be modified rather easily to work as a utility class using the Cipher engine class:
import java.security.*; import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; import java.io.*;
public class CipherExample { private Cipher m_encrypter; private Cipher m_decrypter;
public void init(SecretKey key)
{
// for CBC; must be 8 bytes
byte[] initVector = new byte[]{0x10, 0x10, 0x01, 0x04, 0x01, 0x01, 0x01, 0x02};
AlgorithmParameterSpec algParamSpec =
new IvParameterSpec(initVector);
try {
m_encrypter = Cipher.getInstance(“DES/CBC/PKCS5Padding”); m_decrypter = Cipher.getInstance(“DES/CBC/PKCS5Padding”);
m_encrypter.init(Cipher.ENCRYPT_MODE, key, algParamSpec); m_decrypter.init(Cipher.DECRYPT_MODE, key, algParamSpec);
}catch (InvalidAlgorithmParameterException e) { System.out.println(“Exception: “ + e);
}catch (NoSuchPaddingException e) { System.out.println(“Exception: “ + e);
}catch (NoSuchAlgorithmException e) { System.out.println(“Exception: “ + e);
}catch (InvalidKeyException e) {
605