Skip to main content


developerWorks  >   Java™ technology  >   IBM developer kits  >   Security information  >   5.0  >  

Security information

The following pages contain documentation, example code, and ancillary files relating to IBM's SDKs. The documentation covers IBM-specific features of IBM's offerings. A platform-specific Security User Guide is included in each download. For information about the SDK for z/OS product and security components specific to that platform, see this Web site.

Before you can download code, you will need an IBM Registration ID. You can read about IBM Registration here.

developerWorks

How to Implement a Provider for the Java Cryptography Extension

How to Implement a Provider for the

JavaTM Cryptography Extension(JCE)

in the JavaTM 2 SDK, v 5.0

Last Modified: 31st October 2005


Copyright information

Note: Before using this information and the product it supports, be sure to read the general information under Notices.

(c) Copyright Sun Microsystems, Inc. 1998, 2005, 901 San Antonio Rd., Palo Alto, CA 94303 USA. All rights reserved.

(c) Copyright International Business Machines Corporation, 1998, 2005. All rights reserved.

U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.


IntroductionWhat's New Engine Classes and Corresponding SPI Classes

Steps to Implement and Integrate a Provider How a Provider Can Do Self-Integrity Checking How a Provider Authenticates The Framework(JCE 1.2.1 only) Further Implementation Details and Requirements Appendix A: The "IBMJCE" Provider's Master Class

Appendix B: The java.security Master Properties File

Notices


Introduction

The JavaTM Cryptography Extension (JCE) provides a framework and implementations for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms. Support for encryption includes symmetric, asymmetric, block, and stream ciphers. The software also supports secure streams and sealed objects.

JCE was previously an optional package (extension) to the Java 2 SDK, Standard Edition (Java 2 SDK), versions 1.2.x and 1.3.x. JCE has now been integrated into the Java 2 SDK, v 1.4.

JCE is based on the same design principles as Java 2 SDK, which uses the notion of a Cryptographic Service 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 Java 2 SDK.

JCE 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 that needs to use cryptography functionality can simply request a particular type of object (such as a Cipher object) that implements 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 Java 2 SDK installation has one or more provider packages installed. Each provider package supplies implementations of cryptographic services defined in Java 2 SDK v 1.4 or JCE or both.

Clients can 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.

The Java 2 SDK v 1.4.2 comes standard with a provider named "IBMJCE", which supplies the following services:

    • Implementation of Message Authentication Code (MAC): HmacSHA1, HmacMD5
    • Implementation of Key Agreement algorithms: DiffieHellman
    • Implementation of Message Digest: MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512
    • Implementation of Signature algorithms: SHA1withDSA, SHA1withRSA, MD5withRSA, MD2withRSA
    • Implementation of Key Factory: DiffieHellman, DSA, RSA
    • Implementation of Secret Key Factory: AES, Blowfish, DES, TripleDES, Mars, RC2, RC4, RC5, Seal, PKCS5Key, PBKDF1 and PBKDF2(PKCS5Derived Key)
    • Implementation of Cipher: AES, DES, TripleDES, PBEWithMD2AndDES, PBEWithMD2AndTripleDES, PBEWithMD2AndRC2,PBEWithMD5AndDES, PBEWithMD5AndTripleDES, PBEWithMD5AndRC2, PBEWithSHA1AndDES, PBEWithSHA1AndTripleDES, PBEWithSHA1AndRC2, Mars, RC2, RC4, RSA, Seal
    • Implementation of Modes of operation for Block Ciphers: ECB, CBC, CFB, CTR, OFB, PCBC
    • Implementation of Key PairGeneration: DSA, RSA, DiffieHellman
    • Implementation of Key Generation: Blowfish, DiffieHellman, DES, TripleDES, HmacMD5, HmacSHA1, Mars, RC2, RC4, RC5, Seal
    • Implementation of Algorithm Parameter Generator: DiffieHellman, DSA
    • Implementation of KeyStore: JCEKS, PKCS12, JKS
New providers can be added statically or dynamically. Clients might also query which providers are currently installed.

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

Who Should Read This Document

If you only need to use the Java Security API to access existing cryptography algorithms and other services, you do not need to read this document.

This document is intended for developers of cryptographic service providers. 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.

Only providers signed by a trusted entity can be plugged into the JCE framework.

Related Documentation

This document assumes that 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:

A Note on Terminology

The JCE includes two software components:
  • The framework that defines and supports cryptographic services that providers can supply implementations for. This framework includes everything in the javax.crypto package.
  • A provider named "IBMJCE"
Throughout this document, the term "JCE" refers to the JCE framework. If the full release is mentioned, it will be referred to as "the JCE release."

What's New

JCE in Java 2 SDK, v 5.0

These are the differences between JCE in Java 2 SDK, v 1.4 and Java 2 SDK, v 5.0 that affect providers:

Added ByteBuffer API Support

Methods that take ByteBuffer arguments were added to the JCE API and SPI classes for processing bulk data. Providers can override the engine* methods if they can process ByteBuffers more efficiently than byte[].

Full support for RSA-OAEP algorithm

In 5.0, new parameter classes were added to fully support OAEP.

Simplified retrieval of PKCS8EncodedKeySpec from javax.crypto.EncryptedPrivateKeyInfo

To make EncyptedPrivateKeyInfo easier to use and to make its API consistent with javax.crypto.SealedObject, methods were added to javax.crypto.EncryptedPrivateKeyInfo.

Dynamically determine maximum allowable key length

Methods were added to javax.crypto.Cipher to enable dynamic maximum allowable key length determination.

JCE in Java 2 SDK, v 1.4

These are the differences between JCE 1.2.1 and the JCE in the Java 2 SDK, v 1.4 that affect providers:

JCE Is Now in Java 2 SDK

JCE was previously an optional package (extension) to the Java 2 SDK, Standard Edition (Java 2 SDK), versions 1.2.x and 1.3.x. JCE has now been integrated into the Java 2 SDK, v 1.4. The IBMJCE provider is also included and is automatically registered in the java.security security properties file included with the Java 2 SDK, v 1.4.

Strong Cryptography Is the Default, Unlimited Is Available

Due to import control restrictions, the jurisdiction policy files included with the Java 2 SDK, v 1.4 allow "strong" but limited cryptography to be used. An "unlimited" version of these files indicating no restrictions on cryptographic strengths is available for those living in eligible countries (which is most countries). You can download this version and replace the strong cryptography versions supplied with the Java 2 SDK, v 1.4.2 with the unlimited ones. See the following web site for information indicating where to go to download the unlimited version. Note that the jurisdiction policy files from other JDK levels (e.g. 1.4.1) are not applicable to 1.4.2 and vice versa.

http://www6.software.ibm.com/dl/jcesdk/jcesdk-p

The jurisdiction policy files have been relocated to

<java-home>\lib\security [Windows]
<java-home>/lib/security [Unix]
where <java-home> refers to the directory where the runtime software is installed, which is the top-level directory of the JavaTM 2 Runtime Environment (JRE) or the jre directory in the JavaTM 2 SDK (Java 2 SDK) software. They have been moved to this standard location so that it is easy to replace the strong cryptography versions that come with the Java 2 SDK, v 1.4 with the unlimited ones.

Provider Authentication of JCE Framework Is No Longer Required

In JCE 1.2.1, providers needed to include code to authenticate the JCE framework to assure themselves of the integrity and authenticity of the JCE that they plugged into. Now that JCE is integrated into the Java 2 SDK, v 1.4, this is no longer necessary.

JCE 1.2.1 providers that follow the guidance in the section on "How a Provider Authenticates The Framework" will work with the JCE framework in the Java 2 SDK, v 1.4.

However, a provider whose framework authentication code locates the JCE framework using protection domain instead of following the recommendations in the aforementioned JCE 1.2.1 JCE provider document will not work in the Java 2 SDK, v 1.4. Now that JCE has been integrated into the Java 2 SDK, v 1.4, the JCE framework has a null code source just like any other class in the Java 2 SDK, v 1.4. You can either modify your provider to follow the recommended approach for authenticating the framework, or put in a condition so that the framework authentication code is executed only when the provider is being run with JCE 1.2.1.

JCE 1.2.1 (previous release)

There are two differences between JCE 1.2 and JCE 1.2.1 that affect providers, one substantial and one minor (and optionally implemented):

Exportability

The primary difference between JCE 1.2 and JCE 1.2.1 is that the JCE framework and provider cryptography implementations are now exportable outside the U.S. and Canada if certain conditions are satisfied.

Export control restrictions by the U.S. Commerce Department prohibit frameworks for encryption services from being exported, unless appropriate mechanisms have been implemented to ensure that only qualified providers can be plugged into the framework. (Qualified providers include those approved for export and those certified for domestic use only. Qualified providers are signed by a trusted entity.)

The JCE framework contains such mechanisms and is now exportable. It is transparent to application developers how providers are authenticated, and only qualified providers can be plugged into JCE.

The JCE framework also enforces restrictions regarding the cryptographic algorithms and maximum cryptographic strength available to applets/applications in different jurisdiction contexts (locations). This makes the JCE framework worldwide exportable and worldwide importable.

The cryptographic services that your provider supplies can now be used throughout the world, if certain conditions are met. You can write just one version of your provider software, implementing cryptography of maximum strength. It is up to JCE, not your provider, to enforce restrictions regarding the cryptographic algorithms and maximum cryptographic strengths available. For further information as to how this implementation affects applets and applications, see Application Exportability in the Java Cryptography Extension API Specification & Reference.

In order to be able to plug into JCE, a provider should follow certain implementation guidelines and must be signed by an entity trusted by JCE, as described in Ensuring Exportability.

A provider can also optionally implement one or more exemption mechanisms (such as key recovery) which, if utilized by an application (or applet), allows that application to use cryptography of greater strength than that allowed by default. See How to Implement an Exemption Mechanism.

Key Wrapping for Secure Transport

Another difference between JCE 1.2 and JCE 1.2.1 that affects providers is the addition of engineWrap and engineUnwrap methods in the CipherSpi class. Providers can optionally implement these methods for "wrapping" and "unwrapping" keys.

"Wrapping" a key enables secure transfer of the key from one place to another.

