How to Implement a Provider for the JavaTM Cryptography Extension 1.2


Last Modified: 21 July 1998


Introduction
Who Should Read This Document
Related Documentation

Engine Classes and Corresponding SPI Classes

Steps to Implement and Integrate a Provider

Further Implementation Details and Requirements
Algorithm Aliases
Service Interdependencies
Default Initializations
Diffie-Hellman Interfaces and their Required Implementations
Algorithm Parameter Specification Classes
Key Specification Classes Required by Key Factories
Secret-Key Generation

Appendix A: The "SunJCE" Provider's Master Class

Appendix B: The java.security Master Properties File

Introduction

The JavaTM Cryptography Extension (JCE) 1.2 is a standard extension to the JDKTM platform. JCE 1.2 supplements the cryptographic services defined in the Java Development Kit 1.2 (JDKTM) by adding support for ciphers, key agreement, and message authentication codes.

JCE 1.2 is based on the same design principles as JDK 1.2, which uses the notion of a Cryptography Package Provider, or "provider" for short. This term refers to a package (or a set of packages) that supply a concrete implementation of a subset of the cryptography aspects of the Java Security API in JDK 1.2.

JCE 1.2 extends the list of cryptographic services of which a provider can supply implementations. A provider could, for example, contain an implementation of one or more digital signature algorithms and one or more cipher algorithms.

A program wishing to use cryptography functionality may simply request a particular type of object (such as a Cipher object) implementing a particular algorithm (such as DES) and get an implementation from one of the installed providers. If an implementation from a particular provider is desired, the program can request that provider by name, along with the algorithm desired.

Each JDK installation has one or more provider packages installed. Each provider package supplies implementations of cryptographic services defined in JDK 1.2 and/or JCE 1.2. Only when JCE 1.2 is installed can the JCE-specific implementations supplied by provider packages be accessed.

Clients may configure their runtimes with different providers, and specify a preference order for each of them. The preference order is the order in which providers are searched for requested algorithms when no particular provider is requested.

JCE 1.2 comes with a built-in provider named "SunJCE", which supplies the following services:

New providers may be added statically or dynamically. Clients may also query which providers are currently installed.

The different implementations may have different characteristics. Some may be software-based, while others may be hardware-based. Some may be platform-independent, while others may be platform-specific. Some provider source code may be available for review and evaluation, while some may not.

Who Should Read This Document

This document is intended for experienced programmers wishing to create their own provider packages supplying cryptographic service implementations. It documents what you need to do in order to integrate your provider into Java Security so that your algorithms and other services can be found when Java Security API clients request them. Programmers that only need to use the Java Security API to access existing cryptography algorithms and other services do not need to read this document.

Related Documentation

This document assumes you have already read the following documents:

It also discusses various classes and interfaces in the Java Security API. The complete reference documentation for the relevant Security API packages can be found in:

Engine Classes and Corresponding Service Provider Interface Classes

An "engine class" defines a cryptographic service in an abstract fashion (without a concrete implementation).

A cryptographic service is always associated with a particular algorithm, and it either provides cryptographic operations (like those for ciphers or key agreement protocols), or generates or supplies the cryptographic material (keys or parameters) required for cryptographic operations. For example, two of the engine classes are the Cipher and KeyAgreement classes. The Cipher class provides access to the functionality of an encryption algorithm (such as DES), and the KeyAgreement class provides access to the functionality of a key agreement protocol (such as Diffie-Hellman).

The Java Cryptography Architecture encompasses the classes of the JDK 1.2 Java Security package related to cryptography, including the engine classes. Users of the API request and utilize instances of the engine classes to carry out corresponding operations.

JCE 1.2 is provided as a standard extension to JDK 1.2, and supplements the cryptographic services defined in JDK 1.2 by adding the following engine classes:

An engine class provides the interface to the functionality of a specific type of cryptographic service (independent of a particular cryptographic algorithm). It defines "Application Programming Interface" (API) methods that allow applications to access the specific type of cryptographic service it provides. The actual implementations (from one or more providers) are those for specific algorithms. The Cipher engine class, for example, provides access to the functionality of a cipher algorithm. The actual implementation supplied in a CipherSpi subclass (see next paragraph) would be that for a specific kind of encryption algorithm, such as DES or Triple DES.

The application interfaces supplied by an engine class are implemented in terms of a "Service Provider Interface" (SPI). That is, for each engine class, there is a corresponding abstract SPI class, which defines the Service Provider Interface methods that cryptographic service providers must implement.

An instance of an engine class, the "API object", encapsulates (as a private field) an instance of the corresponding SPI class, the "SPI object". All API methods of an API object are declared "final", and their implementations invoke the corresponding SPI methods of the encapsulated SPI object. An instance of an engine class (and of its corresponding SPI class) is created by a call to the getInstance factory method of the engine class.

