2 Java Cryptography Architecture (JCA) Reference Guide
The Java Cryptography Architecture (JCA) is a major piece of the platform, and contains a "provider" architecture and a set of APIs for digital signatures, message digests (hashes), certificates and certificate validation, encryption (symmetric/asymmetric block/stream ciphers), key generation and management, and secure random number generation, to name a few.
Introduction to Java Cryptography Architecture
The Java platform strongly emphasizes security, including language safety, cryptography, public key infrastructure, authentication, and secure communication.
The JCA is a major piece of the platform, and contains a "provider" architecture and a set of APIs for digital signatures, message digests (hashes), certificates and certificate validation, encryption (symmetric/asymmetric block/stream ciphers), key generation and management, and secure random number generation, to name a few. These APIs allow developers to easily integrate security into their application code. The architecture was designed around the following principles:
-
Implementation independence: Applications do not need to implement security algorithms. Rather, they can request security services from the Java platform. Security services are implemented in providers (see Cryptographic Service Providers), which are plugged into the Java platform via a standard interface. An application may rely on multiple independent providers for security functionality.
-
Implementation interoperability: Providers are interoperable across applications. Specifically, an application is not bound to a specific provider, and a provider is not bound to a specific application.
-
Algorithm extensibility: The Java platform includes a number of built-in providers that implement a basic set of security services that are widely used today. However, some applications may rely on emerging standards not yet implemented, or on proprietary services. The Java platform supports the installation of custom providers that implement such services.
Other cryptographic communication libraries available in the JDK use the JCA provider architecture, but are described elsewhere. The JSSE components provides access to Secure Socket Layer (SSL), Transport Layer Security (TLS), and Datagram Transport Layer Security (DTLS) implementations; see Java Secure Socket Extension (JSSE) Reference Guide. You can use Java Generic Security Services (JGSS) (via Kerberos) APIs, and Simple Authentication and Security Layer (SASL) to securely exchange messages between communicating applications; see Introduction to JAAS and Java GSS-API Tutorials and Java SASL API Programming and Deployment Guide.
Notes on Terminology
-
Prior to JDK 1.4, the JCE was an unbundled product, and as such, the JCA and JCE were regularly referred to as separate, distinct components. As JCE is now bundled in the JDK, the distinction is becoming less apparent. Since the JCE uses the same architecture as the JCA, the JCE should be more properly thought of as a part of the JCA.
-
The JCA within the JDK includes two software components:
- The framework that defines and supports cryptographic services for which providers supply implementations. This framework includes packages such as
java.security
,javax.crypto
,javax.crypto.spec
, andjavax.crypto.interfaces
. - The actual providers such as
Sun
,SunRsaSign
,SunJCE
, which contain the actual cryptographic implementations.
Whenever a specific JCA provider is mentioned, it will be referred to explicitly by the provider's name.
- The framework that defines and supports cryptographic services for which providers supply implementations. This framework includes packages such as
WARNING:
The JCA makes it easy to incorporate security features into your application. However, this document does not cover the theory of security/cryptography beyond an elementary introduction to concepts necessary to discuss the APIs. This document also does not cover the strengths/weaknesses of specific algorithms, not does it cover protocol design. Cryptography is an advanced topic and one should consult a solid, preferably recent, reference in order to make best use of these tools.You should always understand what you are doing and why: DO NOT simply copy random code and expect it to fully solve your usage scenario. Many applications have been deployed that contain significant security or performance problems because the wrong tool or algorithm was selected.
JCA Design Principles
The JCA was designed around these principles:
- Implementation independence and interoperability
- Algorithm independence and extensibility
Implementation independence and algorithm independence are complementary; you can use cryptographic services, such as digital signatures and message digests, without worrying about the implementation details or even the algorithms that form the basis for these concepts. While complete algorithm-independence is not possible, the JCA provides standardized, algorithm-specific APIs. When implementation-independence is not desirable, the JCA lets developers indicate a specific implementation.
Algorithm independence is achieved by defining types of cryptographic "engines" (services), and defining classes that provide the functionality of these cryptographic engines. These classes are called engine classes, and examples are the MessageDigest, Signature, KeyFactory, KeyPairGenerator, and Cipher classes.
Implementation independence is achieved using a "provider"-based architecture. The term Cryptographic Service Provider (CSP), which is used interchangeably with the term "provider," (see Cryptographic Service Providers) refers to a package or set of packages that implement one or more cryptographic services, such as digital signature algorithms, message digest algorithms, and key conversion services. A program may simply request a particular type of object (such as a Signature
object) implementing a particular service (such as the DSA signature algorithm) and get an implementation from one of the installed providers. If desired, a program may instead request an implementation from a specific provider. Providers may be updated transparently to the application, for example when faster or more secure versions are available.
Implementation interoperability means that various implementations can work with each other, use each other's keys, or verify each other's signatures. This would mean, for example, that for the same algorithms, a key generated by one provider would be usable by another, and a signature generated by one provider would be verifiable by another.
Algorithm extensibility means that new algorithms that fit in one of the supported engine classes can be added easily.
Provider Architecture
Providers contain a package (or a set of packages) that supply concrete implementations for the advertised cryptographic algorithms.
Cryptographic Service Providers
java.security.Provider
is the base class for all security providers. Each CSP contains an instance of this class which contains the provider's name and lists all of the security services/algorithms it implements. When an instance of a particular algorithm is needed, the JCA framework consults the provider's database, and if a suitable match is found, the instance is created.
Providers contain a package (or a set of packages) that supply concrete implementations for the advertised cryptographic algorithms. Each JDK installation has one or more providers installed and configured by default. Additional providers may be added statically or dynamically. Clients may configure their runtime environment to specify the provider preference order. The preference order is the order in which providers are searched for requested services when no specific provider is requested.
To use the JCA, an application simply requests a particular type of object (such as a MessageDigest
) and a particular algorithm or service (such as the "SHA-256" algorithm), and gets an implementation from one of the installed providers. For example, the following statement requests a SHA-256 message digest from an installed provider:
md = MessageDigest.getInstance("SHA-256");
Alternatively, the program can request the objects from a specific provider. Each provider has a name used to refer to it. For example, the following statement requests a SHA-256 message digest from the provider named ProviderC:
md = MessageDigest.getInstance("SHA-256", "ProviderC");
The following figures illustrates requesting an SHA-256 message digest implementation. They show three different providers that implement various message digest algorithms (SHA-256, SHA-384, and SHA-512). The providers are ordered by preference from left to right (1-3). In Figure 2-1, an application requests a SHA-256 algorithm implementation without specifying a provider name. The providers are searched in preference order and the implementation from the first provider supplying that particular algorithm, ProviderB, is returned. In Figure 2-2, the application requests the SHA-256 algorithm implementation from a specific provider, ProviderC. This time, the implementation from ProviderC is returned, even though a provider with a higher preference order, ProviderB, also supplies an SHA-256 implementation.
Figure 2-1 Request SHA-256 Message Digest Implementation Without Specifying Provider