Implementation by a provider of the new CipherSpi engineWrap and engineUnwrap methods is optional.

Further information about wrapping and unwrapping keys is provided in the Wrapping and Unwrapping Keys section of the Java Cryptography Extension API Specification & Reference.

Engine Classes and Corresponding SPI 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 J2SE 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 was previously an optional package (also known as an "extension") to the Java 2 Platform, versions 1.2.x and 1.3.x. JCE has now been integrated into the Java 2 SDK, v 1.4 and supplements the cryptographic services defined since Java 2 SDK v 1.2 by adding the following engine classes:

  • Cipher - used to encrypt or decrypt some specified data.
  • KeyAgreement - used to execute a key agreement (key exchange) protocol between 2 or more parties.
  • KeyGenerator - used to generate a secret (symmetric) key suitable for a specified algorithm.
  • Mac - used to compute the message authentication code of some specified data.
  • SecretKeyFactory - used to convert opaque cryptographic keys of type SecretKey into key specifications (transparent representations of the underlying key material), and vice versa.
  • ExemptionMechanism - used to provide the functionality of an exemption mechanism, examples of which are key recovery, key weakening, and key escrow. Applications or applets that use an exemption mechanism can be granted stronger encryption capabilities than those that don't.
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, can 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 Classes Required by Key Factories.) The actual implementation supplied in a SecretKeyFactorySpi subclass would be that for a specific type of secret keys, such as DES keys.

Steps to Implement and Integrate a Provider

The steps required in order to implement a provider and integrate it into JCE are the following:

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 in addition to implementations of cryptographic services defined in Java 2 SDK v 1.4.2.

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