The name of each SPI class is the same as that of the corresponding engine class, followed by "Spi". For example, the SPI class corresponding to the Cipher engine class is the CipherSpi class.

Each SPI class is abstract. To supply the implementation of a particular type of service, for a specific algorithm, a provider must subclass the corresponding SPI class and provide implementations for all the abstract methods.

Another example of an engine class is the KeyAgreement class, which provides access to a key agreement (key exchange) algorithm. Its implementations, in KeyAgreementSpi subclasses, may be those of various key agreement algorithms such as Diffie-Hellman.

As a final example, the SecretKeyFactory engine class supports the conversion from opaque secret keys to transparent key specifications, and vice versa. (See Key Specification Interfaces and Classes Required by Key Factories.) The actual implementation supplied in a SecretKeyFactorySpi subclass would be that for a specific type of secret keys, e.g., DES keys.

Steps to Implement and Integrate a Provider

The steps required in order to implement a provider and integrate it into Java Security are the same as described in the How to Implement a Provider for the Java Cryptography Architecture guide.

Step 1: Write your Service Implementation Code

The first thing you need to do is write the code supplying algorithm-specific implementations of the cryptographic services you want to support.

Note that your provider may supply implementations of cryptographic services defined in JCE 1.2 in addition to implementations of cryptographic services defined in JDK 1.2.

In JCE 1.2, you can supply cipher, key agreement and MAC algorithms, as well as secret-key factories and secret-key generation services.

In JDK 1.2, you can supply signature, message digest, key pair generation, and (pseudo-)random number generation algorithms, as well as key and certificate factories and keystore creation and management, algorithm parameter management, and algorithm parameter generation services.

For each cryptographic service in JCE 1.2 or JDK 1.2, you need to create a subclass of the appropriate SPI class. JCE 1.2 defines the following engine classes, in addition to the engine classes defined in JDK 1.2: CipherSpi, KeyAgreementSpi, KeyGeneratorSpi, MacSpi, and SecretKeyFactorySpi. (See "JCE 1.2 Engine Classes and Corresponding SPI Classes" and "JDK 1.2 Engine Classes and Corresponding SPI Classes".)

In your subclass, you need to

  1. supply implementations for the abstract methods, whose names usually begin with "engine". See Further Implementation Details and Requirements for additional information.

  2. ensure there is a public constructor without any arguments. Here's why: When one of your services is requested, Java Security looks up the subclass implementing that service, as specified by a property in your "master class" (see Step 3). Java Security then creates the Class object associated with your subclass, and creates an instance of your subclass by calling the newInstance method on that Class object. newInstance requires your subclass to have a public constructor without any parameters.

    A default constructor without arguments will automatically be generated if your subclass doesn't have any constructors. But if your subclass defines any constructors, you must explicitly define a public constructor without arguments.

Step 2: Give your Provider a Name

Decide on a name for your provider. This is the name to be used by client applications to refer to your provider.

Step 3: Write your "Master Class", a subclass of Provider

The third step is to create a subclass of the java.security.Provider class.

Your subclass should be a final class, and its constructor should

For further master class property setting examples, see Appendix A to view the current JCE 1.2 SunJCE.java source file. This shows how the SunJCE class constructor sets all the properties for the "SunJCE" provider.

Note: The Provider subclass can get its information from wherever it wants. Thus, the information can be hard-wired in, or retrieved at runtime, e.g., from a file.

As mentioned above, in the case of a Cipher property, algName may actually represent a transformation. A transformation is a string that describes the operation (or set of operations) to be performed by a Cipher object on some given input. A transformation always includes the name of a cryptographic algorithm (e.g., DES), and may be followed by a feedback mode and padding scheme.

A transformation is of the form:

(in the latter case, provider-specific default values for the mode and padding scheme are used). For example, the following is a valid transformation:

    Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

When requesting a block cipher in stream cipher mode (e.g., DES in CFB or OFB mode), a client may optionally specify the number of bits to be processed at a time, by appending this number to the mode name as shown in the following sample transformations:

    Cipher c1 = Cipher.getInstance("DES/CFB8/NoPadding");
    Cipher c2 = Cipher.getInstance("DES/OFB32/PKCS5Padding");

If a feedback mode is not followed by a number, a provider-specific default is used. (For example, the "SunJCE" provider uses a default of 64 bits.)

A provider may supply a separate class for each combination of algorithm/mode/padding, or may decide to provide more generic classes representing sub-transformations corresponding to algorithm or algorithm/mode or algorithm//padding (note the double slashes), in which case the requested mode and/or padding are set automatically by the getInstance methods of Cipher, which invoke the engineSetMode and engineSetPadding methods of the provider's subclass of CipherSpi.

A Cipher property in a provider master class may have one of the following formats:

(See Appendix A of the Java Cryptography Extension 1.2 API Specification & Reference for the standard algorithm names, modes, and padding schemes that should be used.)

