The JavaTM Cryptography Extension (JCE) 1.2 is a standard extension to the JDKTM platform. JCE 1.2 supplements the cryptographic services defined in the Java Development Kit 1.2 (JDKTM) by adding support for ciphers, key agreement, and message authentication codes.
JCE 1.2 is based on the same design principles as JDK 1.2, which uses the notion of a Cryptography Package Provider, or "provider" for short. This term refers to a package (or a set of packages) that supply a concrete implementation of a subset of the cryptography aspects of the Java Security API in JDK 1.2.
JCE 1.2 extends the list of cryptographic services of which a provider can supply implementations. A provider could, for example, contain an implementation of one or more digital signature algorithms and one or more cipher algorithms.
A program wishing to use cryptography functionality may simply request a particular type of object (such as a Cipher object) implementing a particular algorithm (such as DES) and get an implementation from one of the installed providers. If an implementation from a particular provider is desired, the program can request that provider by name, along with the algorithm desired.
Each JDK installation has one or more provider packages installed. Each provider package supplies implementations of cryptographic services defined in JDK 1.2 and/or JCE 1.2. Only when JCE 1.2 is installed can the JCE-specific implementations supplied by provider packages be accessed.
Clients may configure their runtimes with different providers, and specify a preference order for each of them. The preference order is the order in which providers are searched for requested algorithms when no particular provider is requested.
JCE 1.2 comes with a built-in provider named "SunJCE", which supplies the following services:
- An implementation of the DES (FIPS PUB 46-1), Triple DES, and Blowfish algorithms in the Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feedback (CFB), Output Feedback (OFB), and Propagating Cipher Block Chaining (PCBC) modes.
- Key generators for generating keys suitable for the DES and Triple DES algorithms.
- An implementation of the MD5 with DES-CBC password-based encryption (PBE) algorithm defined in PKCS #5.
- "Secret-key factories" providing bi-directional conversions between opaque DES, Triple DES and PBE key objects and transparent representations of their underlying key material.
- An implementation of the Diffie-Hellman key agreement algorithm between two or more parties.
- A Diffie-Hellman key pair generator for generating a pair of public and private values suitable for the Diffie-Hellman algorithm.
- A Diffie-Hellman algorithm parameter generator.
- A Diffie-Hellman "key factory" providing bi-directional conversions between opaque Diffie-Hellman key objects and transparent representations of their underlying key material.
- Algorithm parameter managers for Diffie-Hellman, DES, Triple DES, and PBE parameters.
- An implementation of the HMAC-MD5 and HMAC-SHA1 keyed-hashing algorithms defined in RFC 2104.
- An implementation of the padding scheme described in PKCS#5.
- A keystore implementation for the proprietary keystore type named "JCEKS".
New providers may be added statically or dynamically. Clients may also query which providers are currently installed.
The different implementations may have different characteristics. Some may be software-based, while others may be hardware-based. Some may be platform-independent, while others may be platform-specific. Some provider source code may be available for review and evaluation, while some may not.
Who Should Read This Document
This document is intended for experienced programmers wishing to create their own provider packages supplying cryptographic service implementations. It documents what you need to do in order to integrate your provider into Java Security so that your algorithms and other services can be found when Java Security API clients request them. Programmers that only need to use the Java Security API to access existing cryptography algorithms and other services do not need to read this document.
Related Documentation
This document assumes you have already read the following documents:
- Java Cryptography Architecture API Specification and Reference,
- How to Implement a Provider for the Java Cryptography Architecture, and
- Java Cryptography Extension 1.2 API Specification and Reference.
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:
- java.security package
- java.security.spec package
- java.security.interfaces package
- javax.crypto package
- javax.crypto.spec package
- javax.crypto.interfaces package
An "engine class" defines a cryptographic service in an abstract fashion (without a concrete implementation).
A cryptographic service is always associated with a particular algorithm, and it either provides cryptographic operations (like those for ciphers or key agreement protocols), or generates or supplies the cryptographic material (keys or parameters) required for cryptographic operations. For example, two of the engine classes are the Cipher and KeyAgreement classes. The Cipher class provides access to the functionality of an encryption algorithm (such as DES), and the KeyAgreement class provides access to the functionality of a key agreement protocol (such as Diffie-Hellman).
The Java Cryptography Architecture encompasses the classes of the JDK 1.2 Java Security package related to cryptography, including the engine classes. Users of the API request and utilize instances of the engine classes to carry out corresponding operations.
JCE 1.2 is provided as a standard extension to JDK 1.2, and supplements the cryptographic services defined in JDK 1.2 by adding the following engine classes:
- 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.
An engine class provides the interface to the functionality of a specific type of cryptographic service (independent of a particular cryptographic algorithm). It defines "Application Programming Interface" (API) methods that allow applications to access the specific type of cryptographic service it provides. The actual implementations (from one or more providers) are those for specific algorithms. The Cipher engine class, for example, provides access to the functionality of a cipher algorithm. The actual implementation supplied in a CipherSpi subclass (see next paragraph) would be that for a specific kind of encryption algorithm, such as DES or Triple DES.
The application interfaces supplied by an engine class are implemented in terms of a "Service Provider Interface" (SPI). That is, for each engine class, there is a corresponding abstract SPI class, which defines the Service Provider Interface methods that cryptographic service providers must implement.
An instance of an engine class, the "API object", encapsulates (as a private field) an instance of the corresponding SPI class, the "SPI object". All API methods of an API object are declared "final", and their implementations invoke the corresponding SPI methods of the encapsulated SPI object. An instance of an engine class (and of its corresponding SPI class) is created by a call to the
getInstance
factory method of the engine class.The name of each SPI class is the same as that of the corresponding engine class, followed by "Spi". For example, the SPI class corresponding to the Cipher engine class is the CipherSpi class.
Each SPI class is abstract. To supply the implementation of a particular type of service, for a specific algorithm, a provider must subclass the corresponding SPI class and provide implementations for all the abstract methods.
Another example of an engine class is the KeyAgreement class, which provides access to a key agreement (key exchange) algorithm. Its implementations, in KeyAgreementSpi subclasses, may be those of various key agreement algorithms such as Diffie-Hellman.
As a final example, the SecretKeyFactory engine class supports the conversion from opaque secret keys to transparent key specifications, and vice versa. (See Key Specification Interfaces and Classes Required by Key Factories.) The actual implementation supplied in a SecretKeyFactorySpi subclass would be that for a specific type of secret keys, e.g., DES keys.
The steps required in order to implement a provider and integrate it into Java Security are the same as described in the How to Implement a Provider for the Java Cryptography Architecture guide.Step 1: Write your Service Implementation Code
The first thing you need to do is write the code supplying algorithm-specific implementations of the cryptographic services you want to support.Note that your provider may supply implementations of cryptographic services defined in JCE 1.2 in addition to implementations of cryptographic services defined in JDK 1.2.
In JCE 1.2, you can supply cipher, key agreement and MAC algorithms, as well as secret-key factories and secret-key generation services.
In JDK 1.2, you can supply signature, message digest, key pair generation, and (pseudo-)random number generation algorithms, as well as key and certificate factories and keystore creation and management, algorithm parameter management, and algorithm parameter generation services.
For each cryptographic service in JCE 1.2 or JDK 1.2, you need to create a subclass of the appropriate SPI class. JCE 1.2 defines the following engine classes, in addition to the engine classes defined in JDK 1.2: CipherSpi, KeyAgreementSpi, KeyGeneratorSpi, MacSpi, and SecretKeyFactorySpi. (See "JCE 1.2 Engine Classes and Corresponding SPI Classes" and "JDK 1.2 Engine Classes and Corresponding SPI Classes".)
In your subclass, you need to
- supply implementations for the abstract methods, whose names usually begin with "engine". See Further Implementation Details and Requirements for additional information.
- ensure there is a public constructor without any arguments. Here's why: When one of your services is requested, Java Security looks up the subclass implementing that service, as specified by a property in your "master class" (see Step 3). Java Security then creates the Class object associated with your subclass, and creates an instance of your subclass by calling the
newInstance
method on that Class object.newInstance
requires your subclass to have a public constructor without any parameters.A default constructor without arguments will automatically be generated if your subclass doesn't have any constructors. But if your subclass defines any constructors, you must explicitly define a public constructor without arguments.
Step 2: Give your Provider a Name
Decide on a name for your provider. This is the name to be used by client applications to refer to your provider.Step 3: Write your "Master Class", a subclass of Provider
The third step is to create a subclass of thejava.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 (Signature, MessageDigest, KeyPairGenerator, SecureRandom, KeyFactory, AlgorithmParameterGenerator, or AlgorithmParameters), 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 implementing the service.
The list below shows the various types of properties that must be defined for the various types of services, where the actual algorithm name is substitued for algName:
Cipher.
algNameKeyAgreement.
algNameKeyGenerator.
algNameMac.
algNameSecretKeyFactory.
algNameIn all of these, algName is the "standard" name of the algorithm. In the case of
Cipher
, algName may actually represent a transformation, and may be composed of an algorithm name, a particular operation mode, and a padding scheme. (See Appendix A of the Java Cryptography Extension 1.2 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 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 "SunJCE" provider implements the Diffie-Hellman key agreement algorithm in a class named
DHKeyAgreement
in thecom.sun.crypto.provider
package. Its subclass of Provider (which is theSunJCE
class in thecom.sun.crypto.provider
package) sets theKeyAgreement.DH
property to have the value "com.sun.crypto.provider.DHKeyAgreement" via the following:put("KeyAgreement.DH", "com.sun.crypto.provider.DHKeyAgreement")
For further master class property setting examples, see Appendix A to view the current JCE 1.2
SunJCE.java
source file. This shows how theSunJCE
class constructor sets all the properties for the "SunJCE" provider.Note: The Provider subclass can get its information from wherever it wants. Thus, the information can be hard-wired in, or retrieved at runtime, e.g., from a file.
As mentioned above, in the case of a
Cipher
property, algName may actually represent a transformation. A transformation is a string that describes the operation (or set of operations) to be performed by a Cipher object on some given input. A transformation always includes the name of a cryptographic algorithm (e.g., DES), and may be followed by a feedback mode and padding scheme.A transformation is of the form:
- "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 (e.g.,
DES
inCFB
orOFB
mode), a client may optionally specify the number of bits to be processed at a time, by appending this number to the mode name as shown in the following sample transformations:
Cipher c1 = Cipher.getInstance("DES/CFB8/NoPadding"); Cipher c2 = Cipher.getInstance("DES/OFB32/PKCS5Padding");If a feedback mode is not followed by a number, a provider-specific default is used. (For example, the "SunJCE" provider uses a default of 64 bits.)
A provider may supply a separate class for each combination of algorithm/mode/padding, or may decide to provide more generic classes representing sub-transformations corresponding to algorithm or algorithm/mode or algorithm//padding (note the double slashes), in which case the requested mode and/or padding are set automatically by the
getInstance
methods ofCipher
, which invoke theengineSetMode
andengineSetPadding
methods of the provider's subclass ofCipherSpi
.A
Cipher
property in a provider master class may have one of the following formats:
// provider's subclass of "CipherSpi" implements "algName" with pluggable // mode and paddingCipher.
algName // provider's subclass of "CipherSpi" implements "algName" in the specified // "mode", with pluggable paddingCipher.
algName/mode // provider's subclass of "CipherSpi" implements "algName" with the // specified "padding", with pluggable modeCipher.
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 1.2 API Specification & Reference for the standard algorithm names, modes, and padding schemes that should be used.)
For example, a provider may supply a subclass of
CipherSpi
that implements DES/ECB/PKCS5Padding, one that implements DES/CBC/PKCS5Padding, one that implements DES/CFB/PKCS5Padding, and yet another one that implements DES/OFB/PKCS5Padding. That provider would have the followingCipher
properties in its master class:
Cipher.
DES/ECB/PKCS5PaddingCipher.
DES/CBC/PKCS5PaddingCipher.
DES/CFB/PKCS5PaddingCipher.
DES/OFB/PKCS5PaddingAnother provider may implement a class for each of the above modes (i.e., one class for ECB, one for CBC, one for CFB, and one for OFB), one class for PKCS5Padding, and a generic DES class that subclasses from
CipherSpi
. That provider would have the followingCipher
properties in its master class:
Cipher.
DESThe
getInstance
factory method of theCipher
engine class follows these rules in order to instantiate a provider's implementation ofCipherSpi
for a transformation of the form "algorithm":
- Check if the provider has registered a subclass of
CipherSpi
for the specified "algorithm".If the answer is YES, instantiate this class, for whose mode and padding scheme default values (as supplied by the provider) are used.
If the answer is NO, throw a
NoSuchAlgorithmException
exception.The
getInstance
factory method of theCipher
engine class follows these rules in order to instantiate a provider's implementation ofCipherSpi
for a transformation of the form "algorithm/mode/padding":
- Check if the provider has registered a subclass of
CipherSpi
for the specified "algorithm/mode/padding" transformation.If the answer is YES, instantiate it.
If the answer is NO, go to the next step.
- Check if the provider has registered a subclass of
CipherSpi
for the sub-transformation "algorithm/mode".If the answer is YES, instantiate it, and call
engineSetPadding(padding)
on the new instance.If the answer is NO, go to the next step.
- Check if the provider has registered a subclass of
CipherSpi
for the sub-transformation "algorithm//padding" (note the double slashes).If the answer is YES, instantiate it, and call
engineSetMode(mode)
on the new instance.If the answer is NO, go to the next step.
- Check if the provider has registered a subclass of
CipherSpi
for the sub-transformation "algorithm".If the answer is YES, instantiate it, and call
engineSetMode(mode)
andengineSetPadding(padding)
on the new instance.If the answer is NO, throw a
NoSuchAlgorithmException
exception.Step 4: Compile your Code
After you have created your implementation code (Step 1), given your provider a name (Step 2), and created the master class (Step 3), use the Java compiler to compile your files.Step 5: Prepare for Testing: Install the Provider
In order to prepare for testing your provider, you must install it in the same manner as will be done by clients wishing to use it. The installation enables Java Security to find your algorithm implementations when clients request them.There are two parts to installing a provider: installing the provider package classes, and configuring the provider.
Installing the Provider Classes
The first thing you must do is make your classes available so that they can be found when requested. You ship your provider classes as a JAR (Java ARchive) or ZIP file.Note that in order for your provider to work, you must also have JCE 1.2 (more specifically: the
jce12-beta-dom.jar
extension) installed.There are a couple possible ways of installing your provider classes:
- Place a JAR or ZIP file containing your own provider classes anywhere on your CLASSPATH. Place the
jce12-beta-dom.jar
file on the same CLASSPATH, or supply it as an "installed" extension.
- Supply your own provider JAR file as an "installed" or "bundled" extension.
When you supply your own provider JAR file as an "installed" extension, the
jce12-beta-dom.jar
file must also be supplied as an "installed" extension.When you supply your own provider JAR file as a "bundled" extension, you must either bundle the
jce12-beta-dom.jar
file with it (i.e., in the manifest of your own extension's JAR file you specify the relative URL referring to thejce12-beta-dom.jar
JAR file via theClass-Path
attribute), or you must supply thejce12-beta-dom.jar
file as an "installed" extension on the target Java Virtual Machine (JVM) where your provider classes will be accessed. Since you may not always have access to the target JVM, it is safest to always bundle thejce12-beta-dom.jar
JAR file with your own provider JAR file when you deploy your provider classes as a "bundled" extension.For more information on how to deploy an extension, see How is an extension deployed?.
For more information on "installed" extensions, see Installation: Where is an extension installed?.
For more information on "bundled" extensions, see Dependencies: How does an application specify the other extensions it needs?.
Configuring the Provider
The next step is to add the provider to your list of approved providers. This is done statically by editing the
java.security
file in thelib/security
(lib\security
on Windows) directory of the JDK. Thus, if the JDK is installed in a directory calledjdk1.2
, the file is
jdk1.2/lib/security/java.security
(Solaris)
jdk1.2\lib\security\java.security
(Windows)For each provider, this file should have a statement of the following form:
security.provider.n=masterClassNameThis declares a provider, and specifies its preference order n. The preference order is the order in which providers are searched for requested algorithms when no specific provider is requested. The order is 1-based; 1 is the most preferred, followed by 2, and so on.
masterClassName must specify the fully qualified name of the provider's "master class", which you implemented in Step 3. This class is always a subclass of the Provider class.
Whenever the JDK is installed, it contains one built-in (default) provider, the provider referred to as "SUN". The
java.security
file has just the following provider specification:security.provider.1=sun.security.provider.Sun(The "SUN" provider's master class is theSun
class in thesun.security.provider
package.)Note that when you install JCE 1.2, its provider ("SunJCE") is not automatically installed, i.e., if you want to use the "SunJCE" provider, you have to explicitly register it - either statically or dynamically, as described in this section.
Suppose that your master class is the
CryptoX
class in thecom.cryptox.provider
package, and that you would like to make your provider the second preferred provider. To do so, add the following line to thejava.security
file below the line for the "SUN" provider:security.provider.2=com.cryptox.provider.CryptoXNote: 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 theaddProvider
orinsertProviderAt
method in theSecurity
class. This type of registration is not persistent and can only be done by "trusted" programs. See the Security class section of the Java Cryptography Architecture API Specification and Reference.Step 6: Write and Compile your Test Programs
Write and compile one or more test programs that test your provider's incorporation into the Security API as well as the correctness of its algorithm(s). Create any supporting files needed, such as those for test data to be encrypted.The first tests your program should perform are ones to ensure that your provider is found, and that its name, version number, and additional information is as expected. To do so, you could write code like the following, substituting your provider name for "MyPro":
import java.security.*; Provider p = Security.getProvider("MyPro"); System.out.println("MyPro provider name is " + p.getName()); System.out.println("MyPro provider version # is " + p.getVersion()); System.out.println("MyPro provider info is " + p.getInfo());Next, you should ensure that your services are found. For instance, if you implemented the DES encryption algorithm, you could check to ensure it's found when requested by using the following code (again substituting your provider name for "MyPro"):
Cipher c = Cipher.getInstance("DES", "MyPro"); System.out.println("My Cipher algorithm name is " + c.getAlgorithm());If you don't specify a provider name in the call to
getInstance
, all registered providers will be searched, in preference order (see Configuring the Provider), until one implementing the algorithm is found.Step 7: Run your Test Programs
Run your test program(s). Debug your code and continue testing as needed. If the Java Security API cannot seem to find one of your algorithms, review the steps above and ensure they are all completed.Step 8: Document your Provider and its Supported Services
The next-to-last step is to write documentation for your clients. At the minimum, you need to specifyIn addition, your documentation should specify anything else of interest to clients, such as any default algorithm parameters.
- the name programs should use to refer to your provider. Please note: As of this writing, 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. This behavior may change in the future, but for now be sure to warn your clients to use the exact case you specify.
- the types of algorithms and other services implemented by your provider.
- instructions for installing the provider, similar to those provided in Step 5, except that the information and examples should be specific to your provider.
MACs
For each MAC algorithm, tell whether or not your implementation is cloneable. This is not technically necessary, but it may save clients some time and coding by telling them whether or not intermediate "message authentication codes" (MACs) may be possible through cloning. Clients who do not know whether or not a MAC implementation is cloneable can find out by attempting to clone the Mac object and catching the potential exception, as illustrated by the following example:
try { // try and clone it /* compute the MAC for i1 */ mac.update(i1); byte[] i1Mac = mac.clone().doFinal(); /* compute the MAC for i1 and i2 */ mac.update(i2); byte[] i12Mac = mac.clone().doFinal(); /* compute the MAC for i1, i2 and i3 */ mac.update(i3); byte[] i123Mac = mac.doFinal(); } catch (CloneNotSupportedException cnse) { // have to use an approach not involving cloning }where
mac
is the MAC object they received when they requested one via a call toMac.getInstance
,
i1
,i2
andi3
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 client does not explicitly initialize the key pair generator (via a call to an
initialize
method), each provider must supply and document a default initialization. For example, the Diffie-Hellman key pair generator supplied by the "SunJCE" provider uses a default prime modulus size (strength) of 512 bits.Key Factories
A provider should document all the key specifications supported by its (secret-)key factory.Algorithm Parameter Generators
In case the client does not explicitly initialize the algorithm parameter generator (via a call to aninit
method in the AlgorithmParameterGenerator engine class), each provider must supply and document a default initialization. For example, the "SunJCE" provider uses a default prime modulus size of 512 bits and a random exponent (private value) size of 504 bits for the generation of Diffie-Hellman parameters.Step 9: Make your Class Files and Documentation Available to Clients
The final step is to make your class files and documentation available to clients in whatever form (.class files, zip files, JAR files, ...) and methods (web download, floppy, mail, ...) you feel are appropriate.
Algorithm Aliases
For many cryptographic algorithms, there is a single official "standard name". The standard names defined by JCE 1.2 are listed in Appendix A of the Java Cryptography Extension 1.2 API Specification & Reference.For example, "DiffieHellman" is the standard name for the Diffie-Hellman key agreement algorithm defined in PKCS #3.
JCE 1.2 uses the same aliasing scheme for algorithm names as JDK 1.2. That scheme enables clients to use aliases when referring to algorithms, rather than their standard names. For example, the "SunJCE" provider's master class (
SunJCE.java
) defines the alias "DH" for the key agreement whose standard name is "DiffieHellman". Thus, the following statements are equivalent:KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman", "SunJCE"); KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");Aliases can be defined in your "master class" (see Step 3). To define an alias, create a property namedAlg.Alias.
engineClassName.aliasNamewhere engineClassName is either
Signature
,MessageDigest
,KeyPairGenerator
,KeyFactory
,AlgorithmParameterGenerator
, orAlgorithmParameters
, and aliasName is your alias name. The value of the property must be the standard algorithm name for the algorithm being aliased.As an example, the "SunJCE" provider defines the alias "DH" for the key agreement algorithm whose standard name is "DiffieHellman" by setting a property named
Alg.Alias.KeyAgreement.DH
to have the valueDiffieHellman
via the following:put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");Currently, aliases defined by the "SunJCE" provider are available to all clients, no matter which provider clients request. For example, if you create a provider named "MyPro" that implements the Diffie-Hellman algorithm, then even if you don't define any aliases for it, the "DH" alias defined by "SunJCE" can be used to refer to your provider's Diffie-Hellman implementation as follows:
KeyAgreement ka = KeyAgreement.getInstance("DH", "MyPro");
WARNING: The aliasing scheme may be changed or eliminated in future releases.
Service Interdependencies
Some algorithms require the use of other types of algorithms. For example, a PBE algorithm usually needs to use a message digest algorithm in order to transform a password into a key.If you are implementing one type of algorithm that requires another, you can do one of the following:
- Provide your own implementations for both.
- Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by the default "SUN" provider that is included with every JDK installation. For example, if you are implementing a PBE algorithm that requires a message digest algorithm, you can obtain an instance of a class implementing the MD5 message digest algorithm by calling
MessageDigest.getInstance("MD5", "SUN")
- Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by another specific provider. This is only appropriate if you are sure that all clients who will use your provider will also have the other provider installed.
- Let your implementation of one algorithm use an instance of the other type of algorithm, as supplied by another (unspecified) provider. That is, you can request an algorithm by name, but without specifying any particular provider, as in
MessageDigest.getInstance("MD5")This is only appropriate if you are sure that there will be at least one implementation of the requested algorithm (in this case, MD5) installed on each Java platform where your provider will be used.Default Initializations
In case the client does not explicitly initialize a key pair generator or an algorithm parameter generator, each provider of such a service must supply (and document) a default initialization. For example, the "SunJCE" provider uses a default modulus size (strength) of 512 bits for the generation of Diffie-Hellman parameters.
Diffie-Hellman Interfaces and their Required Implementations
JCE 1.2 contains the following interfaces (in thejavax.crypto.interfaces
package) for the convenience of programmers implementing Diffie-Hellman services: The following sections discuss requirements for implementations of these interfaces.DHPrivateKey and DHPublicKey Implementations
If you implement a Diffie-Hellman key pair generator or key factory, you need to create classes implementing the DHPrivateKey and DHPublicKey interfaces.If you implement a Diffie-Hellman key pair generator, your
generateKeyPair
method (in your KeyPairGeneratorSpi subclass) will return instances of your implementations of those interfaces.If you implement a Diffie-Hellman key factory, your
engineGeneratePrivate
method (in your KeyFactorySpi subclass) will return an instance of your DHPrivateKey implementation, and yourengineGeneratePublic
method will return an instance of your DHPublicKey implementation.Also, your
engineGetKeySpec
andengineTranslateKey
methods will expect the passed-in key to be an instance of a DHPrivateKey or DHPublicKey implementation. ThegetParams
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 yourengineDoPhase
method will expect to be passed a DHPublicKey.Please note: The DHPublicKey and DHPrivateKey interfaces define a very generic, provider-independent interface to Diffie-Hellman public and private keys, respectively. The
engineGetKeySpec
andengineTranslateKey
methods (in your KeyFactorySpi subclass) could additionally check if the passed-in key is actually an instance of their provider's own implementation of DHPrivateKey or DHPublicKey, e.g., to take advantage of provider-specific implementation details. The same is true for the Diffie-Hellman algorithmengineInit
andengineDoPhase
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.SerializableIn order to implement the DHPrivateKey and DHPublicKey interfaces, you must implement the methods they define as well as those defined by interfaces they extend, directly or indirectly.
Thus, for private keys, you need to supply a class that implements
- the
getX
method from the DHPrivateKey interface.
- the
getParams
method from the javax.crypto.interfaces.DHKey interface, since DHPrivateKey extends DHKey.- the
getAlgorithm
,getEncoded
, andgetFormat
methods from the java.security.Key interface, since DHPrivateKey extendsjava.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
, andgetFormat
methods from the java.security.Key interface, since DHPublicKey extendsjava.security.PublicKey
, and PublicKey extends Key.Algorithm Parameter Specification Classes
An algorithm parameter specification is a transparent representation of the sets of parameters used with an algorithm.
A transparent representation of parameters means that you can access each value individually, through one of the "get" methods defined in the corresponding specification class (e.g., DHParameterSpec defines
getP
,getG
, andgetL
methods, to access the p, g, and l parameters, respectively).This is contrasted with an opaque representation, as supplied by the AlgorithmParameters engine class, in which you have no direct access to the key material values; you can only get the name of the algorithm associated with the parameter set (via
getAlgorithm
) and some kind of encoding for the parameter set (viagetEncoded
).If you supply an AlgorithmParametersSpi, AlgorithmParameterGeneratorSpi, or KeyPairGeneratorSpi implementation, you must utilize the AlgorithmParameterSpec interface, since each of those classes contain methods that take an AlgorithmParameterSpec parameter. Such methods need to determine which actual implementation of that interface has been passed in, and act accordingly.
JCE 1.2 contains a number of AlgorithmParameterSpec implementations for the most frequently used cipher and key agreement algorithm parameters. If you are operating on algorithm parameters that should be for a different type of algorithm not provided by JCE 1.2, you will need to supply your own AlgorithmParameterSpec implementation appropriate for that type of algorithm.
JCE 1.2 defines the following algorithm parameter specification classes in the
javax.crypto.spec
package:The IvParameterSpec Class
This class (which implements the AlgorithmParameterSpec interface) specifies the initialization vector (IV) used with a cipher in feedback mode. It has the following method:public byte[] getIV()This method returns the IV.The PBEParameterSpec Class
This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with a password-based encryption (PBE) algorithm. It has the following methods:public byte[] getSalt() public int getIterationCount()These methods return the PBE parameters: the salt and the iteration count.The RC2ParameterSpec Class
This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the RC2 algorithm. It has the following methods:public int getEffectiveKeyBits() public byte[] getIV()These methods return the RC2 algorithm parameters: the effective key size (in bits) and the IV.The RC5ParameterSpec Class
This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the RC5 algorithm. It has the following methods:public int getVersion() public int getRounds() public int getWordSize() public byte[] getIV()These methods return the RC5 algorithm parameters: the version number, number of rounds, word size (in bits), and the IV.The DHParameterSpec Class
This class (which implements the AlgorithmParameterSpec interface) specifies the set of parameters used with the Diffie-Hellman algorithm. It has the following methods:public BigInteger getP() public BigInteger getG() public int getL()These methods return the Diffie-Hellman algorithm parameters: the prime modulusp
, the base generatorg
, and the size in bits of the random exponent (private value),l
.Many types of Diffie-Hellman services will find this class useful - for example, it is utilized by the Diffie-Hellman key agreement, key pair generator, algorithm parameter generator, and algorithm parameters classes implemented by the "SunJCE" provider. As a specific example, an algorithm parameters implementation must include an implementation for the
getParameterSpec
method, which returns an AlgorithmParameterSpec. The Diffie-Hellman algorithm parameters implementation supplied by "SunJCE" returns an instance of the DHParameterSpec class.Key Specification Classes Required by Key Factories
Key specifications are transparent representations of the key material that constitutes a key. JCE 1.2 defines the following key specification classes in the
javax.crypto.spec
package: DHPrivateKeySpec, DHPublicKeySpec, DESKeySpec, and DESedeKeySpec.The DHPrivateKeySpec Class
This class (which implements the KeySpec interface) specifies a Diffie-Hellman private key with its associated parameters. It has the following methods:public BigInteger getX() public BigInteger getP() public BigInteger getG()These methods return the private valuex
, and the Diffie-Hellman algorithm parameters used to calculate it: the prime modulusp
and the base generatorg
.The DHPublicKeySpec Class
This class (which implements the KeySpec interface) specifies a Diffie-Hellman public key with its associated parameters. It has the following methods:public BigInteger getY() public BigInteger getP() public BigInteger getG()These methods return the public valuey
, and the Diffie-Hellman algorithm parameters used to calculate it: the prime modulusp
and the base generatorg
.The DESKeySpec Class
This class (which implements the KeySpec interface) specifies a DES key. It has the following methods:public byte[] getKey() public static boolean isParityAdjusted(byte[] key, int offset) public static boolean isWeak(byte[] key, int offset)The first method returns the DES key bytes. The other (class) methods check if a given DES key is parity adjusted or weak, respectively.The DESedeKeySpec Class
This class (which implements the KeySpec interface) specifies a DES-EDE (Triple DES) key. It has the following methods:public byte[] getKey() public static boolean isParityAdjusted(byte[] key, int offset)The first method returns the DES-EDE key bytes. The other (class) method checks if a given DES-EDE key is parity adjusted.The SecretKeySpec Class
This class implements the KeySpec interface. Since it also implements the SecretKey interface, it can be used to construct aSecretKey
object in a provider-independent fashion, i.e., without having to go through a provider-basedSecretKeyFactory
. 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 ofjavax.crypto.KeyGeneratorSpi
) for a particular secret-key algorithm, you may return the generated secret-key object (which must be an instance ofjavax.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 theSecretKeySpec
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.
Below is an edited version of theSunJCE.java
file, which contains a class namedSunJCE
that is the master class for the provider named "SunJCE". (Although that provider is supplied with every JCE 1.2 installation, it still needs to be configured.)As with all master classes, this class is a subclass of Provider. It specifies the class names and package locations of all the cryptographic service implementations supplied by the "SunJCE" provider. This information is used by the
getInstance
methods of the engine classes to look up the various algorithms and other services when they are requested.This code is supplied as an example of a provider master class.
/* * Copyright 1997, 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ package com.sun.crypto.provider; import java.security.AccessController; import java.security.Provider; /** * The "SunJCE" Cryptographic Service Provider. */ /** * Defines the "SunJCE" provider. * * Supported algorithms and their names: * * - DES (ECB, CBC, CFB, OFB, PCBC) * * - DES-EDE (ECB, CBC, CFB, OFB, PCBC) * * - Password-based Encryption (PBE) * * - Blowfish * * - Diffie-Hellman Key Agreement * * - HMAC-MD5, HMAC-SHA1 * * - PKCS5Padding */ public final class SunJCE extends Provider { private static String info = "SunJCE Provider " + "(implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman, HMAC-MD5, " + "HMAC-SHA1)"; public SunJCE() { /* We are the "SunJCE" provider */ super("SunJCE", 1.2, info); AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { /* * Cipher engines */ put("Cipher.DES", "com.sun.crypto.provider.DESCipher"); put("Cipher.DESede", "com.sun.crypto.provider.DESedeCipher"); put("Alg.Alias.Cipher.TripleDES", "DESede"); put("Cipher.PBEWithMD5AndDES", "com.sun.crypto.provider.PBEWithMD5AndDESCipher"); put("Cipher.Blowfish", "com.sun.crypto.provider.BlowfishCipher"); /* * Key(pair) Generator engines */ put("KeyGenerator.DES", "com.sun.crypto.provider.DESKeyGenerator"); put("KeyGenerator.DESede", "com.sun.crypto.provider.DESedeKeyGenerator"); put("Alg.Alias.KeyGenerator.TripleDES", "DESede"); put("KeyGenerator.Blowfish", "com.sun.crypto.provider.BlowfishKeyGenerator"); put("KeyPairGenerator.DiffieHellman", "com.sun.crypto.provider.DHKeyPairGenerator"); put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman"); /* * Algorithm parameter generation engines */ put("AlgorithmParameterGenerator.DiffieHellman", "com.sun.crypto.provider.DHParameterGenerator"); put("Alg.Alias.AlgorithmParameterGenerator.DH", "DiffieHellman"); /* * Key Agreement engines */ put("KeyAgreement.DiffieHellman", "com.sun.crypto.provider.DHKeyAgreement"); put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); /* * Algorithm Parameter engines */ put("AlgorithmParameters.DiffieHellman", "com.sun.crypto.provider.DHParameters"); put("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman"); put("AlgorithmParameters.DES", "com.sun.crypto.provider.DESParameters"); put("AlgorithmParameters.DESede", "com.sun.crypto.provider.DESedeParameters"); put("Alg.Alias.AlgorithmParameters.TripleDES", "DESede"); put("AlgorithmParameters.PBE", "com.sun.crypto.provider.PBEParameters"); put("Alg.Alias.AlgorithmParameters.PBEWithMD5AndDES", "PBE"); put("AlgorithmParameters.Blowfish", "com.sun.crypto.provider.BlowfishParameters"); /* * Key factories */ put("KeyFactory.DiffieHellman", "com.sun.crypto.provider.DHKeyFactory"); put("Alg.Alias.KeyFactory.DH", "DiffieHellman"); /* * Secret-key factories */ put("SecretKeyFactory.DES", "com.sun.crypto.provider.DESKeyFactory"); put("SecretKeyFactory.DESede", "com.sun.crypto.provider.DESedeKeyFactory"); put("Alg.Alias.SecretKeyFactory.TripleDES", "DESede"); put("SecretKeyFactory.PBE", "com.sun.crypto.provider.PBEKeyFactory"); put("Alg.Alias.SecretKeyFactory.PBEWithMD5AndDES", "PBE"); /* * MAC */ put("Mac.HmacMD5", "com.sun.crypto.provider.HmacMD5"); put("Mac.HmacSHA1", "com.sun.crypto.provider.HmacSHA1"); /* * KeyStore */ put("KeyStore.JCEKS", "com.sun.crypto.provider.JceKeyStore"); return null; } }); } }
Below is a copy of thejava.security
file that appears in every JDK installation. This file appears in thelib/security
(lib\security
on Windows) directory of the JDK. Thus, if the JDK is installed in a directory calledjdk1.2
, the file would be
See Step 5 for an example of adding information about your provider to this file.
jdk1.2/lib/security/java.security
(Solaris)
jdk1.2\lib\security\java.security
(Windows)# # This is the "master security properties file". # # In this file, various security properties are set for use by # java.security classes. This is where users can statically register # Cryptography Package Providers ("providers" for short). The term # "provider" refers to a package or set of packages that supply a # concrete implementation of a subset of the cryptography aspects of # the Java Security API. A provider may, for example, implement one or # more digital signature algorithms or message digest algorithms. # # Each provider must implement a subclass of the Provider class. # To register a provider in this master security properties file, # specify the Provider subclass name and priority in the format # # security.provider.n=className # # This declares a provider, and specifies its preference # order n. The preference order is the order in which providers are # searched for requested algorithms (when no specific provider is # requested). The order is 1-based; 1 is the most preferred, followed # by 2, and so on. # # className must specify the subclass of the Provider class whose # constructor sets the values of various properties that are required # for the Java Security API to look up the algorithms or other # facilities implemented by the provider. # # There must be at least one provider specification in java.security. # There is a default provider that comes standard with the JDK. It # is called the "SUN" provider, and its Provider subclass # named Sun appears in the sun.security.provider package. Thus, the # "SUN" provider is registered via the following: # # security.provider.1=sun.security.provider.Sun # # (The number 1 is used for the default provider.) # # Note: Statically registered Provider subclasses are instantiated # when the system is initialized. Providers can be dynamically # registered instead by calls to either the addProvider or # insertProviderAt method in the Security class. # # List of providers and their preference orders (see above): # security.provider.1=sun.security.provider.Sun # # Class to instantiate as the system Policy. This is the name of the class # that will be used as the Policy object. # policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user's home directory. policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policy # whether or not we expand properties in the policy file # if this is set to false, properties (${...}) will not be expanded in policy # files. policy.expandProperties=true # whether or not we allow an extra policy to be passed on the command line # with -Djava.security.policy=somefile. Comment out this line to disable # this feature. policy.allowSystemProperty=true # whether or not we look into the IdentityScope for trusted Identities # when encountering a 1.1 signed JAR file. If the identity is found # and is trusted, we grant it AllPermission. policy.ignoreIdentityScope=false # # Default keystore type. # keystore.type=jks # # Class to instantiate as the system scope: # system.scope=sun.security.provider.IdentityDatabase
Copyright © 1996-98 Sun Microsystems, Inc. All Rights Reserved. Please send comments to: java-security@java.sun.com. |
![]() Java Software Division |