In Java 2 SDK v 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 or Java 2 SDK, you need to create a subclass of the appropriate SPI class. JCE defines the engine classes: CipherSpi, KeyAgreementSpi, KeyGeneratorSpi, MacSpi, SecretKeyFactorySpi, and ExemptionMechanismSpi. (See "JCE 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. When one of your services is requested, Java Security looks up the subclass that implements 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.
  3. 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.

Additional JCE Provider Requirements and Recommendations

When instantiating a provider's implementation (class) of a JCE service, the JCE framework will determine the provider's codebase (JAR file) and verify its signature. In this way, JCE authenticates the provider and ensures that only providers signed by a trusted entity can be plugged into JCE. Therefore, one new requirement for providers in JCE is that they must be signed, as described in later steps.

Similarly, when using JCE1.2.1 framework, each SPI implementation class should authenticate the JCE 1.2.1 framework in its constructor. This assures authorized providers of the integrity and authenticity of the JCE that they plug into.

In addition, each provider should perform self-integrity checking to ensure that the JAR file containing its code has not been manipulated in an attempt to invoke provider methods directly rather than through JCE. For further information, see How a Provider Can Authenticate JCE and Do Self-Integrity Checking.

In order for provider classes to become unusable if instantiated by an application directly, bypassing JCE, providers should implement the following:

  • All SPI implementation classes in a provider package should be declared final (so that they cannot be subclassed), and their (SPI) implementation methods should be declared protected.
  • All crypto-related helper classes in a provider package should have package-private scope, so that they cannot be accessed from outside the provider package.
For providers that can be exported outside the U.S. and Canada, CipherSpi implementations must include an implementation of the new engineGetKeySize method which, given a Key, returns the key size. Each Cipher initialization method executed in a non-domestic release calls engineGetKeySize and then compares the result with the maximum allowable key size for the particular location and circumstances of the applet or application being run. If the key size is too large, the initialization method throws an Exception.

Additional optional features that providers can implement for JCE are:

  • The engineWrap and engineUnwrap CipherSpi methods. See Wrapping or Unwrapping Keys.
  • One or more "exemption mechanisms." An exemption mechanism is something such as key recovery, key escrow, or key weakening which, if implemented and enforced, can enable reduced cryptographic restrictions for an application (or applet) that utilizes it. See How to Implement an Exemption Mechanism.

Step 2: Give your Provider a Name

Decide on a name for your provider. This name will 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:

  • Call super, specifying the provider name (see Step 2), version number, and a string of information about the provider and algorithms it supports. For example:
  •  super("CryptoX", 1.0, "CryptoX provider v1.0, implementing " +
    "RSA encryption and key pair generation, and DES encryption.");
  • Set the values of various properties that are required for the Java Security API to look up the cryptographic services implemented by the provider. For each service implemented by the provider, there must be a property whose name is the type of service (Cipher, KeyAgreement, KeyGenerator, Mac, SecretKeyFactory, or ExemptionMechanism), followed by a period and the name of the algorithm to which the service applies. The property value must specify the fully qualified name of the class that implements the service.

  • The list below shows the various types of properties that must be defined for the various types of JCE services, where the actual algorithm name is substitued for algName:

    • Cipher.algName
    • KeyAgreement.algName
    • KeyGenerator.algName
    • Mac.algName
    • SecretKeyFactory.algName
    • ExemptionMechanism.algName

    In all of these except ExemptionMechanism and Cipher, algName is the "standard" name of the algorithm.

    In the case of ExemptionMechanism, algName refers to the name of the exemption mechanism, which must be one of the following: "KeyRecovery", "KeyEscrow", or "KeyWeakening". Case does not matter.

    In the case of Cipher, algName can actually represent a transformation, and can be composed of an algorithm name, a particular mode, and a padding scheme. (See Appendix A of the Java Cryptography Extension API Specification & Reference for the standard algorithm names that should be used.)

    The value of each property must be the fully qualified name of the class that implements the specified algorithm. That is, it must be the package name followed by the class name, where the two are separated by a period.

    As an example, the "IBMJCE" provider implements the Diffie-Hellman key agreement algorithm in a class named DHKeyAgreement in the com.ibm.crypto.provider package. Its subclass of Provider (which is the IBMJCE class in the com.ibm.crypto.provider package) sets the KeyAgreement.DiffieHellman property to have the value "com.ibm.crypto.provider.DHKeyAgreement" using the following:

     put("KeyAgreement.DiffieHellman",
    "com.ibm.crypto.provider.DHKeyAgreement")
For further master class property setting examples, see Appendix A to view the current JCE IBMJCE.java source file. This shows how the IBM class constructor sets all the properties for the "IBMJCE" 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, such as from a file.

As mentioned above, in the case of a Cipher property, algName can 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 (such as DES), and can be followed by a mode and a padding scheme.

A transformation is of the form:

  • "algorithm/mode/padding" or
  • "algorithm"
(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 (such as DES in CFB or OFB mode), a client might 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 stream cipher mode is not followed by a number, a provider-specific default is used. (For example, the "IBMJCE" provider uses a default of 64 bits.)

A provider might supply a separate class for each combination of algorithm/mode/padding, or might 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 or padding or both are set automatically by the getInstance methods of Cipher, which invoke the engineSetMode and engineSetPadding methods of the provider's subclass of CipherSpi.

That is, a Cipher property in a provider master class can have one of the following formats:

 // provider's subclass of "CipherSpi" implements "algName" with 
// pluggable mode and padding
Cipher.algName
 // provider's subclass of "CipherSpi" implements "algName" in the
// specified "mode", with pluggable padding
Cipher.algName/mode
 // provider's subclass of "CipherSpi" implements "algName" with
// the specified "padding", with pluggable mode
Cipher.algName//padding
 // provider's subclass of "CipherSpi" implements "algName" with
// the specified "mode" and "padding"
Cipher.algName/mode/padding
(See Appendix A of the Java Cryptography Extension API Specification & Reference for the standard algorithm names, modes, and padding schemes that should be used.)

For example, a provider can 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:

  • Cipher.DES/ECB/PKCS5Padding
  • Cipher.DES/CBC/PKCS5Padding
  • Cipher.DES/CFB/PKCS5Padding
  • Cipher.DES/OFB/PKCS5Padding
Another provider may implement a class for each of the above modes (that is, 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:
  • Cipher.DES
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".

  2. 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.

  2. If the answer is YES, instantiate it.
    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/mode".

  4. 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.
  5. Check if the provider has registered a subclass of CipherSpi for the sub-transformation "algorithm//padding" (note the double slashes).

  6. 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.
  7. Check if the provider has registered a subclass of CipherSpi for the sub-transformation "algorithm".

  8. 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

Step 5a: Get a Code-Signing Certificate for Testing

Request a code-signing certificate for testing only. This certificate has a limited validity period (30 days). It is provided for testing only. You should not use it to sign your provider in the production environment.

Below are the steps you should use to get a code-signing certificate for testing. For more information on the keytool tool, see keytool (Link to external Web sitefor Microsoft(R) Windows(R)).

  1. Use keytool to generate a DSA keypair.
  2.  keytool -genkey -alias <alias> -keyalg DSA -keysize 1024
    -dname "cn=<Company Name>,ou=JCE Code Signing CA,o=IBM Corporation"
    -keystore <keystore file name>
    -storepass <keystore password>
    (Note: This command must be typed as a single line. Multiple lines and indentation are used in the examples just for legibility purposes.)

    This command will generate a DSA keypair (a public key and an associated private key) and store it in an entry in the specified keystore. The public key is stored in a self-signed certificate. The keystore entry can subsequently be accessed using the specified alias.

    The option values in angle brackets ("<" & ">") represent the actual values that must be supplied. For example, <alias> must be replaced with whatever alias name you want to be used to refer to the newly generated keystore entry in the future, and <keystore file name> must be replaced with the name of the keystore to be used. Note: Do not surround actual values with angle brackets. For example, if you want your alias to be myTestAlias, specify the -alias option as follows:

     -alias myTestAlias
    If you specify a keystore that doesn't yet exist, it will be created.

    Note: If command lines you type are not allowed to be as long as the keytool -genkey command you want to execute (for example, if you are using a Microsoft Windows DOS prompt), you can create and execute a plain-text batch file containing the command. That is, create a new text file that contains nothing but the full keytool -genkey command. (Remember to type it all on one line.) Save the file with a .bat extension. Then in your DOS window, type the file name (with its path, if necessary to run the command in the batch file.

  3. Use the keytool to generate a certificate signing request.
  4. keytool -certreq -alias <alias> -sigalg DSA 
    -file <csr file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    Here, <alias> is the alias for the DSA keypair entry created in the previous step. This command generates a Certificate Signing Request (CSR), using the PKCS#10 format. It stores the CSR in the file whose name is specified in <csr file name>.
  5. Send the CSR and contact information to the JCE Code Signing Certification Authority.

  6. Send, using email, the CSR and contact information to javasec@us.ibm.com. Put the following text in the Subject line of your email message: Request a Certificate for Signing a JCE Provider (Testing) Put the contact information in the body of the message and send the CSR file as a plain text attachment to the message. If your mail tool has an option for specifying the encoding format to be used for attachments, select the "MIME" option. Note: The CSR file is just a plain text file, in Base 64 encoding. Only the first and last lines are human-readable.

    Include the following contact information in the body of your message:

    Company Name
    Street Address (Not a post office box)
    City
    State/Province
    Country
    Company Telephone Number
    Company Fax Number
    Company Home Page URL
    Requester Name
    Requester Telephone Number
    Requester Email Address
    Brief description of your company (size, line of business, etc.)
    All of the above information is required, except for the home page URL.

    The JCE Code Signing Certification Authority will authenticate you, the requester. Then it will create and sign a code-signing certificate for testing, valid for 30 days. It will send you an email message containing two plain-text file attachments: one file containing this code-signing certificate for testing and another file containing its own CA certificate, which authenticates its public key.

  7. Use keytool to import the certificates received from the CA.

  8. After you have received the two certificates from the JCE Code Signing Certification Authority, you can use keytool to import them into your keystore.

    First import the CA certificate as a "trusted certificate":

    keytool -import -alias <alias for the CA cert> 
    -file <CA cert file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    Then import the code-signing certificate:
    keytool -import -alias <alias> 
    -file <code-signing cert file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    Here, <alias> is the same alias as that which you created in step 1 where you generated a DSA keypair. This command replaces the self-signed certificate in the keystore entry specified by <alias> with the one signed by the JCE Code Signing Certification Authority.
Now that you have in your keystore a certificate from an entity trusted by JCE (the JCE Code Signing Certification Authority), you can place your provider code in a JAR file (Step 5b) and then use that certificate to sign the JAR file (Step 5c)

Step 5b: Place Your Provider in a JAR File

Place your provider code in a JAR file, in preparation for signing it in the next step. For more information on the jar tool, see jar (Link to external Web sitefor Microsoft Windows).
jar cvf <JAR file name> <list of classes, separated by spaces>
This command creates a JAR file with the specified name containing the specified classes.

Step 5c: Sign Your Provider for Testing

Sign the JAR file created in the previous step with the code-signing certificate obtained in Step 5a. For more information on the jarsigner tool, see jarsigner (Link to external Web sitefor Microsoft Windows).
jarsigner -keystore <keystore file name> 
-storepass <keystore password>
<JAR file name> <alias>
Here, <alias> is the alias into the keystore for the entry containing the code-signing certificate received from the JCE Code Signing Certification Authority (the same alias as that specified in the commands in Step 5a).

You can test verification of the signature using the following command:

jarsigner -verify <JAR file name>
The text "jar verified" will be displayed if the verification was successful.

Step 5d: Install the Provider

In order to prepare for testing your provider, you must install it in the same manner that will be used by the clients that will 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. Your provider classes should be packaged as a JAR (Java ARchive) file.

There are two possible ways of installing your provider classes:

  • Place a JAR file containing your own provider classes anywhere on your CLASSPATH.
  • Supply your own provider JAR file as an "installed" or "bundled" extension.
For more information on "installed" extensions, see Link to external Web siteInstalled Extensions.

For more information on "bundled" extensions, see Link to external Web siteBundled Extensions.

Configuring the Provider

The next step is to add the provider to your list of approved providers. Adding the provider is done statically by editing the security properties file
<java-home>\lib\security\java.security [Windows]
<java-home>/lib/security/java.security [Unix]
Here <java-home> refers to the directory where the JRE was installed. For example, if you have Java 2 SDK v 1.4 installed on Windows in a directory named jdk1.4, you need to edit the following file:
C:\jdk1.4\jre\lib\security\java.security
For each provider, this file should have a statement of the following form:
security.provider.n=masterClassName
          
This statement 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.

Java 2 SDK v 1.4 comes standard with a number of providers that are automatically configured as static providers in the java.security properties file, as follows:

security.provider.1=com.ibm.jsse.IBMJSSEProvider
security.provider.2=com.ibm.crypto.provider.IBMJCE
security.provider.3=com.ibm.security.jgss.IBMJGSSProvider
security.provider.4=com.ibm.security.cert.IBMCertPath

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 fifth preferred provider. To do so, add the following line to the java.security file below the line for the "IBMCertPath" provider:

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

For instance, if the provider code of a provider with name "MyJCE" is in myjce_provider.jar in the myDir directory:

grant codeBase "file:/myDir/myjce_provider.jar" {
permission java.security.SecurityPermission
"insertProvider.MyJCE";
};

Step 5e: Set Provider Permissions

Whenever JCE providers are not installed extensions, permissions must be granted for when applets or applications using JCE are run while a security manager is installed. There is typically a security manager installed whenever an applet is running, and a security manager can be installed for an application either using code in the application itself or via a command-line argument. Permissions do not need to be granted to installed extensions, because the default system policy file grants all permissions to installed extensions.

Whenever a client does not install your provider as an installed extension, your provider might need the following permissions granted to it in the client environment:

  • java.lang.RuntimePermission to get class protection domains. The provider might need to get its own protection domain in the process of doing self-integrity checking.
  • java.security.SecurityPermission to set provider properties.

To ensure that your provider works when a security manager is installed and that the provider is not an installed extension, you need to test such an installation and execution environment. In addition, prior to testing you need to grant appropriate permissions to your provider and to any other providers it uses. For example, a sample statement granting permissions to a provider whose name is "MyJCE" and whose code is in myjce_provider.jar appears below. Such a statement could appear in a policy file. In this example, the myjce_provider.jar file is assumed to be in the /myDir directory.

grant codeBase "file:/myDir/myjce_provider.jar" {
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.security.SecurityPermission
"putProviderProperty.MyJCE";
};

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 algorithms. 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 is 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 a provider that is implementing the algorithm is found.

If your provider implements an exemption mechanism, you should write a test applet or application that utilizes the exemption mechanism. Such an applet or application also needs to be signed, and needs to have a "permission policy file" bundled with it. See How to Make Applications "Exempt" from Cryptographic Restrictions. in the Java Cryptography Extension API Specification & Reference for complete information about creating and testing such an application.

Step 7: Run your Test Programs

Run your test programs. 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 that they are all completed.

Step 8: Document Your Provider and Its Supported Services

The next step is to write documentation for your customers. At the minimum, you need to specify
  • The name programs should use to refer to your provider. Note: Provider name searches are case-sensitive. That is, if your master class specifies your provider name as "CryptoX" but a user requests "CRYPTOx", your provider will not be found.
  • The types of algorithms and other services implemented by your provider.
  • Instructions for installing the provider, similar to those provided in Step 5d, except that the information and examples should be specific to your provider.
In addition, your documentation should specify anything else of interest related to using your provider such as any default algorithm parameters.

MACs

For each MAC algorithm, tell whether or not your implementation is cloneable, to save your customers some time and coding. Customers 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
  • mac is the MAC object they received when they requested one using a call to Mac.getInstance,
  • i1,i2 and i3 are input byte arrays, and
  • they want to calculate separate hashes for:
    • i1
    • i1 and i2
    • i1, i2, and i3

Key Pair Generators

For a key pair generator algorithm, in case the customer does not explicitly initialize the key pair generator (using 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 "IBMJCE" provider uses a default prime modulus size (keysize) of 1024 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 (using a call to an init method in the AlgorithmParameterGenerator engine class), each provider must supply and document a default initialization. For example, the "IBMJCE" provider uses a default prime modulus size (keysize) of 1024 bits for the generation of Diffie-Hellman parameters.

Step 9: Prepare for Production

Step 9a (only for providers that can be exported): Apply for U.S. Government Export Approval

Provider vendors whose providers may be exported outside the U.S. and Canada should apply to the Bureau of Export Administration in the U.S. Department of Commerce for export approval. Consult your export counsel for more information.

The following URLs might be of use to you:

Step 9b: Get a Code-Signing Certificate for Production

Below are the steps you should use to get a code-signing certificate for production. Note that they are basically the same as the steps used to get a code-signing certificate for testing (Step 5a), except that the certificate you receive for production will be valid for a longer than the temporary certificate you received for testing. Before you will be issued a code-signing certificate for production you will need to either show proof of export approval or include a notarized statement that your provider will be distributed only inside the U.S. and Canada.
  1. Use keytool to generate a DSA keypair.
  2.  keytool -genkey -alias <prAlias> -keyalg DSA -keysize 1024
    -dname "cn=<Company Name>,ou=JCE Code Signing CA,o=IBM Corporation"
    -keystore <keystore file name>
    -storepass <keystore password>
    (Note: This command must be typed as a single line. Multiple lines and indentation are used in the examples just for legibility purposes.)

    This command will generate a DSA keypair (a public key and an associated private key) and store it in an entry in the specified keystore. The public key is stored in a self-signed certificate. The keystore entry can subsequently be accessed using the alias specified in <prAlias>.

    As mentioned in the corresponding step for obtaining a code-signing certificate for testing (Step 5a), the option values in angle brackets ("<" & ">") represent the actual values that must be supplied. Also, if command lines you type are not allowed to be as long as the keytool -genkey command you want to execute, you can create and execute a plain-text batch file containing the command.

  3. Use keytool to generate a certificate signing request.
  4. keytool -certreq -alias <prAlias> -sigalg DSA 
    -file <csr file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    Here, <prAlias> is the alias for the DSA keypair entry created in the previous step. This command generates a Certificate Signing Request (CSR), using the PKCS#10 format. It stores the CSR in the file whose name is specified in <csr file name>.
  5. Send the CSR, contact information, and proof of export approval or domestic-only certification to the JCE Code Signing Certification Authority.

  6. Send, using email, the CSR and contact information to javasec@us.ibm.com.

    Put the following text in the Subject line of your e-mail message:

     Request a Certificate for Signing a JCE Provider (Production)
    Put the contact information in the body of the message and send the CSR file as a plain text attachment to the message. If your mail tool has an option for specifying the encoding format to be used for attachments, select the "MIME" option. Note: The CSR file is just a plain text file, in Base 64 encoding. Only the first and last lines are human-readable.

    Include the following contact information in the body of your message:

    Company Name
    Street Address (Not a post office box)
    City
    State/Province
    Country
    Company Telephone Number
    Company Fax Number
    Company Home Page URL
    Requester Name
    Requester Telephone Number
    Requester Email Address
    Brief description of your company (size, line of business, etc.)
    After the JCE Code Signing Certification Authority has received your e-mail message, it will send you a request number, also using email. After receiving this request number, mail required documents to the address specified below. The documents you need to send depend on whether or not the provider can be exported outside the U.S. and Canada.

    • If the provider can be exported, mail a copy of your proof of export approval received from the U.S. government in Step 9a.
    • If the provider will not be exported, mail a notarized letter stating that the provider will be distributed only inside the U.S. and Canada.
    In both cases, the documents should be mailed to the address below and you should include in your mailing a note indicating the request number so that your hardcopy mailing can be matched to your e-mail message containing the CSR and contact information. The documents and request number should be mailed to
    Corporate Export
    Attn: Encryption export
    901 San Antonio Road, UPAL01-541
    Palo Alto, CA 94303
    After the JCE Code Signing Certification Authority has received both your email message and either the proof of export approval or domestic-only certification, it will authenticate you, the requester. Then it will create and sign a code-signing certificate for production, valid for 5 years. It will send you an email message containing two plain-text file attachments: one file containing this code-signing certificate for production and another file containing its own CA certificate, which authenticates its public key.

  7. Use keytool to import the certificates received from the CA.

  8. After you have received the two certificates from the JCE Code Signing Certification Authority, you can use keytool to import them into your keystore.

    If you are using the same keystore as that used for testing, you will already have imported the CA certificate as a "trusted certificate" in the fourth substep of Step 5a: Get a Code-Signing Certificate for Testing, so you don't need to do that again.

    If you are using a different keystore, you need to import the CA certificate into your keystore as a "trusted certificate":

    keytool -import -alias <alias for the CA cert> 
    -file <CA cert file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    In any case, then you should import the code-signing certificate:
    keytool -import -alias <prAlias> 
    -file <code-signing cert file name>
    -keystore <keystore file name>
    -storepass <keystore password>
    Here, <prAlias> is the same alias as that which you created in step 1 where you generated a DSA keypair. This command replaces the self-signed certificate in the keystore entry specified by <prAlias> with the one signed by the JCE Code Signing Certification Authority.
Now that you have in your keystore a code-signing certificate for production from an entity trusted by JCE (the JCE Code Signing Certification Authority), you can place your provider code in a JAR file (Step 9c) and then use that certificate to sign the JAR file (Step 9d).

Step 9c: Place Your Provider in a New JAR File

Create a new JAR file containing the provider code, to be signed in the next step using the official code-signing certificate.
jar cvf <JAR file name> <list of classes, separated by spaces>
This command creates a JAR file with the specified name containing the specified classes.

For efficiency reasons, it is best to create this new JAR file rather than simply adding the official production signature to the JAR file created in Step 5b that was signed using the testing certificate obtained in Step 5a. If the JAR file used in production still contains signatures generated by the test certificate, JCE might waste time trying to verify those signatures.

Step 9d: Sign Your Provider for Production

Sign the JAR file created in the previous step with the code-signing certificate obtained in Step 9b.
jarsigner -keystore <keystore file name> 
-storepass <keystore password>
<JAR file name> <prAlias>
Here, <prAlias> is the alias into the keystore for the entry containing the code-signing certificate for production received from the JCE Code Signing Certification Authority (the same alias as that specified in the commands in Step 9b).

You can test verification of the signature using the following command:

jarsigner -verify <JAR file name>
The text "jar verified" will be displayed if the verification was successful.

Step 10: Run Your Test Programs Again

You should have thoroughly tested your provider in Step 7. However, we suggest that you run your test programs again to make sure that the provider works correctly because what you tested in Step 7 is signed by a different certificate.

Step 11: Make Your Provider Software and Documentation Available to Clients

The final step is to make your provider software and documentation available to your customers.

How a Provider Can Do Self-Integrity Checking

Each provider should do self-integrity checking to ensure that the JAR file containing its code has not been tampered with, for example in an attempt to invoke provider methods directly rather than through JCE.

Integrity checking takes place when the JCE framework tries to instantiate a provider's implementation of a JCE cryptographic service (not when the provider is registered). That way, providers with implementations of cryptographic services defined in both J2SE and JCE (for example, providers with an implementation of java.security.SignatureSpi for the "DSA" algorithm and an implementation of javax.crypto.CipherSpi for "Blowfish") will be usable in the J2SE environment without having to engage in authentication. Only those cryptographic services related to JCE will have to perform self-checking, and will become usable (in the JCE environment) only after such checking has taken place.

Providers that provide implementations for JCE services must be digitally signed with a certificate that is issued by "trusted" Certification Authorities. Currently, the following two Certification Authorities are considered "trusted":

  • IBM JCE Code Signing CA, and
  • Sun Microsystems' JCE Code Signing CA.
Refer to Step 5a (for testing) and Step 9b (for production) for detailed information about how to get a code-signing certificate from the IBM JCE Code Signing CA and the certificate of that CA.

The basic approach that a provider can use to check its own integrity is:

  1. Determine the URL of the JAR file containing the provider code, and

  2. Verify the JAR file's digital signatures to ensure that at least one signer of each entry of the JAR file is trusted.

These steps and their substeps are described in the following sections:

Finding the Provider JAR FileVerifying the Provider JAR FileNotes on the Sample Code

Finding the Provider JAR File

Determining the Provider's JAR File URL

The URL for the provider's JAR file can be obtained by determining the provider's CodeSource and then calling the getLocation method on the CodeSource.

URL providerURL = (URL) AccessController.doPrivileged(
new PrivilegedAction) {
public Object run() {
CodeSource cs = MyProvider.class.getProtectionDomain().
getCodeSource();
return cs.getLocation();
}
});

Creating a JarFile Referring to the JAR File

After you have the URL for the provider's JAR file, you can create a java.util.jar.JarFile that refers to the JAR file. This instance is needed in the step for verifying the Provider JAR file.

To create the JAR file, first open a connection to the specified URL by calling its openConnection method. Because the URL is a JAR URL, the type is java.net.JarURLConnection. Here's the basic code:

// Prep the url with the appropriate protocol.
jarURL =
url.getProtocol().equalsIgnoreCase("jar") ?
url :
new URL("jar:" + url.toString() + "!/");
// Retrieve the jar file using JarURLConnection
JarFile jf = (JarFile) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
JarURLConnection conn =
(JarURLConnection) jarURL.openConnection();

...
Now that you have a JarURLConnection, you can call its getJarFile method to get the JAR file:
// Always get a fresh copy, so we don't have to
// worry about the stale file handle when the
// cached jar is closed by some other application.
conn.setUseCaches(false);
jf = conn.getJarFile();

Verifying the Provider JAR File: Basics

After you have determined the URL for your provider JAR file and you have created a JarFile that refers to the JAR file, as shown in the steps above, you can then verify the file.

The basic approach is:

  1. Ensure that at least one of each entry's signer certificates is equal to the provider's own code signing certificate.

  2. Go through all the entries in the JAR file and ensure that the signature on each one verifies correctly.

  3. Ensure that at least one of each entry's signer certificates can be traced back to a trusted Certification Authority.

Sample code for each of these steps is presented and described in the following sections:

Verification Setup
JAR File Signature Check
Verifying Signatures
Ensuring Signers Are Trusted

Verification Setup

The approach in this example is to define a class JarVerifier to handle the retrieval of a JAR file from a given URL and verify whether the JAR file is signed with the specified certificate.

The constructor of JarVerifier takes the provider URL as a parameter, which will be used to retrieve the JAR file later.

The actual jar verification is implemented in the verify method, which takes the provider code signing certificate as a parameter.

public void verify(X509Certificate targetCert) 
throws IOException {
// variable 'jarFile' is a JarFile object created
// from the provider's Jar URL.
...
Vector entriesVec = new Vector();
Basically the verify method will go through the JAR file entries twice: the first time checking the signature on each entry and the second time verifying that the signer is trusted.

Note: In these code snippets, the jarFile variable is the JarFile object of the provider's jar file.

JAR File Signature Check

An authentic provider JAR file is signed. If the JAR file is not signed, it has been tempered with:

// Ensure the jar file is signed.
Manifest man = jarFile.getManifest();
if (man == null) {
throw new SecurityException("The provider is not signed");
}

Verifying Signatures

The next step is to go through all the entries in the JAR file and ensure that the signature on each one verifies correctly. One possible way to verify the signature on a JAR file entry is to simply read the file. If a JAR file is signed, the read method itself automatically performs the signature verification. Here is sample code:

// Ensure all the entries' signatures verify correctly
byte[] buffer = new byte[8192];
Enumeration entries = jarFile.entries();

while (entries.hasMoreElements()) {
JarEntry je = (JarEntry) entries.nextElement();

// Skip directories.
if (je.isDirectory()) continue;
entriesVec.addElement(je);
InputStream is = jarFile.getInputStream(je);

// Read in each jar entry. A security exception will
// be thrown if a signature/digest check fails.
int n;
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
// Don't care
}
is.close();
}

Ensuring Signers Are Trusted

The code in the previous section verified the signatures of all the provider JAR file entries. The fact that they all verify correctly is a requirement, but it is not sufficient to verify the authenticity of the JAR file. A final requirement is that the signatures were generated by the same entity as the one that developed this provider. To test that the signatures are trusted, we can again go through each entry in the JAR file (this time using the entriesVec built in the previous step), and for each entry that must be signed (that is, each entry that is not a directory and that is not in the META-INF directory):

  1. Get the list of signer certificates for the entry.
  2. Identify each of the certificate chains and determine whether any of the certificate chains are trusted. At least one of the certificate chains must be trusted.
The loop setup is the following:
Enumeration e = entriesVec.elements();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
...
}

Getting the List of Certificates

The certificates for the signers of a JAR file entry JarEntry can be obtained simply by calling the JarEntry getCertificates method:

Certificate[] certs = je.getCertificates();

Adding this line of code to the previous loop setup code, and adding code to ignore directories and files in the META-INF directory results in:

while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();

// Every file must be signed except files in META-INF.
Certificate[] certs = je.getCertificates();
if ((certs == null) || (certs.length == 0)) {
if (!je.getName().startsWith("META-INF"))
throw new SecurityException("The provider " +
"has unsigned " +
"class files.");
} else {
// Check whether the file is signed by the expected
// signer. The jar may be signed by multiple signers.
// See if one of the signers is 'targetCert'.
...
}
...

Identifying Each of the Signers and Determining If One is Trusted

The certificate array returned by the JarEntry getCertificates method contains one or more certificate chains. There is one chain per signer of the entry. Each chain contains one or more certificates. Each certificate in a chain authenticates the public key in the previous certificate.

The first certificate in a chain is the signer's certificate, which contains the public key corresponding to the private key that was actually used to sign the entry. Each subsequent certificate is a certificate for the issuer of the previous certificate. Because the self-integrity check is based on whether the JAR file is signed with the provider's signing cert, the trust decision will be made upon only the first certificate, the signer's certificate.

Next to go through the array of certificate chains and check each chain and the associated signers until you find a trusted entity. For each JAR file entry, at least one of the signers must be trusted. A signer is considered "trusted" if and only if its certificate is equals to the embedded provider signing certificate.

The following sample code loops through all the certificate chains, compares the first certificate in a chain to the embedded provider signing certificate, and only returns true if a match is found.

int startIndex = 0;
X509Certificate[] certChain;
boolean signedAsExpected = false;

while ((certChain = getAChain(certs, startIndex)) != null) {
if (certChain[0].equals(targetCert)) {
// Stop since one trusted signer is found.
signedAsExpected = true;
break;
}
// Proceed to the next chain.
startIndex += certChain.length;
}

if (!signedAsExpected) {
throw new SecurityException("The provider " +
"is not signed by a " +
"trusted signer");
}
The getAChain method is defined as follows:
/**
* Extracts ONE certificate chain from the specified certificate array
* which may contain multiple certificate chains, starting from index
* 'startIndex'.
*/
private static X509Certificate[] getAChain(Certificate[] certs,
int startIndex) {
if (startIndex > certs.length - 1)
return null;

int i;
// Keep going until the next certificate is not the
// issuer of this certificate.
for (i = startIndex; i < certs.length - 1; i++) {
if (!((X509Certificate)certs[i + 1]).getSubjectDN().
equals(((X509Certificate)certs[i]).getIssuerDN())) {
break;
}
}

// Construct and return the found certificate chain.
int certChainSize = (i-startIndex) + 1;
X509Certificate[] ret = new X509Certificate[certChainSize];
for (int j = 0; j < certChainSize; j++ ) {
ret[j] = (X509Certificate) certs[startIndex + j];
}
return ret;
}

Notes on the Sample Code

The sample code, MyProvider.java, is a sample provider that has a method selfIntegrityChecking, which performs self-integrity checking. It first determines the URL of its own provider JAR file and then verifies that the provider JAR file is signed with the embedded code-signing certificate.

Note: The method selfIntegrityChecking should be called by all the constructors of its cryptographic engine classes to ensure that its integrity is not compromised.

Provider MyProvider performs self-integrity checking in the following steps:

  1. Determine the URL to access the provider JAR file using its own class, MyProvider.class.

  2. Instantiate a JarVerifier object with the provider URL in Step 1.

  3. Create a X509Certificate object from the embedded byte array bytesOfProviderCert.

  4. Call the JarVerifier.verify method to verify that all entries in the provider JAR file are signed and that they are signed with the same certificate that was instantiated in Step 3.
Note: The class JarVerifier will retrieve the JAR file from the given URL and make sure that the JAR file is signed, all entries have valid signatures, and all entries are signed with the specified X509Certificate.

A security exception is thrown by JarVerifier.verify in several cases:

  • The certificate passed to verify is null (invalid).
  • When unable to retrieve the JAR file from the given URL.
  • The provider is not signed. (The jar has no manifest.)
  • The provider has unsigned class files.
  • The provider is not signed with the specified certificate.

The MyProvider.java sample code is comprised of the code snippets shown above. In addition, it includes error handling, sample code signing certificate bytes, and code for instantiating a X509Certificate object from the embedded sample code signing certificate bytes.

Regarding the use of AccessController.doPrivileged, see Link to external Web siteAPI For Privileged Blocks for information on the use of doPrivileged.

How a Provider Authenticates the Framework (JCE 1.2.1 only)

JCE 1.2.1 was an optional extension to Java 2 v 1.3 and as such the JCE framework was packaged in a separate jar file that was digitally signed. Providers that provide implementations for JCE services, which need to work with JCE 1.2.1, need to authenticate that the JCE framework is valid and has not been tampered with.

Each SPI implementation class, in addition to performing self-integrity chekcing must authenticate the JCE framework in its constructor, by:

  1. Determining the codebase (URL) of the JCE JAR file and
  2. Verifying its digital signature
These steps and their substeps are described below. For each, initially simplified sample basic code is provided, followed by a complete coding example. Here is an outline for the sections:

Finding the framework JAR FileComplete Example

Verifying the framework JAR FileComplete Example

Finding the framework JAR File

The basic idea for a sample method to determine the URL for the JCE framework is the following: An authentic JCE framework must contain the javax.crypto.Cipher class, you can find the URL for that class and extract the subpart of that URL which identifies the JAR file that the class is in. This JAR file is also the JAR file for the JCE framework.

Finding the Cipher Class

To find the URL for the Cipher class, you begin with what you know about the current class (the SPI implementation class):
Class c = this.getClass();
From the current class you can determine the class loader for the class:
ClassLoader cl = c.getClassLoader();
You can then call that class loader's getResource method to find the URL for Cipher.class:
URL url = cl.getResource("javax/crypto/Cipher.class");
This method works because the JCE framework is always deployed as an installed extension, while the provider can be either installed or bundled. The "javax/crypto/Cipher.class" resource will have been loaded either by the same class loader as the provider (if the provider is installed) or by the delegation parent of the provider's class loader (if the provider is bundled). In either case, the provider's class loader can always find the "javax/crypto/Cipher.class" resource, if the provider has sufficient permissions.

IMPORTANT NOTE: If you want your provider to work both with JCE 1.2.1 and with the JCE in the Java 2 SDK, v 1.4, then you will need to add a conditional statement. This way the provider code to authenticate the JCE framework is executed only when the provider is run with JCE 1.2.1. The following is sample code:

Class cipherCls = Class.forName("javax.crypto.Cipher");
CodeSource cs =
cipherCls.getProtectionDomain().getCodeSource();
if (cs != null) {
// Authenticate JCE framework
. . .
}

Extracting the JAR URL

The syntax of a JAR URL is:
jar:<URL_for_jar_file>!/<entry>
Therefore, the URL returned by the getResource call should be in the following format:
jar:<URL_for_jce_jar_file>!/javax/crypto/Cipher.class
The URL returned by getResource is the URL for one entry in the JCE framework JAR file. What we really need is the URL for the whole JAR file, which is the full string preceding javax/crypto/Cipher.class, that is the substring from "jar:" through "!/", inclusive. Suppose slash is the index of the "/" character at the end of the URL for the full JAR file. Then you can extract the JAR file URL using the following code:
URL jceJarURL = new URL(url.toString().substring(0, 
slash + 1));
(Recall that the substring method returns the substring beginning at the index specified by its first parameter and ending at the index specified by its second parameter minus 1.)

The URL for the framework should have the protocol "file" because it is expected to be deployed as an installed extension. The complete coding example for finding the JCE framework JAR file will show how to ensure this is the case.

Creating a JarFile that refers to the JAR File

After you have the URL for the JCE JAR file, you can create a java.util.jar.JarFile that refers to the JAR file. This file is needed in the step for verifying the framework JAR file. To create a JarFile, open a connection to the specified URL by calling its openConnection method. Because the URL is a JAR URL, the result is a java.net.JarURLConnection:
JarURLConnection jc = 
(JarURLConnection)jceJarURL.openConnection();
Now that you have a JarURLConnection, you can call its getJarFile method to get the JAR file:
JarFile jf = (JarFile)jc.getJarFile();

Complete Example

The above code is just the basic code required to determine the framework's codebase (JAR File URL). In reality, there are additional coding requirements that are briefly described here and that are included in the complete example below.

A SecurityException should be thrown if anything is not as it should be, for example if:

  • The Cipher class cannot be found.
  • The URL returned for the Cipher class is not in the proper format.
  • The URL for JCE does not have the protocol "file".
Below is a complete example of determining the URL of the JCE JAR file. It includes all the basic code described above, plus further details such as error handling and use of AccessController.doPrivileged where needed. (See Link to external Web siteAPI For Privileged Blocks for information on the use of doPrivileged.) Be sure to substitute your provider name for all occurrences of myProvider.
// For efficiency, keep track of whether or not the JCE 
// has already been verified to avoid doing it
// multiple times unnecessarily.
private static boolean verifiedJce = false;

private static final synchronized void doVerifyJceJar()
{
// If the JCE has already previously been verified, just return.
// Otherwise, verify the JCE.
if (verifiedJce) {
return;
}

// Find out the URL for the JCE framework.
URL jceJarURL = null;
try {
Class c = this.getClass();
final ClassLoader cl = c.getClassLoader();

// An authentic JCE framework must
// contain the javax.crypto.Cipher class. So we can
// rely on it to find out the URL for the JCE
// JAR file.
// As explained in the JCE API Specification &
// Reference, the JCE framework is always deployed as an
// installed extension. The provider can be either
// installed or bundled. So the provider will always be
// able to determine the "javax/crypto/Cipher.class"
// resource (provided it has sufficient permissions),
// because that resource will have been loaded by
// the same classloader as the provider (if the
// provider is installed) or its delegation parent
// (if the provider is bundled).
URL url = (URL)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return cl.getResource("javax/crypto/Cipher.class");
}
});

if (url == null) {
throw new SecurityException("Cannot get the JCE framework " +
"URL. Check that this provider can " +
"read the JCE framework");
}

// The URL for "javax/crypto/Cipher.class" should be in
// the following format:
// jar:<URL_for_jce_jar_file>!/javax/crypto/Cipher.class

String urlStr = url.toString();

// Determine the location of the slash at the end of the
// JAR specification.
// First, get index of period in last occurrence of ".jar!/"
int per = urlStr.lastIndexOf(".jar!/);
if per = -1 {
// No such substring was found
throw new SecurityException(
"The JCE framework is invalid");
}
// Get index of the slash at the end of ".jar!/"
int slash = per + 5;

// Determine the full JAR URL
jceJarURL = new URL(urlStr.substring(0, slash + 1));

// The URL for JCE should have the protocol "file"
// since we expect JCE to be deployed as an installed
// extension. Ensure this is the case.
// Skip the "jar:" in the beginning.
int beginIndex = 4;

URL jceURL =
new URL(urlStr.substring(beginIndex, slash - 1));
if (!jceURL.getProtocol().equalsIgnoreCase("file")) {
throw new SecurityException("JCE should be deployed " +
"as an installed extension");
}
} catch (IOException ioe) {
throw new SecurityException("The provider myProvider cannot " +
"authenticate the JCE framework" + ioe);
}

// Read the JCE framework JAR file.
JarFile jf;

try {
final URL url = jceJarURL;
jf = (JarFile)AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return ((JarURLConnection)
url.openConnection()).getJarFile();
}
});
} catch (java.security.PrivilegedActionException pae) {
throw new SecurityException("Cannot authenticate " +
"the JCE framework " + pae);
}