For example, a provider may supply a subclass of CipherSpi that implements DES/ECB/PKCS5Padding, one that implements DES/CBC/PKCS5Padding, one that implements DES/CFB/PKCS5Padding, and yet another one that implements DES/OFB/PKCS5Padding. That provider would have the following Cipher properties in its master class:

Another provider may implement a class for each of the above modes (i.e., one class for ECB, one for CBC, one for CFB, and one for OFB), one class for PKCS5Padding, and a generic DES class that subclasses from CipherSpi. That provider would have the following Cipher properties in its master class:

The getInstance factory method of the Cipher engine class follows these rules in order to instantiate a provider's implementation of CipherSpi for a transformation of the form "algorithm":

  1. Check if the provider has registered a subclass of CipherSpi for the specified "algorithm".

    If the answer is YES, instantiate this class, for whose mode and padding scheme default values (as supplied by the provider) are used.

    If the answer is NO, throw a NoSuchAlgorithmException exception.

The getInstance factory method of the Cipher engine class follows these rules in order to instantiate a provider's implementation of CipherSpi for a transformation of the form "algorithm/mode/padding":

  1. Check if the provider has registered a subclass of CipherSpi for the specified "algorithm/mode/padding" transformation.

    If the answer is YES, instantiate it.

    If the answer is NO, go to the next step.

  2. Check if the provider has registered a subclass of CipherSpi for the sub-transformation "algorithm/mode".

    If the answer is YES, instantiate it, and call engineSetPadding(padding) on the new instance.

    If the answer is NO, go to the next step.

  3. Check if the provider has registered a subclass of CipherSpi for the sub-transformation "algorithm//padding" (note the double slashes).

    If the answer is YES, instantiate it, and call engineSetMode(mode) on the new instance.

    If the answer is NO, go to the next step.

  4. Check if the provider has registered a subclass of CipherSpi for the sub-transformation "algorithm".

    If the answer is YES, instantiate it, and call engineSetMode(mode) and engineSetPadding(padding) on the new instance.

    If the answer is NO, throw a NoSuchAlgorithmException exception.

Step 4: Compile your Code

After you have created your implementation code (Step 1), given your provider a name (Step 2), and created the master class (Step 3), use the Java compiler to compile your files.

Step 5: Prepare for Testing: Install the Provider

In order to prepare for testing your provider, you must install it in the same manner as will be done by clients wishing to use it. The installation enables Java Security to find your algorithm implementations when clients request them.

There are two parts to installing a provider: installing the provider package classes, and configuring the provider.

Installing the Provider Classes

The first thing you must do is make your classes available so that they can be found when requested. You ship your provider classes as a JAR (Java ARchive) or ZIP file.

Note that in order for your provider to work, you must also have JCE 1.2 (more specifically: the jce12-beta-dom.jar extension) installed.

There are a couple possible ways of installing your provider classes:

For more information on how to deploy an extension, see How is an extension deployed?.

For more information on "installed" extensions, see Installation: Where is an extension installed?.

For more information on "bundled" extensions, see Dependencies: How does an application specify the other extensions it needs?.

Configuring the Provider

The next step is to add the provider to your list of approved providers. This is done statically by editing the java.security file in the lib/security (lib\security on Windows) directory of the JDK. Thus, if the JDK is installed in a directory called jdk1.2, the file is

  • jdk1.2/lib/security/java.security (Solaris)

  • jdk1.2\lib\security\java.security (Windows)

For each provider, this file should have a statement of the following form:

    security.provider.n=masterClassName

This declares a provider, and specifies its preference order n. The preference order is the order in which providers are searched for requested algorithms when no specific provider is requested. The order is 1-based; 1 is the most preferred, followed by 2, and so on.

masterClassName must specify the fully qualified name of the provider's "master class", which you implemented in Step 3. This class is always a subclass of the Provider class.

Whenever the JDK is installed, it contains one built-in (default) provider, the provider referred to as "SUN". The java.security file has just the following provider specification:

    security.provider.1=sun.security.provider.Sun
