In the JCE, there are new ways to generate keys. Since the existing key engines only operate on public and private keys, the JCE introduces two new engines that can operate on secret keys. Note also in Table 13-1 that the SunJCE security provider implements a new algorithm to generate key pairs for Diffie-Hellman key agreement; that algorithm uses the standard KeyPairGenerator class we explored in Chapter 10, "Keys and Certificates".
The first engine we'll look at is the KeyGenerator class (javax.crypto.Key-Generator); this class is used to generate secret keys. This class is very similar to the KeyPairGenerator class except that it generates instances of secret keys instead of pairs of public and private keys:
Generate instances of secret keys for use by a symmetric encryption algorithm.
The KeyGenerator class is an engine within the JCE. As such, it has all the hallmarks of a cryptographic engine. It has a complementary SPI and a set of public methods that are used to operate upon it, and its implementation must be registered with the security provider.
Like other engine classes, the KeyGenerator class does not have any public constructors. An instance of a KeyGenerator is obtained by calling one of these methods:
Return an object capable of generating secret keys that correspond to the given algorithm. These methods use the standard rules of searching the list of security providers in order to find an object that implements the desired algorithm. If the generator for the appropriate algorithm cannot be found, a NoSuchAlgorithmException is thrown; if the named provider cannot be found, a NoSuchProviderException is thrown.
Once an object has been obtained with these methods, the generator must be initialized by calling one of these methods:
Initialize the key generator. Like a key pair generator, the key generator needs a source of random numbers to generate its keys (in the second method, a default instance of the SecureRandom class will be used). In addition, some key generators can accept an algorithm parameter specification to initialize their keys (just as the key pair generator); however, for the DES-style keys generated by the SunJCE security provider, no algorithm parameter specification may be used.
A key generator does not have to be initialized explicitly, in which case it is initialized internally with a default instance of the SecureRandom class. However, it is up to the implementor of the engine class to make sure that this happens correctly; it is better to be sure your code will work by always initializing your key generator.
A secret key can be generated by calling this method:
Generate a secret key. A generator can produce multiple keys by repeatedly calling this method.
There are two additional methods in this class, both of which are informational:
Return the string representing the name of the algorithm this generator supports.
Return the provider that was used to obtain this key generator.
In the next section, we'll show the very simple code needed to use this class to generate a secret key.
Implementing a key generator requires implementing its corresponding SPI. Like all engines that are not available in Java 1.1, the SPI for the KeyGenerator class is unrelated in the class hierarchy to the KeyGenerator class itself, and the class that we register with the security provider must extend the KeyGeneratorSpi class (javax.crypto.KeyGeneratorSpi):
This class forms the service provider interface class for the KeyGenerator class.
There are three protected methods of this class that we must implement if we want to provide an SPI for a key generator:
Generate the secret key. This method should use the installed random number generator and (if applicable) the installed algorithm parameter specification to generate the secret key. If the engine has not been initialized, it is expected that this method will initialize the engine with a default instance of the SecureRandom class.
Initialize the key generation engine with the given random number generator and, if applicable, algorithm parameter specification. If the class does not support initialization via an algorithm parameter specification, or if the specification is invalid, an InvalidAlgorithmParameterException should be thrown.
Hence, a complete implementation might look like this:
public class XORKeyGenerator extends KeyGeneratorSpi { SecureRandom sr; public void engineInit(SecureRandom sr) { this.sr = sr; } public void engineInit(AlgorithmParameterSpec ap, SecureRandom sr) throws InvalidAlgorithmParameterException { throw new InvalidAlgorithmParameterException( "No parameters supported in this class"); } public SecretKey engineGenerateKey() { if (sr == null) sr = new SecureRandom(); byte b[] = new byte[1]; sr.nextBytes(b); return new XORKey(b[0]); } }
Keys, of course, are usually longer than a single byte. However, unlike a public key/private key pair, there is not necessarily a mathematical requirement for generating a symmetric key. Such a requirement depends on the encryption algorithm the key will be used for, and some symmetric encryption algorithms require a key that is just an arbitrary sequence of bytes.
The second engine that we'll look at is the SecretKeyFactory class (javax.crypto.SecretKeyFactory). Like the KeyFactory class, this class can convert from algorithmic or encoded key specifications to actual key objects and can translate key objects from one implementation to another. Unlike the KeyFactory class, which can only operate on public and private keys, the SecretKeyFactory class can operate only on secret keys:
Provide an engine that can translate between secret key specifications and secret key objects (and vice versa). This allows for secret keys to be imported and exported in a neutral format.
The interface to the SecretKeyFactory class is exactly the same at a conceptual level as the interface to the KeyFactory. At a programming level, this means that while most of the methods between the two classes have the same name and perform the same operation, they may require slightly different parameters: a secret key, rather than a public or private key. In addition, instead of methods to generate public or private keys, the SecretKeyFactory class contains this method:
Generate the secret key according to the given specification. If the specification is invalid, an InvalidKeySpecException is thrown.
Because of its similarity to the KeyFactory class, we won't show an example of how to use it; you may use examples from Chapter 10, "Keys and Certificates" and simply substitute this new method.
The specifications used to import and export secret keys depend on the underlying algorithm that generated the secret key. As a result, the JCE provides twelve new key specifications that deal with the new keys the JCE provides:
This class provides the encoded and algorithmic parameter specifications for DES keys.
This class provides the encoded specification for DESede keys.
These classes implement algorithm specifications forDiffie-Hellman keys.
These classes implement the encoded key specifications for Diffie-Hellman keys.
These classes implement the encoded and algorithm key specifications for the password-based cipher algorithm (the PKCS#5 standard).
This class implements an initialization vector. Initialization vectors are used in many algorithms; notably in DES.
These classes implement the algorithm parameter specifications for RC2 and RC5 encryption.
This class implements a key specification for the new class of secret keys.
We typically treat the values contained in these specifications as opaque values. Table 13-2 lists the methods for each class needed to import and export each of these key specifications. As usual for key specifications, exporting a specification involves transmitting the individual data elements of the class, while importing a specification involves constructing the specification with the correct values.
Key Specifications |
Methods to Export Data |
Methods to Import Data |
---|---|---|
Class DefinitionDESKeySpec |
Class Definitionbyte[] getKey() |
Class DefinitionDESKeySpec(byte[] buf) DESKeySpec( byte[] buf, int offset) |
Class DefinitionIvParameterSpec |
Class Definitionbyte[] getIV() |
Class DefinitionIvParameterSpec( byte[] buf) IvParameterSpec( byte[] buf, int offset) |
Class DefinitionDESedeKeySpec |
Class Definitionbyte[] getKey() |
Class DefinitionDESedeKeySpec(byte[] buf) DESedeKeySpec( byte[] buf, int offset) |
Class DefinitionDHGenParameterSpec |
Class Definitionint getPrimeSize() int getExponentSize() |
Class DefinitionDHGenParameterSpec( int primeSize, int exponentSize) |
Class DefinitionDHParameterSpec |
Class DefinitionBigInteger getP() BigInteger getG() int getL() |
Class DefinitionDHParameterSpec( BigInteger g) DHParameterKeySpec( BigInteger g, int l) |
Class DefinitionDHPrivateKeySpec |
Class DefinitionBigInteger getX() BigInteger getP() BigInteger getG() int getL() |
Class DefinitionDHPrivateKeySpec( BigInteger p, BigInteger g) DHPrivateKeySpec( BigInteger p, BigInteger g, int l) |
Class DefinitionDHPublicKeySpec |
Class DefinitionBigInteger getY() BigInteger getP() BigInteger getG() int getL() |
Class DefinitionDHPublicKeySpec( BigInteger p, BigInteger g) DHPublicKeySpec( BigInteger p, BigInteger g, int l) |
Class DefinitionPBEKeySpec |
Class DefinitionString getPassword() |
Class DefinitionPBEKeySpec(String pw) |
Class DefinitionPBEParameterSpec |
Class Definitionint getIterationCount() byte[] getSalt() |
Class DefinitionPBEParameterSpec( byte[] salt, int count) |
Class DefinitionRC2ParameterSpec |
Class Definitionbyte[] getIV() int getEffectiveKeyBits() |
Class DefinitionRC2ParameterSpec(int effective) RC2ParameterSpec(int effective, byte[] iv) RC2ParameterSpec(int effective, byte[] iv, int offset) |
Class DefinitionRC5ParameterSpec |
Class Definitionbyte[] getIV() int getRounds() int getVersion() int getWordSize() |
Class DefinitionRC5ParameterSpec(int version, int rounds, int wordSize) RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv) RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv, int offset) |
Class DefinitionSecretKeySpec |
Class Definitionbyte[] getEncoded() |
Class DefinitionSecretKeySpec(byte[] key, String Algorithm) SecretKeySpec(byte[] key, int offset, String Algorithm) |
Like all engines, the secret key engine is implemented via an SPI; if you want to implement your own secret key factory you must extend the SecretKeyFactorySpi class (javax.crypto.SecretKeyFactorySpi):
This class is the SPI for the SecretKeyFactory class. As this class is only available as an extension to 1.2, the SPI is unrelated to the engine class; providers must extend this class directly to provide a secret key factory.
Implementation of this class follows the implementation of a key factory SPI, except that the methods of this class must operate upon secret keys rather than public or private keys. If you want to implement a secret key factory SPI, you can use the sample key factory SPI as a model.
Copyright © 2001 O'Reilly & Associates. All rights reserved.