try {
verifySingleJarFile(jf); // see next section
} catch (Exception e) {
throw new SecurityException("Cannot authenticate " +
"JCE framework " + e);
}

verifiedJce = true;
}

Verifying the JCE JAR File

After you have determined the URL for the JCE JAR file and you have created a JarFile that refers to the JAR file, as shown in the Finding the JCE JAR File: Complete Example, you can then verify the file.

The basic approach is:

  1. Ensure that the JAR file is a signed JAR file,
  2. Go through all the entries in the JAR file and ensure that the signature on each one can be verified correctly, and
  3. Ensure at least one of each entry's signer's certificates can be traced back to a trusted Certification Authority.
Sample code for each of these steps is presented and described below, followed by the complete code example. Here is an outline for the sections;

Verification Setup
JAR File Signature Check
Verifying Signatures
Ensuring Signers Are Trusted

Verification Setup

This example will define a method verifySingleJarFile that takes as a parameter the JarFile created in the previous step.

verifySingleJarFile will basically go through the JAR file entries twice. As an efficiency measure, it will allocate a Vector entriesVec and the first time through the loop processing of the JAR file entries, it will add each entry to entriesVec, for use by the second loop. Here is the first part of our method:

private static void verifySingleJarFile(JarFile jf)
throws IOException, CertificateException {
Vector entriesVec = new Vector();

JAR File Signature Check

An authentic JCE framework JAR file is signed. If the JAR file is not signed, it has been tampered with:
 Manifest man = jf.getManifest();
if (man == null)
throw new SecurityException(
"The JCE framework is not signed");

Verifying Signatures

The next step is to go through all the entries in the JAR file and ensure the signature on each one verifies correctly. One possible way to verify the signature on a JAR file entry is to simply read the file. If a JAR file is signed, the read method itself automatically performs the signature verification. Here is sample code:
 byte[] buffer = new byte[8192];
Enumeration entries = jf.entries();

while (entries.hasMoreElements()) {
JarEntry je = (JarEntry)entries.nextElement();
entriesVec.addElement(je);
InputStream is = jf.getInputStream(je);
int n;
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
is.close();
}
jf.close();

Ensuring Signers Are Trusted

The code in the previous section verified the signatures of all the JCE framework JAR file entries. The fact that they all were verified correctly is a requirement, but it is not sufficient to verify the authenticity of the JAR file. A final requirement is that the signatures were generated by an entity that JCE trusts. In order to test that, you can again go through each entry in the JAR file (this time using the entriesVec built in the previous step), and for each entry that must be signed (that is, each entry that is not a directory and that is not in the META-INF directory):
  1. Get the list of signer certificates for the entry.
  2. Determine the roots of the signer certificate chains.
  3. Determine whether any of the root certificates is trusted. At least one of the signers must be trusted.
The loop setup is the following:
 Enumeration e = entriesVec.elements();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();

Getting the List of Signer Certificates

The certificates for the signers of a JAR file entry JarEntry can be obtained simply by calling the JarEntry getCertificates method:
 Certificate[] certs = je.getCertificates();
Adding this to the previous loop setup code, and adding code to ignore directories and files in the META-INF directory results in:
Enumeration e = entriesVec.elements();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();

if (je.isDirectory())
continue;
// Every file must be signed - except
// files in META-INF
Certificate[] certs = je.getCertificates();
if ((certs == null) || (certs.length == 0)) {
if (!je.getName().startsWith("META-INF"))
throw new SecurityException("The JCE framework " +
"has unsigned " +
"class files.");
} else {
// Check whether the file
// is signed as expected.
. . .
}

Determining the Roots of the Signer Certificate Chains

The certificate array returned by the JarEntry getCertificates method contains one or more certificate chains. There is one chain per signer of the entry. Each chain contains one or more certificates. Each certificate in a chain authenticates the public key in the previous certificate. The first certificate in a chain is the certificate that contains the public key that corresponds to the private key actually used to sign the entry. Each subsequent certificate is a certificate for the entity who signed the previous certificate. The last certificate in a chain is either:
  • The certificate for a Certification Authority, or
  • A certificate issued by a Certification Authority
We need to go through the array of certificate chains to determine the final certificate in each chain, referred to as the "root" certificate:
Certificate[] chainRoots = getChainRoots(certs);
The getChainRoots method is defined as follows:
private static Certificate[] 
getChainRoots(Certificate[] certs) {
Vector result = new Vector(3);
// choose a Vector size that seems reasonable
for (int i = 0; i < certs.length - 1; i++) {
if (!((X509Certificate)certs[i + 1]).getSubjectDN().equals(
((X509Certificate)certs[i]).getIssuerDN())) {
// We've reached the end of a chain
result.addElement(certs[i]);
}
}
// The final entry in the certs array is always
// a "root" certificate
result.addElement(certs[certs.length - 1]);
Certificate[] ret = new Certificate[result.size()];
result.copyInto(ret);

return ret;
}

Determining whether any one of the Root Certificates is Trusted

Now that you have (in the chainRoots array) the list of root certificates for all the signers of a JCE framework JAR file entry, you can go through that array and determine whether any one of the root certificates is a certificate for a "trusted" entity. At least one of the root certificates for each JAR file entry must be trusted. Assume that trustedCaCerts is an array of certificates for trusted Certificate Authorities. Sample code is the following:
boolean signedAsExpected = false;

for (int i = 0; i < chainRoots.length; i++) {
if (isTrusted((X509Certificate)chainRoots[i],
trustedCaCerts)) {
signedAsExpected = true;
break;
}
}

if (!signedAsExpected) {
throw new SecurityException("The JCE framework " +
"is not signed by a trusted signer");
}
A root certificate is considered "trusted" if one of the following is true:
  • It is the certificate for a trusted Certification Authority. (In the following sample code, this is true if it is the same as a certificate in the trustedCaCerts array.)
  • It is a certificate issued by a trusted Certification Authority. This is true if the certificate's IssuerDN is the same as the SubjectDN of one of the trustedCaCerts certificates and you can verify the signature. (The IssuerDN of a certificate is the name of the entity that signed the certificate, while the SubjectDN identifies the entity whose public key is being identified by the certificate.)
Here is sample code:
private static boolean isTrusted(X509Certificate cert, 
X509Certificate[] trustedCaCerts)
{
// Return true iff either of the following is true:
// 1) the cert is in the trustedCaCerts.
// 2) the cert is issued by a trusted CA.

// Check whether the cert is in the trustedCaCerts
for (int i = 0; i < trustedCaCerts.length; i++) {
// If the cert has the same SubjectDN
// as a trusted CA, check whether
// the two certs are the same.
if (cert.getSubjectDN().equals(
trustedCaCerts[i].getSubjectDN())) {
if (cert.equals(trustedCaCerts[i])) {
return true;
}
}
}

// Check whether the cert is issued by a trusted CA.
// Signature verification is expensive. So we check
// whether the cert is issued
// by one of the trusted CAs iff the above loop failed.
for (int i = 0; i < trustedCaCerts.length; i++) {
// If the issuer of the cert has the same name as
// a trusted CA, check whether that trusted CA
// actually issued the cert.
if (cert.getIssuerDN().equals(
trustedCaCerts[i].getSubjectDN())) {
try {
cert.verify(trustedCaCerts[i].getPublicKey());
return true;
} catch (Exception e) {
// Do nothing.
}
}
}

return false;
}

Complete Example

Below is the complete code for verifying the JCE JAR file. It assumes the parameter jf refers to a JarFile that is open (and thus needs a close). It also assumes trustedCaCerts is the array of Certificates for trusted Certificate Authorities.
private static void verifySingleJarFile(JarFile jf)
throws IOException, CertificateException {
Vector entriesVec = new Vector();

// Ensure there is a manifest file
Manifest man = jf.getManifest();
if (man == null)
throw new SecurityException(
"The JCE framework is not signed");

// Ensure all the entries' signatures verify correctly
byte[] buffer = new byte[8192];
Enumeration entries = jf.entries();

while (entries.hasMoreElements()) {
JarEntry je = (JarEntry)entries.nextElement();
entriesVec.addElement(je);
InputStream is = jf.getInputStream(je);
int n;
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
is.close();
}
jf.close();

// Get the list of signer certificates
Enumeration e = entriesVec.elements();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();

if (je.isDirectory())
continue;
// Every file must be signed - except
// files in META-INF
Certificate[] certs = je.getCertificates();
if ((certs == null) || (certs.length == 0)) {
if (!je.getName().startsWith("META-INF"))
throw new SecurityException("The JCE framework " +
"has unsigned " +
"class files.");
} else {
// Check whether the file
// is signed as expected.
// The framework may be signed by
// multiple signers. At least one of
// the signers must be a trusted signer.

// First, determine the roots of the certificate chains
Certificate[] chainRoots = getChainRoots(certs);
boolean signedAsExpected = false;

for (int i = 0; i < chainRoots.length; i++) {
if (isTrusted((X509Certificate)chainRoots[i],
trustedCaCerts)) {
signedAsExpected = true;
break;
}
}

if (!signedAsExpected) {
throw new SecurityException("The JCE framework " +
"is not signed by a " +
"trusted signer");
}
}
}
}