Description of "Figure 2-1 Request SHA-256 Message Digest Implementation Without Specifying Provider"
Figure 2-2 Request SHA-256 Message Digest with ProviderC

Description of "Figure 2-2 Request SHA-256 Message Digest with ProviderC"
Cryptographic implementations in the JDK are distributed via several different providers (Sun
, SunJSSE
, SunJCE
, SunRsaSign
) primarily for historical reasons, but to a lesser extent by the type of functionality and algorithms they provide. Other Java runtime environments may not necessarily contain these providers, so applications should not request a provider-specific implementation unless it is known that a particular provider will be available.
The JCA offers a set of APIs that allow users to query which providers are installed and what services they support.
This architecture also makes it easy for end-users to add additional providers. Many third party provider implementations are already available. See The Provider Class for more information on how providers are written, installed, and registered.
How Providers Are Actually Implemented
Algorithm independence is achieved by defining a generic high-level Application Programming Interface (API) that all applications use to access a service type. Implementation independence is achieved by having all provider implementations conform to well-defined interfaces. Instances of engine classes are thus "backed" by implementation classes which have the same method signatures. Application calls are routed through the engine class and are delivered to the underlying backing implementation. The implementation handles the request and returns the proper results.
The application API methods in each engine class are routed to the provider's implementations through classes that implement the corresponding Service Provider Interface (SPI). That is, for each engine class, there is a corresponding abstract SPI class which defines the methods that each cryptographic service provider's algorithm must implement. The name of each SPI class is the same as that of the corresponding engine class, followed by Spi
. For example, the Signature
engine class provides access to the functionality of a digital signature algorithm. The actual provider implementation is supplied in a subclass of SignatureSpi
. Applications call the engine class' API methods, which in turn call the SPI methods in the actual implementation.
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.
For each engine class in the API, implementation instances are requested and instantiated by calling the getInstance() factory method in the engine class. A factory method is a static method that returns an instance of a class. The engine classes use the framework provider selection mechanism described previously to obtain the actual backing implementation (SPI), and then creates the actual engine object. Each instance of the engine class encapsulates (as a private field) the instance of the corresponding SPI class, known as 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.
To make this clearer, review Example 2-1 and Figure 2-3:
Example 2-1 Sample Code for Getting an Instance of an Engine Class
Cipher c = Cipher.getInstance("AES");
c.init(ENCRYPT_MODE, key);
Figure 2-3 Application Retrieves “AES” Cipher Instance

Description of "Figure 2-3 Application Retrieves “AES” Cipher Instance"
Here an application wants an "AES" javax.crypto.Cipher
instance, and doesn't care which provider is used. The application calls the getInstance()
factory methods of the Cipher
engine class, which in turn asks the JCA framework to find the first provider instance that supports "AES". The framework consults each installed provider, and obtains the provider's instance of the Provider
class. (Recall that the Provider
class is a database of available algorithms.) The framework searches each provider, finally finding a suitable entry in CSP3. This database entry points to the implementation class com.foo.AESCipher
which extends CipherSpi
, and is thus suitable for use by the Cipher
engine class. An instance of com.foo.AESCipher
is created, and is encapsulated in a newly-created instance of javax.crypto.Cipher
, which is returned to the application. When the application now does the init() operation on the Cipher
instance, the Cipher
engine class routes the request into the corresponding engineInit() backing method in the com.foo.AESCipher
class.