(The "SUN" provider's master class is the Sun class in the sun.security.provider package.)

Note that when you install JCE 1.2, its provider ("SunJCE") is not automatically installed, i.e., if you want to use the "SunJCE" provider, you have to explicitly register it - either statically or dynamically, as described in this section.

Suppose that your master class is the CryptoX class in the com.cryptox.provider package, and that you would like to make your provider the second preferred provider. To do so, add the following line to the java.security file below the line for the "SUN" provider:

    security.provider.2=com.cryptox.provider.CryptoX
Note: Providers may also be registered dynamically. To do so, a program (such as your test program, to be written in Step 7) can call either the addProvider or insertProviderAt method in the Security class. This type of registration is not persistent and can only be done by "trusted" programs. See the Security class section of the Java Cryptography Architecture API Specification and Reference.

Step 6: Write and Compile your Test Programs

Write and compile one or more test programs that test your provider's incorporation into the Security API as well as the correctness of its algorithm(s). Create any supporting files needed, such as those for test data to be encrypted.

The first tests your program should perform are ones to ensure that your provider is found, and that its name, version number, and additional information is as expected. To do so, you could write code like the following, substituting your provider name for "MyPro":

    import java.security.*;

    Provider p = Security.getProvider("MyPro");
    
    System.out.println("MyPro provider name is " + p.getName());
    System.out.println("MyPro provider version # is " + p.getVersion());
    System.out.println("MyPro provider info is " + p.getInfo());

Next, you should ensure that your services are found. For instance, if you implemented the DES encryption algorithm, you could check to ensure it's found when requested by using the following code (again substituting your provider name for "MyPro"):

    Cipher c = Cipher.getInstance("DES", "MyPro");

    System.out.println("My Cipher algorithm name is " + c.getAlgorithm());

If you don't specify a provider name in the call to getInstance, all registered providers will be searched, in preference order (see Configuring the Provider), until one implementing the algorithm is found.

Step 7: Run your Test Programs

Run your test program(s). Debug your code and continue testing as needed. If the Java Security API cannot seem to find one of your algorithms, review the steps above and ensure they are all completed.

Step 8: Document your Provider and its Supported Services

The next-to-last step is to write documentation for your clients. At the minimum, you need to specify In addition, your documentation should specify anything else of interest to clients, such as any default algorithm parameters.

MACs

For each MAC algorithm, tell whether or not your implementation is cloneable. This is not technically necessary, but it may save clients some time and coding by telling them whether or not intermediate "message authentication codes" (MACs) may be possible through cloning. Clients who do not know whether or not a MAC implementation is cloneable can find out by attempting to clone the Mac object and catching the potential exception, as illustrated by the following example:

try {
    // try and clone it
    /* compute the MAC for i1 */
    mac.update(i1); 
    byte[] i1Mac = mac.clone().doFinal();

    /* compute the MAC for i1 and i2 */
    mac.update(i2); 
    byte[] i12Mac = mac.clone().doFinal(); 

    /* compute the MAC for i1, i2 and i3 */
    mac.update(i3); 
    byte[] i123Mac = mac.doFinal();
} catch (CloneNotSupportedException cnse) {
  // have to use an approach not involving cloning
}
where

Key Pair Generators

For a key pair generator algorithm, in case the client does not explicitly initialize the key pair generator (via a call to an initialize method), each provider must supply and document a default initialization. For example, the Diffie-Hellman key pair generator supplied by the "SunJCE" provider uses a default prime modulus size (strength) of 512 bits.

Key Factories

A provider should document all the key specifications supported by its (secret-)key factory.

Algorithm Parameter Generators

In case the client does not explicitly initialize the algorithm parameter generator (via a call to an init method in the AlgorithmParameterGenerator engine class), each provider must supply and document a default initialization. For example, the "SunJCE" provider uses a default prime modulus size of 512 bits and a random exponent (private value) size of 504 bits for the generation of Diffie-Hellman parameters.

Step 9: Make your Class Files and Documentation Available to Clients

The final step is to make your class files and documentation available to clients in whatever form (.class files, zip files, JAR files, ...) and methods (web download, floppy, mail, ...) you feel are appropriate.

Further Implementation Details and Requirements

Algorithm Aliases

For many cryptographic algorithms, there is a single official "standard name". The standard names defined by JCE 1.2 are listed in Appendix A of the Java Cryptography Extension 1.2 API Specification & Reference.

For example, "DiffieHellman" is the standard name for the Diffie-Hellman key agreement algorithm defined in PKCS #3.

JCE 1.2 uses the same aliasing scheme for algorithm names as JDK 1.2. That scheme enables clients to use aliases when referring to algorithms, rather than their standard names. For example, the "SunJCE" provider's master class (SunJCE.java) defines the alias "DH" for the key agreement whose standard name is "DiffieHellman". Thus, the following statements are equivalent:

    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman", "SunJCE");

    KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");
Aliases can be defined in your "master class" (see Step 3). To define an alias, create a property named
    Alg.Alias.engineClassName.aliasName

where engineClassName is either Signature, MessageDigest, KeyPairGenerator, KeyFactory, AlgorithmParameterGenerator, or AlgorithmParameters, and aliasName is your alias name. The value of the property must be the standard algorithm name for the algorithm being aliased.

As an example, the "SunJCE" provider defines the alias "DH" for the key agreement algorithm whose standard name is "DiffieHellman" by setting a property named Alg.Alias.KeyAgreement.DH to have the value DiffieHellman via the following:

    put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");

Currently, aliases defined by the "SunJCE" provider are available to all clients, no matter which provider clients request. For example, if you create a provider named "MyPro" that implements the Diffie-Hellman algorithm, then even if you don't define any aliases for it, the "DH" alias defined by "SunJCE" can be used to refer to your provider's Diffie-Hellman implementation as follows:

    KeyAgreement ka = KeyAgreement.getInstance("DH", "MyPro");

WARNING: The aliasing scheme may be changed or eliminated in future releases.

Service Interdependencies

Some algorithms require the use of other types of algorithms. For example, a PBE algorithm usually needs to use a message digest algorithm in order to transform a password into a key.

If you are implementing one type of algorithm that requires another, you can do one of the following:

  1. Provide your own implementations for both.

  2. Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by the default "SUN" provider that is included with every JDK installation. For example, if you are implementing a PBE algorithm that requires a message digest algorithm, you can obtain an instance of a class implementing the MD5 message digest algorithm by calling
        MessageDigest.getInstance("MD5", "SUN")
    

  3. Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by another specific provider. This is only appropriate if you are sure that all clients who will use your provider will also have the other provider installed.
  4. Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by another (unspecified) provider. That is, you can request an algorithm by name, but without specifying any particular provider, as in
        MessageDigest.getInstance("MD5")
    
    This is only appropriate if you are sure that there will be at least one implementation of the requested algorithm (in this case, MD5) installed on each Java platform where your provider will be used.

Default Initializations

In case the client does not explicitly initialize a key pair generator or an algorithm parameter generator, each provider of such a service must supply (and document) a default initialization. For example, the "SunJCE" provider uses a default modulus size (strength) of 512 bits for the generation of Diffie-Hellman parameters.

Diffie-Hellman Interfaces and their Required Implementations

JCE 1.2 contains the following interfaces (in the javax.crypto.interfaces package) for the convenience of programmers implementing Diffie-Hellman services: The following sections discuss requirements for implementations of these interfaces.

DHPrivateKey and DHPublicKey Implementations

If you implement a Diffie-Hellman key pair generator or key factory, you need to create classes implementing the DHPrivateKey and DHPublicKey interfaces.

If you implement a Diffie-Hellman key pair generator, your generateKeyPair method (in your KeyPairGeneratorSpi subclass) will return instances of your implementations of those interfaces.

If you implement a Diffie-Hellman key factory, your engineGeneratePrivate method (in your KeyFactorySpi subclass) will return an instance of your DHPrivateKey implementation, and your engineGeneratePublic method will return an instance of your DHPublicKey implementation.

Also, your engineGetKeySpec and engineTranslateKey methods will expect the passed-in key to be an instance of a DHPrivateKey or DHPublicKey implementation. The getParams method provided by the interface implementations is useful for obtaining and extracting the parameters from the keys and then using the parameters, for example as parameters to the DHParameterSpec constructor called to create a parameter specification from parameter values that could be used to initialize a KeyPairGenerator object for Diffie-Hellman.

If you implement the Diffie-Hellman key agreement algorithm, your engineInit method (in your KeyAgreementSpi subclass) will expect to be passed a DHPrivateKey and your engineDoPhase method will expect to be passed a DHPublicKey.

Please note: The DHPublicKey and DHPrivateKey interfaces define a very generic, provider-independent interface to Diffie-Hellman public and private keys, respectively. The engineGetKeySpec and engineTranslateKey methods (in your KeyFactorySpi subclass) could additionally check if the passed-in key is actually an instance of their provider's own implementation of DHPrivateKey or DHPublicKey, e.g., to take advantage of provider-specific implementation details. The same is true for the Diffie-Hellman algorithm engineInit and engineDoPhase methods (in your KeyAgreementSpi subclass).

To see what methods need to be implemented by classes that implement the DHPublicKey and DHPrivateKey interfaces, first note the following interface signatures:

  In the javax.crypto.interfaces package:

    public interface DHPrivateKey extends DHKey, 
                                     java.security.PrivateKey

    public interface DHPublicKey extends DHKey, 
                                    java.security.PublicKey

    public interface DHKey

  In the java.security package:

    public interface PrivateKey extends Key

    public interface PublicKey extends Key

    public interface Key extends java.io.Serializable

In order to implement the DHPrivateKey and DHPublicKey interfaces, you must implement the methods they define as well as those defined by interfaces they extend, directly or indirectly.

Thus, for private keys, you need to supply a class that implements

  • the getX method from the DHPrivateKey interface.

  • the getParams method from the javax.crypto.interfaces.DHKey interface, since DHPrivateKey extends DHKey.
  • the getAlgorithm, getEncoded, and getFormat methods from the java.security.Key interface, since DHPrivateKey extends java.security.PrivateKey, and PrivateKey extends Key. Similarly, for public Diffie-Hellman keys, you need to supply a class that implements
    • the getY method from the DHPublicKey interface.

    • the getParams method from the javax.crypto.interfaces.DHKey interface, since DHPublicKey extends DHKey.
    • the getAlgorithm, getEncoded, and getFormat methods from the java.security.Key interface, since DHPublicKey extends java.security.PublicKey, and PublicKey extends Key.

Algorithm Parameter Specification Classes

An algorithm parameter specification is a transparent representation of the sets of parameters used with an algorithm.

A transparent representation of parameters means that you can access each value individually, through one of the "get" methods defined in the corresponding specification class (e.g., DHParameterSpec defines getP, getG, and getL methods, to access the p, g, and l parameters, respectively).

This is contrasted with an opaque representation, as supplied by the AlgorithmParameters engine class, in which you have no direct access to the key material values; you can only get the name of the algorithm associated with the parameter set (via getAlgorithm) and some kind of encoding for the parameter set (via getEncoded).

If you supply an AlgorithmParametersSpi, AlgorithmParameterGeneratorSpi, or KeyPairGeneratorSpi implementation, you must utilize the AlgorithmParameterSpec interface, since each of those classes contain methods that take an AlgorithmParameterSpec parameter. Such methods need to determine which actual implementation of that interface has been passed in, and act accordingly.

JCE 1.2 contains a number of AlgorithmParameterSpec implementations for the most frequently used cipher and key agreement algorithm parameters. If you are operating on algorithm parameters that should be for a different type of algorithm not provided by JCE 1.2, you will need to supply your own AlgorithmParameterSpec implementation appropriate for that type of algorithm.

JCE 1.2 defines the following algorithm parameter specification classes in the javax.crypto.spec package:

The IvParameterSpec Class

This class (which implements the AlgorithmParameterSpec interface) specifies the initialization vector (IV) used with a cipher in feedback mode. It has the following method:
    public byte[] getIV()
This method returns the IV.

The PBEParameterSpec Class

This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with a password-based encryption (PBE) algorithm. It has the following methods:
    public byte[] getSalt()

    public int getIterationCount()
These methods return the PBE parameters: the salt and the iteration count.

The RC2ParameterSpec Class

This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the RC2 algorithm. It has the following methods:
    public int getEffectiveKeyBits()

    public byte[] getIV()
These methods return the RC2 algorithm parameters: the effective key size (in bits) and the IV.

The RC5ParameterSpec Class

This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the RC5 algorithm. It has the following methods:
    public int getVersion()

    public int getRounds()

    public int getWordSize()

    public byte[] getIV()
These methods return the RC5 algorithm parameters: the version number, number of rounds, word size (in bits), and the IV.

The DHParameterSpec Class

This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the Diffie-Hellman algorithm. It has the following methods:
    public BigInteger getP()

    public BigInteger getG()

    public int getL()
These methods return the Diffie-Hellman algorithm parameters: the prime modulus p, the base generator g, and the size in bits of the random exponent (private value), l.

Many types of Diffie-Hellman services will find this class useful - for example, it is utilized by the Diffie-Hellman key agreement, key pair generator, algorithm parameter generator, and algorithm parameters classes implemented by the "SunJCE" provider. As a specific example, an algorithm parameters implementation must include an implementation for the getParameterSpec method, which returns an AlgorithmParameterSpec. The Diffie-Hellman algorithm parameters implementation supplied by "SunJCE" returns an instance of the DHParameterSpec class.

Key Specification Classes Required by Key Factories

Key specifications are transparent representations of the key material that constitutes a key. JCE 1.2 defines the following key specification classes in the javax.crypto.spec package: DHPrivateKeySpec, DHPublicKeySpec, DESKeySpec, and DESedeKeySpec.

The DHPrivateKeySpec Class

This class (which implements the KeySpec interface) specifies a Diffie-Hellman private key with its associated parameters. It has the following methods:
    public BigInteger getX()

    public BigInteger getP()

    public BigInteger getG()
These methods return the private value x, and the Diffie-Hellman algorithm parameters used to calculate it: the prime modulus p and the base generator g.

The DHPublicKeySpec Class

This class (which implements the KeySpec interface) specifies a Diffie-Hellman public key with its associated parameters. It has the following methods:
    public BigInteger getY()

    public BigInteger getP()

    public BigInteger getG()
These methods return the public value y, and the Diffie-Hellman algorithm parameters used to calculate it: the prime modulus p and the base generator g.

The DESKeySpec Class

This class (which implements the KeySpec interface) specifies a DES key. It has the following methods:
    public byte[] getKey()

    public static boolean isParityAdjusted(byte[] key, int offset)

    public static boolean isWeak(byte[] key, int offset)
The first method returns the DES key bytes. The other (class) methods check if a given DES key is parity adjusted or weak, respectively.

The DESedeKeySpec Class

This class (which implements the KeySpec interface) specifies a DES-EDE (Triple DES) key. It has the following methods:
    public byte[] getKey()

    public static boolean isParityAdjusted(byte[] key, int offset)
The first method returns the DES-EDE key bytes. The other (class) method checks if a given DES-EDE key is parity adjusted.

The SecretKeySpec Class

This class implements the KeySpec interface. Since it also implements the SecretKey interface, it can be used to construct a SecretKey object in a provider-independent fashion, i.e., without having to go through a provider-based SecretKeyFactory. It has the following methods:
    public SecretKeySpec(byte[] key, String algorithm)

    public SecretKeySpec(byte[] key, int offset, int len, String algorithm)

    public String getAlgorithm()
    
    public String getFormat()

    public byte[] getEncoded()

The two constructors take a byte array that constitutes the secret-key material, and the name of the associated secret-key algorithm.

The other methods return the secret-key algorithm name, key format (given as the string "RAW"), and secret-key bytes, respectively.

Secret-Key Generation

If you provide a secret-key generator (subclass of javax.crypto.KeyGeneratorSpi) for a particular secret-key algorithm, you may return the generated secret-key object (which must be an instance of javax.crypto.SecretKey, see engineGenerateKey) in one of the following ways:
  • You implement a class whose instances represent secret-keys of the algorithm associated with your key generator. Your key generator implementation returns instances of that class. This approach is useful if the keys generated by your key generator have provider-specific properties.

  • Your key generator returns an instance of SecretKeySpec, which already implements the javax.crypto.SecretKey interface. You pass the (raw) key bytes and the name of the secret-key algorithm associated with your key generator to the SecretKeySpec constructor. This approach is useful if the underlying (raw) key bytes can be represented as a byte array and have no key-parameters associated with them.

Appendix A: The "SunJCE" Provider's Master Class

Below is an edited version of the SunJCE.java file, which contains a class named SunJCE that is the master class for the provider named "SunJCE". (Although that provider is supplied with every JCE 1.2 installation, it still needs to be configured.)

As with all master classes, this class is a subclass of Provider. It specifies the class names and package locations of all the cryptographic service implementations supplied by the "SunJCE" provider. This information is used by the getInstance methods of the engine classes to look up the various algorithms and other services when they are requested.

This code is supplied as an example of a provider master class.

/*
 * Copyright 1997, 1998 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

package com.sun.crypto.provider;

import java.security.AccessController;
import java.security.Provider;

/**
 * The "SunJCE" Cryptographic Service Provider.
 */

/**
 * Defines the "SunJCE" provider.
 *
 * Supported algorithms and their names:
 *
 * - DES (ECB, CBC, CFB, OFB, PCBC)
 *
 * - DES-EDE (ECB, CBC, CFB, OFB, PCBC)
 *
 * - Password-based Encryption (PBE)
 *
 * - Blowfish
 *
 * - Diffie-Hellman Key Agreement
 *
 * - HMAC-MD5, HMAC-SHA1
 *
 * - PKCS5Padding
 */

public final class SunJCE extends Provider {

    private static String info = "SunJCE Provider " + 
    "(implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman, HMAC-MD5, "
    + "HMAC-SHA1)";

    public SunJCE() {
	/* We are the "SunJCE" provider */
	super("SunJCE", 1.2, info);

        AccessController.doPrivileged(new java.security.PrivilegedAction() {
            public Object run() {

		/*
		 * Cipher engines 
		 */
		put("Cipher.DES", "com.sun.crypto.provider.DESCipher");

		put("Cipher.DESede", "com.sun.crypto.provider.DESedeCipher");
		put("Alg.Alias.Cipher.TripleDES", "DESede");

		put("Cipher.PBEWithMD5AndDES",
		    "com.sun.crypto.provider.PBEWithMD5AndDESCipher");

		put("Cipher.Blowfish",
		    "com.sun.crypto.provider.BlowfishCipher");

		/*
		 *  Key(pair) Generator engines 
		 */
		put("KeyGenerator.DES", 
		    "com.sun.crypto.provider.DESKeyGenerator");

		put("KeyGenerator.DESede", 
		    "com.sun.crypto.provider.DESedeKeyGenerator");
		put("Alg.Alias.KeyGenerator.TripleDES", "DESede");

		put("KeyGenerator.Blowfish", 
		    "com.sun.crypto.provider.BlowfishKeyGenerator");

		put("KeyPairGenerator.DiffieHellman", 
		    "com.sun.crypto.provider.DHKeyPairGenerator");
		put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman");

		/*
		 * Algorithm parameter generation engines
		 */
		put("AlgorithmParameterGenerator.DiffieHellman",
		    "com.sun.crypto.provider.DHParameterGenerator");
		put("Alg.Alias.AlgorithmParameterGenerator.DH",
		    "DiffieHellman");

		/* 
		 * Key Agreement engines 
		 */
		put("KeyAgreement.DiffieHellman",
		    "com.sun.crypto.provider.DHKeyAgreement");
		put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");

		/* 
		 * Algorithm Parameter engines 
		 */
		put("AlgorithmParameters.DiffieHellman",
		    "com.sun.crypto.provider.DHParameters");
		put("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman");

		put("AlgorithmParameters.DES",
		    "com.sun.crypto.provider.DESParameters");

		put("AlgorithmParameters.DESede",
		    "com.sun.crypto.provider.DESedeParameters");
		put("Alg.Alias.AlgorithmParameters.TripleDES", "DESede");

		put("AlgorithmParameters.PBE",
		    "com.sun.crypto.provider.PBEParameters");
		put("Alg.Alias.AlgorithmParameters.PBEWithMD5AndDES", "PBE");

		put("AlgorithmParameters.Blowfish",
		    "com.sun.crypto.provider.BlowfishParameters");

		/*
		 * Key factories
		 */
		put("KeyFactory.DiffieHellman",
		    "com.sun.crypto.provider.DHKeyFactory");
		put("Alg.Alias.KeyFactory.DH", "DiffieHellman");

		/*
		 * Secret-key factories
		 */
		put("SecretKeyFactory.DES", 
		    "com.sun.crypto.provider.DESKeyFactory");

		put("SecretKeyFactory.DESede",
		    "com.sun.crypto.provider.DESedeKeyFactory");
		put("Alg.Alias.SecretKeyFactory.TripleDES", "DESede");

		put("SecretKeyFactory.PBE",
		    "com.sun.crypto.provider.PBEKeyFactory");
		put("Alg.Alias.SecretKeyFactory.PBEWithMD5AndDES", "PBE");

		/*
		 * MAC
		 */
		put("Mac.HmacMD5", "com.sun.crypto.provider.HmacMD5");
		put("Mac.HmacSHA1", "com.sun.crypto.provider.HmacSHA1");

		/*
		 * KeyStore
		 */
		put("KeyStore.JCEKS", "com.sun.crypto.provider.JceKeyStore");

		return null;
	    }
	});
    }
}

Appendix B: The java.security Properties File

Below is a copy of the java.security file that appears in every JDK installation. This file appears in the lib/security (lib\security on Windows) directory of the JDK. Thus, if the JDK is installed in a directory called jdk1.2, the file would be

See Step 5 for an example of adding information about your provider to this file.
#
# This is the "master security properties file".
#
# In this file, various security properties are set for use by
# java.security classes. This is where users can statically register 
# Cryptography Package Providers ("providers" for short). The term 
# "provider" refers to a package or set of packages that supply a 
# concrete implementation of a subset of the cryptography aspects of 
# the Java Security API. A provider may, for example, implement one or 
# more digital signature algorithms or message digest algorithms.
#
# Each provider must implement a subclass of the Provider class.
# To register a provider in this master security properties file, 
# specify the Provider subclass name and priority in the format
#
#    security.provider.n=className 
#
# This declares a provider, and specifies its preference 
# order n. The preference order is the order in which providers are 
# searched for requested algorithms (when no specific provider is 
# requested). The order is 1-based; 1 is the most preferred, followed 
# by 2, and so on.
#
# className must specify the subclass of the Provider class whose 
# constructor sets the values of various properties that are required
# for the Java Security API to look up the algorithms or other 
# facilities implemented by the provider.
# 
# There must be at least one provider specification in java.security. 
# There is a default provider that comes standard with the JDK. It
# is called the "SUN" provider, and its Provider subclass
# named Sun appears in the sun.security.provider package. Thus, the
# "SUN" provider is registered via the following:
#
#    security.provider.1=sun.security.provider.Sun 
#
# (The number 1 is used for the default provider.) 
#
# Note: Statically registered Provider subclasses are instantiated 
# when the system is initialized. Providers can be dynamically 
# registered instead by calls to either the addProvider or 
# insertProviderAt method in the Security class.

#
# List of providers and their preference orders (see above):
#
security.provider.1=sun.security.provider.Sun

#
# Class to instantiate as the system Policy. This is the name of the class
# that will be used as the Policy object.
#
policy.provider=sun.security.provider.PolicyFile

# The default is to have a single system-wide policy file, 
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

# whether or not we expand properties in the policy file
# if this is set to false, properties (${...}) will not be expanded in policy
# files.
policy.expandProperties=true

# whether or not we allow an extra policy to be passed on the command line
# with -Djava.security.policy=somefile. Comment out this line to disable
# this feature.
policy.allowSystemProperty=true

# whether or not we look into the IdentityScope for trusted Identities
# when encountering a 1.1 signed JAR file. If the identity is found
# and is trusted, we grant it AllPermission.
policy.ignoreIdentityScope=false

#
# Default keystore type.
#
keystore.type=jks

#
# Class to instantiate as the system scope:
#
system.scope=sun.security.provider.IdentityDatabase


Copyright © 1996-98 Sun Microsystems, Inc. All Rights Reserved.

Please send comments to: java-security@java.sun.com.
Sun
Java Software Division