private static boolean isTrusted(X509Certificate cert,
X509Certificate[] trustedCaCerts)
{
// Return true iff either of the following is true:
// 1) the cert is in the trustedCaCerts.
// 2) the cert is issued by a trusted CA.

// Check whether the cert is in the trustedCaCerts
for (int i = 0; i < trustedCaCerts.length; i++) {
// If the cert has the same SubjectDN
// as a trusted CA, check whether
// the two certs are the same.
if (cert.getSubjectDN().equals(
trustedCaCerts[i].getSubjectDN())) {
if (cert.equals(trustedCaCerts[i])) {
return true;
}
}
}

// Check whether the cert is issued by a trusted CA.
// Signature verification is expensive. So we check
// whether the cert is issued
// by one of the trusted CAs iff the above loop failed.
for (int i = 0; i < trustedCaCerts.length; i++) {
// If the issuer of the cert has the same name as
// a trusted CA, check whether that trusted CA
// actually issued the cert.
if (cert.getIssuerDN().equals(
trustedCaCerts[i].getSubjectDN())) {
try {
cert.verify(trustedCaCerts[i].getPublicKey());
return true;
} catch (Exception e) {
// Do nothing.
}
}
}

return false;
}

private static Certificate[]
getChainRoots(Certificate[] certs) {
Vector result = new Vector(3);
// choose a Vector size that seems reasonable
for (int i = 0; i < certs.length - 1; i++) {
if (!((X509Certificate)certs[i + 1]).getSubjectDN().equals(
((X509Certificate)certs[i]).getIssuerDN())) {
// We've reached the end of a chain
result.addElement(certs[i]);
}
}
// The final entry in the certs array is always
// a "root" certificate
result.addElement(certs[certs.length - 1]);
Certificate[] ret = new Certificate[result.size()];
result.copyInto(ret);

return ret;
}

Further Implementation Details and Requirements

Algorithm Aliases

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

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

JCE uses the same aliasing scheme for algorithm names as Java 2 SDK v 1.2. That scheme enables clients to use aliases when referring to algorithms, rather than their standard names. For example, the "IBMJCE" provider's master class (IBMJCE.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", "IBMJCE");

KeyAgreement ka = KeyAgreement.getInstance("DH", "IBMJCE");
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 Cipher, KeyAgreement, KeyGenerator, Mac, SecretKeyFactory, or ExemptionMechanism, and aliasName is your alias name. For all but ExemptionMechanism, the value of the property must be the standard algorithm name for the algorithm being aliased. For ExemptionMechanism, the value must be the exemption mechanism name ("KeyRecovery", "KeyEscrow", or "KeyWeakening").

As an example, the "IBMJCE" 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 using the following:

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

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 "IBMJCE" provider that is included with every Java 2 v1.4 installation. For example, if you are implementing a PBE algorithm that requires a message digest algorithm, you can obtain an instance of a class that is implementing the MD5 message digest algorithm by calling
  3.  MessageDigest.getInstance("MD5", "IBMJCE")
  4. Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by another specific provider. This method is appropriate only if you are sure that all clients who will use your provider will also have the other provider installed.
  5. 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
  6. MessageDigest.getInstance("MD5")
    This method is appropriate only 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 "IBMJCE" provider uses a default modulus size (keysize) of 1024 bits for the generation of Diffie-Hellman parameters.

Diffie-Hellman Interfaces and Their Required Implementations

JCE 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 that implements 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.

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, for example, 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.

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, because DHPrivateKey extends DHKey.
  • The getAlgorithm, getEncoded, and getFormat methods from the Link to external Web sitejava.security.Key interface, because 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 Link to external Web sitejava.security.Key interface, because 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 (for example, DHParameterSpec defines getP, getG, and getL methods, to access the p, g, and l parameters, respectively).

This representation 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 get only the name of the algorithm associated with the parameter set (using getAlgorithm) and some kind of encoding for the parameter set (using getEncoded).

If you supply an AlgorithmParametersSpi, AlgorithmParameterGeneratorSpi, or KeyPairGeneratorSpi implementation, you must utilize the AlgorithmParameterSpec interface, because each of those classes contains 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 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, you will need to supply your own AlgorithmParameterSpec implementation appropriate for that type of algorithm.

JCE 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 "IBMJCE" 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 "IBMJCE" 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 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 Link to external Web siteKeySpec 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 Link to external Web siteKeySpec 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 Link to external Web siteKeySpec 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 Link to external Web siteKeySpec 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 Link to external Web siteKeySpec interface. Because it also implements the SecretKey interface, it can be used to construct a SecretKey object in a provider-independent fashion, that is, 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 can 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.

Ensuring Exportability

The key feature of the JCE release is the exportability of the JCE framework and of the provider cryptography implementations if certain conditions are met.

As noted elsewhere, you can write just one version of your provider software, implementing cryptography of maximum strength. It is up to JCE framework, not your provider, to enforce restrictions regarding the cryptographic algorithms and maximum cryptographic strengths available to applets or applications in different locations.

The conditions that must be met by your provider in order to enable it to be plugged into JCE are the following:

  • The constructor of each SPI implementation class should do self-integrity checking, as described in How a Provider Can Do Self-Integrity Checking.
  • The provider code should be written in such a way that provider classes become unusable if instantiated by an application directly, bypassing JCE framework. See Step 1: Write Your Service Implementation Code in the Steps to Implement and Integrate a Provider section.
  • The provider package must be signed by an entity that is trusted by JCE. Providers that can be exported first need to apply for U.S. government export approval. See Step 9a through Step 9d.

How to Implement an ExemptionMechanism

The steps required in order to implement an exemption mechanism provider and integrate it into Java Security are;

Step 1: Write your Exemption Mechanism Service Implementation Code
Step 2: Give your Exemption Mechanism Provider a Name
Step 3: Write your "Master Class", a subclass of Provider
Step 4: Compile your Code
Step 5: Sign your Exemption Mechanism Provider for Testing
Step 6: Prepare for Testing: Install the Exemption Mechanism ProviderStep 7: Write and Compile your Test Programs
Step 8: Run your Test Programs
Step 9: Document your Exemption Mechanism Provider and its Supported Services
Step 10: Attach the cryptoPerms to your provider
Step 11: Sign your Exemption Mechanism Provider for Production
Step 12: Run your Test Programs Again
Step 13: Make your Exemption Mechanism Provider Software and Documentation Available to Clients

Step 1: Write your Exemption Mechanism Service Implementation Code

Write the code that supplys the algorithm-specific implementations of the exemption mechanism services that you want to support.

For each exemption mechanism service in JCE, you need to create a subclass of the exemption mechanism SPI class. (See "JCE 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 that there is a public constructor without any arguments. This step is needed because when one of your services is requested, Java Security looks up the subclass that is implementing that service, as specified by a property in your "master class" (see Step 3). Java Security then creates the Class object that is associated with your subclass, and creates an instance of your subclass by calling the newInstance method on that Class object. The newInstance method 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 Exemption Mechanism Provider a Name

Decide on a name for your exemption mechanism provider. This is the name to be used by client applications to refer to your exemption mechanism 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 call super, specifying the provider name (see Step 2), version number, and a string of information about the provider and algorithms it supports. For example:

super("ExemptionX", 1.0, "X provider v1.0, implementing " + "Key Recovery, Key Escrow and Key Weakening exemption mechanism algorithms.");

Set the values of various properties that are required for the Java Security API to look up the cryptographic services that are implemented by the provider. For each exemption mechanism service implemented by the provider, ExemptionMechanism must be the name of the service followed by a period and the name of the exemption algorithm to which the service applies. The property value must specify the fully qualified name of the class that is implementing the service. ExemptionMechanism.algName

algName is the "standard" name of the algorithm.

The value of each property must be the fully qualified name of the class that is implementing the specified algorithm. That is, it must be the package name followed by the class name, where the two are separated by a period.

As an example, the "IBMEM" provider implements the key recovery algorithm in a class named KeyRecovery in the com.ibm.crypto.provider package. Its subclass of Provider (which is the IBMEM class in the com.ibm.crypto.provider package) sets the ExemptionMechanism.KeyRecovery property to have the value "com.ibm.crypto.provider.KeyRecovery" using the following:

 
put("ExemptionMechanism.KeyRecovery",
"com.ibm.crypto.provider.KeyRecovery")
For further master class property setting examples, see Appendix A to view a sample JCE IBMJCE.java source file. This appendix shows how the IBMJCE class constructor sets all the properties for the "IBMJCE" provider.

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

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: Sign your Exemption Mechanism Provider for Testing

Request a code signing certificate for testing only. This certificate has a limited validity period. It is provided for testing only. You should not use it to sign your product in the production environment.

Step 6: Prepare for Testing: Install the Exemption Mechanism Provider

In order to prepare for testing your provider, you must install it in the same manner as will be done by a customer who will 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 Exemption Mechanism Provider Classes

First, make your classes available so that they can be found when requested. You should bundle your provider classes as a JAR file.

There are two possible ways of installing your provider classes:

  • Place your provider JAR file on the CLASSPATH
  • Supply your provider JAR file as an "installed" or "bundled" extension.

For more information on how to deploy an extension, see Extension Deployment.

For more information on "installed" extensions, see Installed Extensions.

For more information on "bundled" extensions, see Bundled Extensions.

Configuring the Provider

The next step is to add the provider to your list of approved providers. This step is done statically by editing the security properties file
<java-home>\lib\security\java.security [Windows]
<java-home>/lib/security/java.security [UNIX]
Here <java-home> refers to the directory where the JRE was installed. For example, if you have JDK 1.4 installed on Windows in a directory name jdk1.4, you need to edit the following file:
C:\jdk1.4\jre\lib\security\java.security
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.

Java 2 v 1.4 comes standard with a number of providers, which are automatically configured as static providers in the java.security properties file, as follows:

security.provider.1=com.ibm.jsse.IBMJSSEProvider
security.provider.2=com.ibm.crypto.provider.IBMJCE
security.provider.3=com.ibm.security.jgss.IBMJGSSProvider
security.provider.4=com.ibm.security.cert.IBMCertPath
Suppose that your master class is the ExemptionX class in the com.ExemptionX.provider package, and that you would like to make your provider the fifth preferred provider. To do so, add the following line to the java.security file below the line for the "IBMCertPath" provider:
security.provider.2=com.cryptox.provider.ExemptionX
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 7: 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 exemption mechanism 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 key recovery algorithm, you could check to ensure it's found when requested by using the following code (again, substituting your provider name for "MyPro"):
ExemptionMechanism em = ExemptionMechanism.getInstance("KeyRecovery", "MyPro");
System.out.println("My Cipher algorithm name is " + em.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 8: Run your Test Programs

Run your test programs. 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 9: Document your Exemption Mechanism Provider and its Supported Services

The next step is to write documentation for your clients. At the minimum, you need to specify the name that programs should use to refer to your provider.

The documentation should include:

  • The types of algorithms and other services implemented by your provider.
  • Instructions for installing the provider are similar to those provided in Step 6, except that the information and examples should be specific to your provider.
In addition, your documentation should specify anything else of interest to clients, such as algorithm parameters is needed.

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 "IBMJCE" provider uses a default prime modulus size (keysize) of 1024 bits for the generation of Diffie-Hellman parameters.

Step 10: Attach the cryptoPerms to your provider

Some exemption mechanism may involve usuage of some crypto algorithm. In order to use those crypto algorithm, a cryptoPerms file should be included in the exemption mechanism provider JAR or ZIP file. Different level of permission for the exemption mechanism provider is defined the cryptoPerms file. A typical all-permission file is as follow:
// Permission policy file for provider

grant {
permission javax.crypto.CryptoAllPermission;
};
Or a restricted policy file would be like:
// A more restricted permission policy file for provider

grant {
permission javax.crypto.CryptoPermission "DES", 64;
permission javax.crypto.CryptoPermission "RC2", 64,
permission javax.crypto.CryptoPermission "RC5", 64,
permission javax.crypto.CryptoPermission *, 64;
};

Step 11: Sign your Exemption Mechanism Provider for Production

Note: The JCE provider signing policies have yet to be finalized.

Step 12: Run your Test Programs Again

Your provider should have been thoroughly tested in Step 8. However, we suggest you run your test programs again to
make sure that everything still works fine since what you tested in Step 8 is signed by a different certificate.

Step 13: Make your Exemption Mechanism Provider Software and Documentation Available to Clients

The final step is to make your provider software and documentation available to your customers.

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

Below is an edited version of the IBMJCE.java file, which contains a class named IBMJCE that is the master class for the provider named "IBMJCE". (Although that provider is supplied with every JCE 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 "IBMJCE" 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.

package com.ibm.crypto.provider;

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

/**
* The "IBMJCE" Cryptographic Service Provider.
*
* @version 1.30, 02/02/02
*/

/**
* Defines the "IBMJCE" 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 IBMJCE extends Provider {

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

public IBMJCE() {
/* We are the "IBMJCE" provider */
super("IBMJCE", 1.3, info);

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

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

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

put("Cipher.PBEWithMD5AndDES",
"com.ibm.crypto.provider.PBEWithMD5AndDESCipher");
put("Cipher.PBEWithMD5AndTripleDES",
"com.ibm.crypto.provider.PBEWithMD5AndTripleDESCipher");

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

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

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

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

put("KeyGenerator.HmacMD5",
"com.ibm.crypto.provider.HmacMD5KeyGenerator");

put("KeyGenerator.HmacSHA1",
"com.ibm.crypto.provider.HmacSHA1KeyGenerator");

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

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

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

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

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

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

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

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

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

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

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

put("SecretKeyFactory.PBEWithMD5AndDES",
"com.ibm.crypto.provider.PBEKeyFactory");

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

/*
* KeyStore
*/
put("KeyStore.JCEKS", "com.ibm.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 JRE installation. This file appears at
<java-home>\lib\security\java.security [Windows]
<java-home>/lib/security/java.security [UNIX]
Here <java-home> refers to the directory where the JRE was installed. If you have Java 2 SDK v 1.4 installed on Windows in a directory named jdk1.4, the file would be
C:\jdk1.4\jre\lib\security\java.security
See Step 5d 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.=
#
# 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.
#
# 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.
# 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=com.ibm.jsse.IBMJSSEProvider
security.provider.2=com.ibm.crypto.provider.IBMJCE
security.provider.3=com.ibm.security.jgss.IBMJGSSProvider
security.provider.4=com.ibm.security.cert.IBMCertPath

#
# The entropy gathering device is described as a URL and can
# also be specified with the property "java.security.egd". For example,
# -Djava.security.egd=file:/dev/urandom
# Specifying this property will override the securerandom.source setting.

#
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
login.configuration.provider=com.ibm.security.auth.login.ConfigFile

#
# Default login configuration file
#
#login.config.url.1=file:${user.home}/.java.login.config

#
# 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:${java.home}/lib/security/java.pol
policy.url.3=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

#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.

#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, no packages are restricted for definition, and none of
# the class loaders supplied with the JDK call checkPackageDefinition.
#
#package.definition=

#
# Determines whether this properties file can be appended to
# or overridden on the command line via -Djava.security.properties
#
security.overridePropertiesFile=true

#
# Determines the default key and trust manager factory algorithms for
# the javax.net.ssl package.
#
ssl.KeyManagerFactory.algorithm=IbmX509
ssl.TrustManagerFactory.algorithm=IbmX509

#
# Determines the default SSLSocketFactory and SSLServerSocketFactory
# provider implementations for the javax.net.ssl package. If, due to
# export and/or import regulations, the providers are not allowed to be
# replaced, changing these values will produce non-functional
# SocketFactory or ServerSocketFactory implementations.
#
#ssl.SocketFactory.provider=
#ssl.ServerSocketFactory.provider=

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set.
#
# NOTE: setting this to anything other than the default value can have
# serious security implications. Do not set it unless
# you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1

# The Java-level namelookup cache policy for failed lookups:
#
# any negative value: cache forever
# any positive value: the number of seconds to cache negative lookup results
# zero: do not cache
#
# In some Microsoft Windows networking environments that employ
# the WINS name service in addition to DNS, name service lookups
# that fail may take a noticeably long time to return (approx. 5 seconds).
# For this reason the default caching policy is to maintain these
# results for 10 seconds.
networkaddress.cache.negative.ttl=10

Notices

This information was developed for products and services offered in the U.S.A. IBM may not offer the products, services, or features discussed in this document in other countries. Consult your local IBM representative for information on the products and services currently available in your area. Any reference to an IBM product, program, or service is not intended to state or imply that only that IBM product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any IBM intellectual property right may be used instead. However, it is the user's responsibility to evaluate and verify the operation of any non-IBM product, program, or service.

IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to:

  • IBM Director of Licensing
    IBM Corporation
    North Castle Drive, Armonk
    NY 10504-1758 U.S.A.

For license inquiries regarding double-byte (DBCS) information, contact the IBM Intellectual Property Department in your country or send inquiries, in writing, to:

  • IBM World Trade Asia Corporation Licensing
    2-31 Roppongi 3-chome, Minato-ku
    Tokyo 106-0032, Japan

The following paragraph does not apply to the United Kingdom or any other country where such provisions are inconsistent with local law:

INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.

This information could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the information. IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this information at any time without notice.

Any references in this information to non-IBM Web sites are provided for convenience only and do not in any manner serve as an endorsement of those Web sites. The materials at those Web sites are not part of the materials for this IBM product and use of those Web sites is at your own risk.

IBM may use or distribute any of the information you supply in any way it believes appropriate without incurring any obligation to you.

Licensees of this program who wish to have information about it for the purpose of enabling (i) the exchange of information between independently created programs and other programs (including this one) and (ii) the mutual use of the information which has been exchanged, should contact:

  • JIMMAIL@uk.ibm.com
    [Hursley Java Technology Center (JTC) contact]

Such information may be available, subject to appropriate terms and conditions, including in some cases, payment of a fee.

The licensed program described in this document and all licensed material available for it are provided by IBM under terms of the IBM Customer Agreement, IBM International Program License Agreement or any equivalent agreement between us.

Any performance data contained herein was determined in a controlled environment. Therefore, the results obtained in other operating environments may vary significantly. Some measurements may have been made on development-level systems and there is no guarantee that these measurements will be the same on generally available systems. Furthermore, some measurement may have been estimated through extrapolation. Actual results may vary. Users of this document should verify the applicable data for their specific environment.

Information concerning non-IBM products was obtained from the suppliers of those products, their published announcements or other publicly available sources. IBM has not tested those products and cannot confirm the accuracy of performance, compatibility or any other claims related to non-IBM products. Questions on the capabilities of non-IBM products should be addressed to the suppliers of those products.



Trademarks

IBM is a trademark or registered trademark of International Business Machines Corporation in the United States, or other countries, or both.

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Other company, product, or service names may be trademarks or service marks of others.

 

 




Back to top


Document options

Document options requiring JavaScript are not displayed


Related information
General SDK FAQs
Newsgroups
Future plans

Special offers
Rate and  Review Rational products
DB2 pureScale Unlimited capacity for your data
WebSphere Application Server Hypervisor trial

More offers