-
Type:
Sub-task
-
Resolution: Withdrawn
-
Priority:
P4
-
None
-
Affects Version/s: None
-
Component/s: security-libs
Summary
-------
Create a Java [cryptographic provider](https://docs.oracle.com/en/java/javase/25/security/java-cryptography-architecture-jca-reference-guide.html#GUID-3E0744CE-6AC7-4A6D-A1F6-6C01199E6920) that wraps a [FIPS 140](https://en.wikipedia.org/wiki/FIPS_140) certified cryptographic module, and make it available to Oracle customers.
Goals
-----
* Allow Java applications to access cryptographic functions implemented by a [FIPS 140-3](https://en.wikipedia.org/wiki/FIPS_140-3) certified cryptographic module so that they do not need to use third-party certified providers.
* Provide performance similar to the JDK’s [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313).
* Support Linux/x64 and Linux/AArch64 on mainline JDK.
Non-Goals
---------
* It is not a goal to implement higher-level functionality such as the [KeyStore API](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyStore.html) or a TLS protocol stack, in accordance with restrictions documented in the FIPS 140 standards.
* It is not a goal to allow the provider to be configured to support operations that are not allowed by the FIPS 140 standards.
* It is not a goal to support non-Oracle Java runtimes.
Motivation
----------
The [Federal Information Processing Standards](https://www.nist.gov/standardsgov/compliance-faqs-federal-information-processing-standards-fips) (FIPS) are published by the United States [National Institute of Standards and Technology](https://www.nist.gov/) (NIST). Government agencies in the United States must comply with the [Federal Information Security Management Act](https://www.cisa.gov/topics/cyber-threats-and-advisories/federal-information-security-modernization-act) (FISMA), which mandates the use of FIPS. Private sector companies with government contracts must also comply with FISMA. Various compliance programs, such as the [Federal Risk and Authorization Management Program](https://www.fedramp.gov) (FedRAMP) also mandate the use of FIPS. Finally, other jurisdictions with strong information security programs also require adherence to the FIPS standards.
The FIPS 140 standards define security requirements for cryptographic modules. As part of the [Cryptographic Module Validation Program](https://csrc.nist.gov/projects/cryptographic-module-validation-program), accredited laboratories certify that cryptographic modules meet the FIPS 140 security requirements. Applications deployed to FIPS 140 regulated environments may only use FIPS 140 approved or allowed cryptography provided by certified cryptographic modules.
The JDK’s [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313) are not certified to comply with the FIPS 140 standards. Thus Java applications deployed to FIPS 140 regulated environments must use certified providers from third parties. This approach has two drawbacks:
* Third-party providers can be significantly slower than the JDK’s built-in providers. The latter, being part of the JDK, benefit from the [intrinsification](https://github.com/openjdk/jdk/blob/jdk-25-ga/src/java.base/share/classes/jdk/internal/vm/annotation/IntrinsicCandidate.java#L31,L46) of low-level operations by native-code compilers such as HotSpot's C2. This allows them to take advantage of hardware instructions specifically designed to perform cryptographic operations efficiently, such as those in Intel's [AES-NI](https://en.wikipedia.org/wiki/AES_instruction_set) instruction set. Third-party providers cannot benefit from intrinsification. Those that do not employ native code to access architecture-specific hardware instructions can be tens of times slower than the JDK providers.
* Procuring a FIPS 140 certified provider from a separate vendor brings additional contracts as well as ongoing costs and support interactions.
Customers who work in FIPS 140 regulated environments would be better served by a solution that is as efficient as the JDK’s built-in providers and that is created and supported by Oracle.
Description
-----------
We propose to create a FIPS 140 cryptographic provider, named `JipherJCE`, which addresses FIPS certification requirements by wrapping an embedded copy of OpenSSL's [FIPS module](https://docs.openssl.org/3.0/fips/).
[OpenSSL](https://en.wikipedia.org/wiki/OpenSSL) is a widely used commercial-grade native-code cryptographic library that is FIPS 140 certified. `JipherJCE` will not itself need to be certified because its essential function is to map Java cryptography API calls to calls into the OpenSSL FIPS module via the [Foreign Function & Memory API](https://openjdk.org/jeps/454) (FFM).
OpenSSL's native code uses architecture-specific hardware instructions specifically designed to perform cryptographic operations efficiently. `JipherJCE` thus benefits from hardware acceleration without relying on intrinsification by Java native-code compilers.
### Algorithms supported
`JipherJCE` provides implementations of the following cryptographic classes with the following named algorithms:
* [AlgorithmParameters](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameters.html) — `AES`, `DESede`, `DiffieHellman`, `DSA`, `EC`, `GCM`, `OAEP`, `PBE`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `PBES2`, `RSASSA-PSS`
* [AlgorithmParameterGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameterGenerator.html) — `DSA`
* [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) — `AES` (modes: CBC, CFB, CTR, ECB, GCM, OFB), `AESWrap`, `AESWrapPad`, `DESede`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `RSA`
* [KeyAgreement](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyAgreement.html) — `DiffieHellman`, `ECDH`
* [KeyFactory](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html) — `DiffieHellman`, `DSA`, `EC`, `RSA`, `RSASSA-PSS`
* [KeyGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyGenerator.html) — `AES`, `DESede`, `Hmac<digest>`, `SunTls12Prf`, `SunTlsExtendedMasterSecret`, `SunTlsKeyMaterial`, `SunTlsMasterSecret`, `SunTlsRsaPremasterSecret`
* [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) — `DiffieHellman`, `DSA`, `EC`, `RSA`, `RSASSA-PSS`
* [Mac](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Mac.html) — `Hmac<digest>`, `HmacPBE<digest>`
* [MessageDigest](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/MessageDigest.html) — `SHA-1`, `SHA-224`, `SHA-256`, `SHA-384`, `SHA-512`, `SHA3-224`, `SHA3-256`, `SHA3-384`, `SHA3-512`
* [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) — `DRBG`
* [SecretKeyFactory](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKeyFactory.html) — `AES`, `DESede`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `PBKDF2With<prf>`
* [Signature](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Signature.html) — `NONEwithRSA`, `<digest>withRSA`, `<digest>withRSAandMGF1`, `RSASSA-PSS`, `NONEwithDSA`, `<digest>withDSA`, `NONEwithECDSA`, `<digest>withECDSA`
Where:
* `<prf>` is any of `HmacSHA1`, `HmacSHA224`, `HmacSHA384`, or `HmacSHA512`,
* `<encryption>` is any of `AES_128` or `AES_256`, and
* `<digest>` is any of `SHA1`, `SHA224`, `SHA384`, or `SHA512`.
The AES Cipher modes `CBC` and `ECB`, and the DES Cipher mode `CBC`, support `PKCS5Padding`.
The RSA Cipher supports the paddings `OAEPPadding` and `OAEPWith<digest>AndMGF1Padding`, where `<digest>` is any of `SHA-1`, `SHA-224`, `SHA-256`, `SHA-384`, or `SHA-512`.
Aliases and OIDs corresponding to the [Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/25/docs/specs/security/standard-names.html) listed above are supported by `JipherJCE` if they are supported by the JDK providers.
`SunTls12Prf`, `SunTlsExtendedMasterSecret`, `SunTlsKeyMaterial`, `SunTlsMasterSecret` and `SunTlsRsaPremasterSecret` are non-standard [KeyGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyGenerator.html) algorithms that are required by the built-in `SunJSSE` provider.
[SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) `DRBG` instances provided by `JipherJCE` use the underlying deterministic random bit generator algorithm in OpenSSL, which generates random bits with a [security strength](https://csrc.nist.gov/glossary/term/security_strength) of 256 bits.
The built-in `SUN` provider supports SecureRandom algorithms named `SHA1PRNG`, `NativePRNG`, and `NativePRNGNonBlocking`. `JipherJCE` treats these names as aliases for `DRBG` so that applications that request these algorithms but do not specify a provider can easily be migrated to use `JipherJCE`.
### Deployment
`JipherJCE` is packaged in a signed JAR file named `jipher-jce-<version>.jar`, where `<version>` is a version string. An application that uses `JipherJCE` must include this JAR file on its class path or on its module path. When placed on the module path, it will be observable as the module `com.oracle.jipher`.
The Java cryptography framework authenticates security providers by verifying the JAR file's signature at run time. Consequently, the content of the `jipher-jce` JAR cannot be extracted and incorporated in an Über-JAR to simplify deployment.
### Native libraries in the `jipher-jce` JAR file
OpenSSL is a native-code library, but JAR files do not support native code directly. The single `jipher-jce` JAR file therefore embeds four native-code shared libraries as resources, two for each supported platform. The first time a given class loader loads `JipherJCE`, the two libraries for the local platform are extracted to a temporary directory in the filesystem and loaded from there into the JVM process. The files are then [unlinked](https://man7.org/linux/man-pages/man2/unlink.2.html) and the temporary directory removed, resulting in anonymous files that persist until the JVM process exits.
By default, the temporary directory is created in the directory named by the system property `java.io.tmpdir`. The system property `jipher.user.dir`, if set, overrides the default parent directory. These system properties should be used to select a parent directory that the user running the JVM process can write to, and that is not in a filesystem mounted with the [noexec](https://linux.die.net/man/8/mount) option.
### Independence from, and coexistence with, other instances of OpenSSL
`JipherJCE` explicitly loads the OpenSSL native-code libraries embedded in the `jipher-jce` JAR file. It is therefore independent of any other instance of OpenSSL present on the system, including any instance that is part of the operating-system distribution. The embedded libraries do not export any symbols from the OpenSSL library, so there will be no symbol clashes in a process that uses `JipherJCE` and also loads another instance of OpenSSL.
### Registration
`JipherJCE` can be registered as a security provider either statically or dynamically.
* Register it statically by modifying the JDK's built-in security properties file, `java.security`, or by providing an alternate security properties file via the system property [java.security.properties](https://github.com/openjdk/jdk/blob/jdk-21-ga/src/java.base/share/conf/security/java.security#L4-L19).
In the security properties file, list `JipherJCE` in the registered provider list as:
```
security.provider.<n>=com.oracle.jipher.provider.JipherJCE
```
where `<n>` is the preference order for the provider. See the [documentation](https://github.com/openjdk/jdk/blob/jdk-21-ga/src/java.base/share/conf/security/java.security#L44-L50) for more information.
* Register it dynamically by either inserting `JipherJCE` at a specified position in the list of registered providers:
```
java.security.Security.insertProviderAt(new com.oracle.jipher.provider.JipherJCE(),
position);
```
or by appending it to the list of registered providers:
```
java.security.Security.addProvider(new com.oracle.jipher.provider.JipherJCE());
```
Whether registered statically or dynamically, if `JipherJCE` is registered as the highest priority provider, i.e., at position 1 in the list of registered providers, then the lower-level cryptographic primitives it provides are automatically used by higher-level services such as the [KeyStore](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyStore.html) and [SSLContext](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/net/ssl/SSLContext.html) providers.
### Configuration via system properties
The following system properties can be used to configure `JipherJCE`:
* [java.security.debug](https://docs.oracle.com/en/java/javase/25/security/troubleshooting-security.html) — If the value of this property includes `"jipher"` or `"all"` then debug logging via [System.err](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html#err) is enabled in `JipherJCE`.
* [java.io.tmpdir](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html#java.io.tmpdir) — The directory in which to create temporary directories for the extraction of native libraries, if `jipher.user.dir` is not set.
* `jipher.user.dir` — If set, the directory in which to create temporary directories for the extraction of native libraries.
* `jipher.fips.enforcement` — The FIPS 140 enforcement policy to be applied, one of:
* `FIPS`, the default, which enforces current FIPS guidance but allows for legacy usage, or
* `FIPS_STRICT`, which enforces current FIPS guidance and does not allow for legacy usage.
* <a id="stream"/> `jipher.cipher.AEAD.stream` — Configures the streaming mode of AES/GCM [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) objects.
* When set to `false`, which is the default, ciphertext passed to each `Cipher.update` call is internally buffered. The buffered ciphertext is later processed during the `Cipher.doFinal` call. Authenticated recovered plaintext is returned if the AEAD tag is validated, otherwise an [AEADBadTagException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/AEADBadTagException.html) is thrown.
* When set to `true`, ciphertext passed to each `Cipher.update` call is processed immediately to produce unauthenticated recovered plaintext. If the later `Cipher.doFinal` call fails to validate the AEAD tag then a [SecurityException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/SecurityException.html) is thrown with the detail message `"Authentication tag does not match"`. Applications should respond to this exception by discarding any unauthenticated recovered plaintext obtained from earlier `Cipher.update` method calls.
* `jipher.fips.deactivateSecurityPatches` — `JipherJCE` embeds two copies of the native-code OpenSSL FIPS module:
1. The latest available version of the module that has been FIPS 140 certified, and
2. A version of that module built from the same source code, but with additional security patches applied.
By default, `JipherJCE` prioritizes security over compliance and uses the second module, with the additional security patches. If the system property `jipher.fips.deactivateSecurityPatches` has the value `true` then `JipherJCE` prioritizes compliance over security and uses the first module.
> **Setting `jipher.fips.deactivateSecurityPatches` to `true` will make published security vulnerabilities exploitable.**
### Enforcing FIPS 140 restrictions
`JipherJCE` enforces FIPS 140 restrictions. It throws an [InvalidParameterException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidParameterException.html) if directed to generate
* A [SecretKey](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKey.html) or [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 112 bits;
* A DSA [AlgorithmParameters](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameters.html) or a DSA [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html)
using domain parameters with sizes other that those allowed by FIPS 140, which are (P=2048,Q=224), (P=2048,Q=256), and (P=3072,Q=256);
* A Diffie-Hellman [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) using domain parameters that are not a FIPS 140 approved safe prime group (see Appendix D of [NIST SP 800-56A Rev. 3](https://csrc.nist.gov/pubs/sp/800/56/a/r3/final)); or
* An elliptic curve [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html)
using a curve that is not a FIPS 140 approved `secp` curve (see Appendix D of [NIST SP 800-56A Rev. 3](https://csrc.nist.gov/pubs/sp/800/56/a/r3/final)).
Similarly, it throws a [java.security.ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) if directed to use
* A [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 80 bits to process secured data;
* A [SecretKey](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKey.html) or [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 112 bits to process secure data;
* `SHA-1` to generate a signature; or
* A DSA [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) that does not use domain parameters allowed by FIPS 140 (listed above).
(See *Table 2: Comparable security strengths of symmetric block cipher and asymmetric-key algorithms* in [NIST SP 800-57 Part 1 Rev. 5](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final) for the estimated security strengths of specific algorithms and key lengths.)
### Reporting misconfiguration
If `JipherJCE` cannot extract the embedded native libraries to a temporary directory in the filesystem, and load them from there into the JVM process, then it throws a [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html). This can happen if the user running the JVM process does not have permission to create the temporary directory, or to execute binaries stored in the encompassing filesystem.
If `JipherJCE` is statically registered and a [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) is thrown when loading the native libraries then the provider will not be registered. Other statically registered providers will still be registered.
### Reporting abnormal operation
An error condition that arises in OpenSSL native code is reported to the application via
* A [java.lang.Error](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Error.html), such as [java.lang.OutOfMemoryError](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/OutOfMemoryError.html);
* A [java.lang.RuntimeException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/RuntimeException.html), either [java.lang.ArrayIndexOutOfBoundsException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ArrayIndexOutOfBoundsException.html) or [java.lang.IllegalArgumentException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/IllegalArgumentException.html), indicating a programming error; or
* A [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) whose chained cause is an internal `OpenSslException` whose detail message describes the OpenSSL error stack for use in debugging and troubleshooting.
### Differences between `JipherJCE` and the JDK's built-in providers
* _Sourcing cryptographically secure random bits_ — The Java cryptography API includes the [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) class, which generates cryptographically secure random bits either by using a pseudo-random number generator or by reading a native source of randomness.
Cryptographic class instances provided by the built-in `SunJCE` provider can be configured with a specific source of randomness by passing a [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) instance to their initialization methods.
Cryptographic class instances provided by `JipherJCE` that support initialization methods that accept a [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) parameter **do not** use that parameter as their source of randomness. They instead source randomness from the DRBG in the embedded OpenSSL library, which generates random bits with a [security strength](https://csrc.nist.gov/glossary/term/security_strength) of 256 bits.
* _Automatic reset on `Cipher.doFinal`_ — The specification of the [Cipher.doFinal](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html#doFinal()) method states:
> Upon finishing, this method resets this `Cipher` object to the state it was in when previously initialized via a call to `init`. That is, the object is reset and available to encrypt or decrypt (depending on the operation mode that was specified in the call to `init`) more data.
`JipherJCE` supports the specified reset behavior during encryption only for the `CBC` mode, and during decryption for all modes except `CTR`, `GCM`, and `OFB`.
If a mode does not support the specified reset behavior then calling a `Cipher.update` or `Cipher.doFinal` method, after calling a `Cipher.doFinal` method but before calling a `Cipher.init` method once more, will cause an [IllegalStateException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/IllegalStateException.html) with the detail message `"Not initialized"` to be thrown.
* _Diffie–Hellman (DH) keys_ — The [initialize(AlgorithmParameterSpec)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html#initialize(java.security.spec.AlgorithmParameterSpec)) method of a `DiffieHellman` [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) instance can take a
[DHParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/DHParameterSpec.html).
Unlike `SunJCE`, `JipherJCE` silently ignores the size in bits, `l`, of the random exponent (private value) optionally specified in the [DHParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/DHParameterSpec.html).
* _DSA keys_ — Unlike the `SUN` provider, the `JipherJCE` [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) for the DSA algorithm does not implement the [DSAKeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/interfaces/DSAKeyPairGenerator.html) interface.
* _RSA keys_ — Unlike the built-in `SunRsaSign` and `SunJCE` providers, `JipherJCE` does not support importing a representation of an RSA key, and does not support using an RSA key that does not include the public key component. Specifically:
* Passing either an [RSAPrivateKeySpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/RSAPrivateKeySpec.html), or a [PKCS8EncodedKeySpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/PKCS8EncodedKeySpec.html) that carries an encoding of an RSA private key that does not include the public key component, to the [KeyFactory.generatePrivate(KeySpec)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html#generatePrivate(java.security.spec.KeySpec)) method causes an [InvalidKeySpecException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/InvalidKeySpecException.html) to be thrown.
* Passing an RSA private [Key](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Key.html) that does not include the public key component to [Key.translateKey(Key)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html#translateKey(java.security.Key)) causes an [InvalidKeyException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidKeyException.html) to be thrown.
* Initializing a `JipherJCE` [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) or [Signature](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Signature.html) instance with an RSA private [Key](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Key.html) that does not include a public key component causes an [InvalidKeyException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidKeyException.html) to be thrown.
* _AES key wrap and unwrap integrity check values (ICV)_ — Unlike `SunJCE`, `JipherJCE` supports only the default ICVs specified in [NIST Special Publication 800-38F](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf).
Passing an [IvParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/IvParameterSpec.html) to an `init` method of an AES key wrap or unwrap [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) instance provided by
`JipherJCE` causes an [InvalidAlgorithmParameterException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidAlgorithmParameterException.html) to be thrown.
* _AES GCM initialization vector (IV) size_ — Unlike `SunJCE`, `JipherJCE` imposes a maximum AES GCM IV size of 1024 bits (128 bytes).
* _NIST algorithm AES OIDs for CBC modes_ — The [NIST algorithm AES OIDs](http://oid-info.com/get/2.16.840.1.101.3.4.1) for the [CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)) modes
* [2.16.840.1.101.3.4.1.2](http://oid-info.com/get/2.16.840.1.101.3.4.1.2),
* [2.16.840.1.101.3.4.1.22](http://oid-info.com/get/2.16.840.1.101.3.4.1.22), and
* [2.16.840.1.101.3.4.1.42](http://oid-info.com/get/2.16.840.1.101.3.4.1.42)
are implemented by the `SunJCE` provider as Cipher transformations that do not perform padding. It assumes that the input data is pre-padded to a multiple of the block size.
The `JipherJCE` provider implements these OIDs as Cipher transformations that perform [PKCS #7 padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS#5_and_PKCS#7).
Using a `SunJCE` implementation of one these OIDs to encrypt some plaintext and then using a `JipherJCE` implementation of the same OID to decrypt the resulting ciphertext will likely cause a [BadPaddingException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/BadPaddingException.html) to be thrown.
Using a `JipherJCE` implementation of one these OIDs to encrypt some plaintext and then using the `SunJCE` provider's implementation of the same OID to decrypt the ciphertext will result in incorrect recovered text. The recovered text will include up to one additional block of padding.
* _Using `JipherJCE` with the `SunJSSE` provider_ — If `JipherJCE` is registered as the highest priority provider, i.e., at position 1 in the list of registered providers, then the lower-level cryptographic primitives it provides will automatically be used by the `SunJSSE` provider.
Any provider that underpins `SunJSSE` must access these internal JDK classes:
* [sun.security.internal.spec.TlsKeyMaterialParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java),
* [sun.security.internal.spec.TlsMasterSecretParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java),
* [sun.security.internal.spec.AlgorithmParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java), and
* [sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java).
Internal JDK classes are [strongly encapsulated by default](https://openjdk.org/jeps/396). Consequently, if `JipherJCE` accesses any of these classes, an [IllegalAccessException](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/IllegalAccessException.html) is thrown.
This can be avoided by adding a directive to the `java` launcher command line. If the `jipher-jce` JAR file is on the class path:
```
--add-exports=java.base/sun.security.internal.spec=ALL-UNNAMED
```
Otherwise, if the JAR file is on the module path:
```
--add-exports=java.base/sun.security.internal.spec=com.oracle.jipher
```
### Differences between `JipherJCE` and other FIPS providers
- _FIPS 140 enforcement_ — By default, the [Bouncy Castle FIPS provider](https://www.bouncycastle.org/download/bouncy-castle-java-fips/) (`BCFIPS`) provides cryptographic functions that are not approved in the FIPS 140 standard. It can be configured to provide only FIPS 140 approved functions.
Unlike `BCFIPS`, `JipherJCE` provides only FIPS 140 approved cryptographic functions. It requires no configuration to activate FIPS 140 enforcement.
- _Providing access to unauthenticated recovered plaintext_ — By default, `BCFIPS` processes ciphertext passed to the `Cipher.update` method immediately to produce unauthenticated recovered plaintext, before the AEAD tag is validated.
Unlike `BCFIPS`, `JipherJCE`, by default, buffers such ciphertext, producing authenticated recovered plaintext only after the AEAD tag is validated. The system property `jipher.cipher.AEAD.stream` can be used to request the `BCFIPS` behavior, as described [above](#stream).
### Thread safety
`JipherJCE` implementations of the [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) class are safe for use by multiple concurrent threads, as are all key and domain parameters.
Otherwise, `JipherJCE`-provided cryptographic objects are not safe for use by multiple concurrent threads.
Future Work
-----------
* _Support additional platforms_ — macOS/AArch64, macOS/x64, and Windows/x64.
* _Support additional JDK versions_ — JDK 11 and, possibly, JDK 8.
* _FIPS 140-3_ — Transition to a [FIPS 140-3](https://en.wikipedia.org/wiki/FIPS_140-3) certified cryptographic module.
Alternatives
------------
We could, instead, submit the JDK's [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313) for certification as a FIPS 140 cryptographic module. Doing so would require us to:
* Define the cryptographic module boundary, which would be challenging since the JDK providers rely on classes throughout the JDK, and they leverage intrinsification for performance;
* Define a testing interface so that a certification laboratory can run test vectors against the cryptographic module, obtain intermediate values not normally exposed via the public API, and inject errors not normally achievable via the public API;
* Potentially update cryptographic algorithm implementations to comply with FIPS 140 requirements, which would require devising a means to preserve existing behavior for compatibility; and
* Spend a significant sum of money to hire a certification laboratory, and then spend a significant amount of time interacting with the laboratory.
It is more efficient to create a cryptographic provider that simply wraps an existing certified cryptographic module.
Testing
-------
Since `JipherJCE` uses native code, namely the OpenSSL FIPS module, we must build and test it on each supported platform.
### Functional testing
* `JipherJCE` must pass a suite of API (integration) tests that use test vectors, generated using the JDK providers and third-party Java cryptographic providers, to ensure that it produces the same output as other providers when performing the same operation on the same inputs.
* `JipherJCE` must pass a copy of the [jdk_security](https://github.com/openjdk/jdk/blob/jdk-21-ga/test/jdk/TEST.groups#L236) JDK regression test group which has been modified so that
* Tests use only FIPS 140-2 allowed key sizes, domain parameters, and algorithms;
* Tests name `JipherJCE` as the provider of cryptographic services instead of the JDK providers; and
* The default security provider list contains `JipherJCE` as the highest priority provider.
### Stability testing
* `JipherJCE` must pass all of the integration tests while using a leak-detecting native memory allocator.
### Performance testing
* The performance of `JipherJCE` should be similar to or better than the JDK's built-in providers, as measured by microbenchmarks using [JMH](https://github.com/openjdk/jmh).
There is some overhead in creating OpenSSL objects to process data, and in forwarding application data to these OpenSSL objects via FFM. For operations that process a variable amount of data, the relative performance of `JipherJCE` is a function of the amount of data processed. Processing small amounts of data using a low-cost operation, e.g., digesting two bytes, is significantly slower with `JipherJCE` than with the JDK's providers. Processing larger quantities of data should have similar or better performance than the JDK's providers.
* The performance of `JipherJCE` should be better than pure-Java third-party FIPS certified Java cryptographic service providers, as measured by the same microbenchmarks. It should be more than ten times better when OpenSSL takes advantage of processor instructions specifically designed to perform cryptographic operations efficiently.
Risks and Assumptions
---------------------
`JipherJCE` calls into native code, namely the OpenSSL FIPS module. Loading native code into the JVM and running it makes the JVM vulnerable to security and stability flaws in the native code.
These risks are mitigated by the following factors:
* OpenSSL is a mature code base. Its binaries are widely deployed and tested for stability and security issues.
* The FFM interface to OpenSSL is lean and carefully scrutinized for stability and security issues.
* We will perform stress testing to help identify any security or memory management issues.
-------
Create a Java [cryptographic provider](https://docs.oracle.com/en/java/javase/25/security/java-cryptography-architecture-jca-reference-guide.html#GUID-3E0744CE-6AC7-4A6D-A1F6-6C01199E6920) that wraps a [FIPS 140](https://en.wikipedia.org/wiki/FIPS_140) certified cryptographic module, and make it available to Oracle customers.
Goals
-----
* Allow Java applications to access cryptographic functions implemented by a [FIPS 140-3](https://en.wikipedia.org/wiki/FIPS_140-3) certified cryptographic module so that they do not need to use third-party certified providers.
* Provide performance similar to the JDK’s [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313).
* Support Linux/x64 and Linux/AArch64 on mainline JDK.
Non-Goals
---------
* It is not a goal to implement higher-level functionality such as the [KeyStore API](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyStore.html) or a TLS protocol stack, in accordance with restrictions documented in the FIPS 140 standards.
* It is not a goal to allow the provider to be configured to support operations that are not allowed by the FIPS 140 standards.
* It is not a goal to support non-Oracle Java runtimes.
Motivation
----------
The [Federal Information Processing Standards](https://www.nist.gov/standardsgov/compliance-faqs-federal-information-processing-standards-fips) (FIPS) are published by the United States [National Institute of Standards and Technology](https://www.nist.gov/) (NIST). Government agencies in the United States must comply with the [Federal Information Security Management Act](https://www.cisa.gov/topics/cyber-threats-and-advisories/federal-information-security-modernization-act) (FISMA), which mandates the use of FIPS. Private sector companies with government contracts must also comply with FISMA. Various compliance programs, such as the [Federal Risk and Authorization Management Program](https://www.fedramp.gov) (FedRAMP) also mandate the use of FIPS. Finally, other jurisdictions with strong information security programs also require adherence to the FIPS standards.
The FIPS 140 standards define security requirements for cryptographic modules. As part of the [Cryptographic Module Validation Program](https://csrc.nist.gov/projects/cryptographic-module-validation-program), accredited laboratories certify that cryptographic modules meet the FIPS 140 security requirements. Applications deployed to FIPS 140 regulated environments may only use FIPS 140 approved or allowed cryptography provided by certified cryptographic modules.
The JDK’s [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313) are not certified to comply with the FIPS 140 standards. Thus Java applications deployed to FIPS 140 regulated environments must use certified providers from third parties. This approach has two drawbacks:
* Third-party providers can be significantly slower than the JDK’s built-in providers. The latter, being part of the JDK, benefit from the [intrinsification](https://github.com/openjdk/jdk/blob/jdk-25-ga/src/java.base/share/classes/jdk/internal/vm/annotation/IntrinsicCandidate.java#L31,L46) of low-level operations by native-code compilers such as HotSpot's C2. This allows them to take advantage of hardware instructions specifically designed to perform cryptographic operations efficiently, such as those in Intel's [AES-NI](https://en.wikipedia.org/wiki/AES_instruction_set) instruction set. Third-party providers cannot benefit from intrinsification. Those that do not employ native code to access architecture-specific hardware instructions can be tens of times slower than the JDK providers.
* Procuring a FIPS 140 certified provider from a separate vendor brings additional contracts as well as ongoing costs and support interactions.
Customers who work in FIPS 140 regulated environments would be better served by a solution that is as efficient as the JDK’s built-in providers and that is created and supported by Oracle.
Description
-----------
We propose to create a FIPS 140 cryptographic provider, named `JipherJCE`, which addresses FIPS certification requirements by wrapping an embedded copy of OpenSSL's [FIPS module](https://docs.openssl.org/3.0/fips/).
[OpenSSL](https://en.wikipedia.org/wiki/OpenSSL) is a widely used commercial-grade native-code cryptographic library that is FIPS 140 certified. `JipherJCE` will not itself need to be certified because its essential function is to map Java cryptography API calls to calls into the OpenSSL FIPS module via the [Foreign Function & Memory API](https://openjdk.org/jeps/454) (FFM).
OpenSSL's native code uses architecture-specific hardware instructions specifically designed to perform cryptographic operations efficiently. `JipherJCE` thus benefits from hardware acceleration without relying on intrinsification by Java native-code compilers.
### Algorithms supported
`JipherJCE` provides implementations of the following cryptographic classes with the following named algorithms:
* [AlgorithmParameters](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameters.html) — `AES`, `DESede`, `DiffieHellman`, `DSA`, `EC`, `GCM`, `OAEP`, `PBE`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `PBES2`, `RSASSA-PSS`
* [AlgorithmParameterGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameterGenerator.html) — `DSA`
* [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) — `AES` (modes: CBC, CFB, CTR, ECB, GCM, OFB), `AESWrap`, `AESWrapPad`, `DESede`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `RSA`
* [KeyAgreement](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyAgreement.html) — `DiffieHellman`, `ECDH`
* [KeyFactory](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html) — `DiffieHellman`, `DSA`, `EC`, `RSA`, `RSASSA-PSS`
* [KeyGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyGenerator.html) — `AES`, `DESede`, `Hmac<digest>`, `SunTls12Prf`, `SunTlsExtendedMasterSecret`, `SunTlsKeyMaterial`, `SunTlsMasterSecret`, `SunTlsRsaPremasterSecret`
* [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) — `DiffieHellman`, `DSA`, `EC`, `RSA`, `RSASSA-PSS`
* [Mac](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Mac.html) — `Hmac<digest>`, `HmacPBE<digest>`
* [MessageDigest](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/MessageDigest.html) — `SHA-1`, `SHA-224`, `SHA-256`, `SHA-384`, `SHA-512`, `SHA3-224`, `SHA3-256`, `SHA3-384`, `SHA3-512`
* [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) — `DRBG`
* [SecretKeyFactory](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKeyFactory.html) — `AES`, `DESede`, `PBEWith<prf>And<encryption>`, `PBEWithSHA1AndDESede`, `PBKDF2With<prf>`
* [Signature](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Signature.html) — `NONEwithRSA`, `<digest>withRSA`, `<digest>withRSAandMGF1`, `RSASSA-PSS`, `NONEwithDSA`, `<digest>withDSA`, `NONEwithECDSA`, `<digest>withECDSA`
Where:
* `<prf>` is any of `HmacSHA1`, `HmacSHA224`, `HmacSHA384`, or `HmacSHA512`,
* `<encryption>` is any of `AES_128` or `AES_256`, and
* `<digest>` is any of `SHA1`, `SHA224`, `SHA384`, or `SHA512`.
The AES Cipher modes `CBC` and `ECB`, and the DES Cipher mode `CBC`, support `PKCS5Padding`.
The RSA Cipher supports the paddings `OAEPPadding` and `OAEPWith<digest>AndMGF1Padding`, where `<digest>` is any of `SHA-1`, `SHA-224`, `SHA-256`, `SHA-384`, or `SHA-512`.
Aliases and OIDs corresponding to the [Java Security Standard Algorithm Names](https://docs.oracle.com/en/java/javase/25/docs/specs/security/standard-names.html) listed above are supported by `JipherJCE` if they are supported by the JDK providers.
`SunTls12Prf`, `SunTlsExtendedMasterSecret`, `SunTlsKeyMaterial`, `SunTlsMasterSecret` and `SunTlsRsaPremasterSecret` are non-standard [KeyGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/KeyGenerator.html) algorithms that are required by the built-in `SunJSSE` provider.
[SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) `DRBG` instances provided by `JipherJCE` use the underlying deterministic random bit generator algorithm in OpenSSL, which generates random bits with a [security strength](https://csrc.nist.gov/glossary/term/security_strength) of 256 bits.
The built-in `SUN` provider supports SecureRandom algorithms named `SHA1PRNG`, `NativePRNG`, and `NativePRNGNonBlocking`. `JipherJCE` treats these names as aliases for `DRBG` so that applications that request these algorithms but do not specify a provider can easily be migrated to use `JipherJCE`.
### Deployment
`JipherJCE` is packaged in a signed JAR file named `jipher-jce-<version>.jar`, where `<version>` is a version string. An application that uses `JipherJCE` must include this JAR file on its class path or on its module path. When placed on the module path, it will be observable as the module `com.oracle.jipher`.
The Java cryptography framework authenticates security providers by verifying the JAR file's signature at run time. Consequently, the content of the `jipher-jce` JAR cannot be extracted and incorporated in an Über-JAR to simplify deployment.
### Native libraries in the `jipher-jce` JAR file
OpenSSL is a native-code library, but JAR files do not support native code directly. The single `jipher-jce` JAR file therefore embeds four native-code shared libraries as resources, two for each supported platform. The first time a given class loader loads `JipherJCE`, the two libraries for the local platform are extracted to a temporary directory in the filesystem and loaded from there into the JVM process. The files are then [unlinked](https://man7.org/linux/man-pages/man2/unlink.2.html) and the temporary directory removed, resulting in anonymous files that persist until the JVM process exits.
By default, the temporary directory is created in the directory named by the system property `java.io.tmpdir`. The system property `jipher.user.dir`, if set, overrides the default parent directory. These system properties should be used to select a parent directory that the user running the JVM process can write to, and that is not in a filesystem mounted with the [noexec](https://linux.die.net/man/8/mount) option.
### Independence from, and coexistence with, other instances of OpenSSL
`JipherJCE` explicitly loads the OpenSSL native-code libraries embedded in the `jipher-jce` JAR file. It is therefore independent of any other instance of OpenSSL present on the system, including any instance that is part of the operating-system distribution. The embedded libraries do not export any symbols from the OpenSSL library, so there will be no symbol clashes in a process that uses `JipherJCE` and also loads another instance of OpenSSL.
### Registration
`JipherJCE` can be registered as a security provider either statically or dynamically.
* Register it statically by modifying the JDK's built-in security properties file, `java.security`, or by providing an alternate security properties file via the system property [java.security.properties](https://github.com/openjdk/jdk/blob/jdk-21-ga/src/java.base/share/conf/security/java.security#L4-L19).
In the security properties file, list `JipherJCE` in the registered provider list as:
```
security.provider.<n>=com.oracle.jipher.provider.JipherJCE
```
where `<n>` is the preference order for the provider. See the [documentation](https://github.com/openjdk/jdk/blob/jdk-21-ga/src/java.base/share/conf/security/java.security#L44-L50) for more information.
* Register it dynamically by either inserting `JipherJCE` at a specified position in the list of registered providers:
```
java.security.Security.insertProviderAt(new com.oracle.jipher.provider.JipherJCE(),
position);
```
or by appending it to the list of registered providers:
```
java.security.Security.addProvider(new com.oracle.jipher.provider.JipherJCE());
```
Whether registered statically or dynamically, if `JipherJCE` is registered as the highest priority provider, i.e., at position 1 in the list of registered providers, then the lower-level cryptographic primitives it provides are automatically used by higher-level services such as the [KeyStore](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyStore.html) and [SSLContext](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/net/ssl/SSLContext.html) providers.
### Configuration via system properties
The following system properties can be used to configure `JipherJCE`:
* [java.security.debug](https://docs.oracle.com/en/java/javase/25/security/troubleshooting-security.html) — If the value of this property includes `"jipher"` or `"all"` then debug logging via [System.err](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html#err) is enabled in `JipherJCE`.
* [java.io.tmpdir](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html#java.io.tmpdir) — The directory in which to create temporary directories for the extraction of native libraries, if `jipher.user.dir` is not set.
* `jipher.user.dir` — If set, the directory in which to create temporary directories for the extraction of native libraries.
* `jipher.fips.enforcement` — The FIPS 140 enforcement policy to be applied, one of:
* `FIPS`, the default, which enforces current FIPS guidance but allows for legacy usage, or
* `FIPS_STRICT`, which enforces current FIPS guidance and does not allow for legacy usage.
* <a id="stream"/> `jipher.cipher.AEAD.stream` — Configures the streaming mode of AES/GCM [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) objects.
* When set to `false`, which is the default, ciphertext passed to each `Cipher.update` call is internally buffered. The buffered ciphertext is later processed during the `Cipher.doFinal` call. Authenticated recovered plaintext is returned if the AEAD tag is validated, otherwise an [AEADBadTagException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/AEADBadTagException.html) is thrown.
* When set to `true`, ciphertext passed to each `Cipher.update` call is processed immediately to produce unauthenticated recovered plaintext. If the later `Cipher.doFinal` call fails to validate the AEAD tag then a [SecurityException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/SecurityException.html) is thrown with the detail message `"Authentication tag does not match"`. Applications should respond to this exception by discarding any unauthenticated recovered plaintext obtained from earlier `Cipher.update` method calls.
* `jipher.fips.deactivateSecurityPatches` — `JipherJCE` embeds two copies of the native-code OpenSSL FIPS module:
1. The latest available version of the module that has been FIPS 140 certified, and
2. A version of that module built from the same source code, but with additional security patches applied.
By default, `JipherJCE` prioritizes security over compliance and uses the second module, with the additional security patches. If the system property `jipher.fips.deactivateSecurityPatches` has the value `true` then `JipherJCE` prioritizes compliance over security and uses the first module.
> **Setting `jipher.fips.deactivateSecurityPatches` to `true` will make published security vulnerabilities exploitable.**
### Enforcing FIPS 140 restrictions
`JipherJCE` enforces FIPS 140 restrictions. It throws an [InvalidParameterException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidParameterException.html) if directed to generate
* A [SecretKey](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKey.html) or [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 112 bits;
* A DSA [AlgorithmParameters](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/AlgorithmParameters.html) or a DSA [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html)
using domain parameters with sizes other that those allowed by FIPS 140, which are (P=2048,Q=224), (P=2048,Q=256), and (P=3072,Q=256);
* A Diffie-Hellman [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) using domain parameters that are not a FIPS 140 approved safe prime group (see Appendix D of [NIST SP 800-56A Rev. 3](https://csrc.nist.gov/pubs/sp/800/56/a/r3/final)); or
* An elliptic curve [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html)
using a curve that is not a FIPS 140 approved `secp` curve (see Appendix D of [NIST SP 800-56A Rev. 3](https://csrc.nist.gov/pubs/sp/800/56/a/r3/final)).
Similarly, it throws a [java.security.ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) if directed to use
* A [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 80 bits to process secured data;
* A [SecretKey](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/SecretKey.html) or [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) with a security strength of less than 112 bits to process secure data;
* `SHA-1` to generate a signature; or
* A DSA [KeyPair](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPair.html) that does not use domain parameters allowed by FIPS 140 (listed above).
(See *Table 2: Comparable security strengths of symmetric block cipher and asymmetric-key algorithms* in [NIST SP 800-57 Part 1 Rev. 5](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final) for the estimated security strengths of specific algorithms and key lengths.)
### Reporting misconfiguration
If `JipherJCE` cannot extract the embedded native libraries to a temporary directory in the filesystem, and load them from there into the JVM process, then it throws a [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html). This can happen if the user running the JVM process does not have permission to create the temporary directory, or to execute binaries stored in the encompassing filesystem.
If `JipherJCE` is statically registered and a [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) is thrown when loading the native libraries then the provider will not be registered. Other statically registered providers will still be registered.
### Reporting abnormal operation
An error condition that arises in OpenSSL native code is reported to the application via
* A [java.lang.Error](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Error.html), such as [java.lang.OutOfMemoryError](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/OutOfMemoryError.html);
* A [java.lang.RuntimeException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/RuntimeException.html), either [java.lang.ArrayIndexOutOfBoundsException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ArrayIndexOutOfBoundsException.html) or [java.lang.IllegalArgumentException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/IllegalArgumentException.html), indicating a programming error; or
* A [ProviderException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/ProviderException.html) whose chained cause is an internal `OpenSslException` whose detail message describes the OpenSSL error stack for use in debugging and troubleshooting.
### Differences between `JipherJCE` and the JDK's built-in providers
* _Sourcing cryptographically secure random bits_ — The Java cryptography API includes the [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) class, which generates cryptographically secure random bits either by using a pseudo-random number generator or by reading a native source of randomness.
Cryptographic class instances provided by the built-in `SunJCE` provider can be configured with a specific source of randomness by passing a [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) instance to their initialization methods.
Cryptographic class instances provided by `JipherJCE` that support initialization methods that accept a [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) parameter **do not** use that parameter as their source of randomness. They instead source randomness from the DRBG in the embedded OpenSSL library, which generates random bits with a [security strength](https://csrc.nist.gov/glossary/term/security_strength) of 256 bits.
* _Automatic reset on `Cipher.doFinal`_ — The specification of the [Cipher.doFinal](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html#doFinal()) method states:
> Upon finishing, this method resets this `Cipher` object to the state it was in when previously initialized via a call to `init`. That is, the object is reset and available to encrypt or decrypt (depending on the operation mode that was specified in the call to `init`) more data.
`JipherJCE` supports the specified reset behavior during encryption only for the `CBC` mode, and during decryption for all modes except `CTR`, `GCM`, and `OFB`.
If a mode does not support the specified reset behavior then calling a `Cipher.update` or `Cipher.doFinal` method, after calling a `Cipher.doFinal` method but before calling a `Cipher.init` method once more, will cause an [IllegalStateException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/IllegalStateException.html) with the detail message `"Not initialized"` to be thrown.
* _Diffie–Hellman (DH) keys_ — The [initialize(AlgorithmParameterSpec)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html#initialize(java.security.spec.AlgorithmParameterSpec)) method of a `DiffieHellman` [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) instance can take a
[DHParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/DHParameterSpec.html).
Unlike `SunJCE`, `JipherJCE` silently ignores the size in bits, `l`, of the random exponent (private value) optionally specified in the [DHParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/DHParameterSpec.html).
* _DSA keys_ — Unlike the `SUN` provider, the `JipherJCE` [KeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyPairGenerator.html) for the DSA algorithm does not implement the [DSAKeyPairGenerator](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/interfaces/DSAKeyPairGenerator.html) interface.
* _RSA keys_ — Unlike the built-in `SunRsaSign` and `SunJCE` providers, `JipherJCE` does not support importing a representation of an RSA key, and does not support using an RSA key that does not include the public key component. Specifically:
* Passing either an [RSAPrivateKeySpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/RSAPrivateKeySpec.html), or a [PKCS8EncodedKeySpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/PKCS8EncodedKeySpec.html) that carries an encoding of an RSA private key that does not include the public key component, to the [KeyFactory.generatePrivate(KeySpec)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html#generatePrivate(java.security.spec.KeySpec)) method causes an [InvalidKeySpecException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/spec/InvalidKeySpecException.html) to be thrown.
* Passing an RSA private [Key](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Key.html) that does not include the public key component to [Key.translateKey(Key)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/KeyFactory.html#translateKey(java.security.Key)) causes an [InvalidKeyException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidKeyException.html) to be thrown.
* Initializing a `JipherJCE` [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) or [Signature](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Signature.html) instance with an RSA private [Key](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Key.html) that does not include a public key component causes an [InvalidKeyException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidKeyException.html) to be thrown.
* _AES key wrap and unwrap integrity check values (ICV)_ — Unlike `SunJCE`, `JipherJCE` supports only the default ICVs specified in [NIST Special Publication 800-38F](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf).
Passing an [IvParameterSpec](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/spec/IvParameterSpec.html) to an `init` method of an AES key wrap or unwrap [Cipher](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/Cipher.html) instance provided by
`JipherJCE` causes an [InvalidAlgorithmParameterException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/InvalidAlgorithmParameterException.html) to be thrown.
* _AES GCM initialization vector (IV) size_ — Unlike `SunJCE`, `JipherJCE` imposes a maximum AES GCM IV size of 1024 bits (128 bytes).
* _NIST algorithm AES OIDs for CBC modes_ — The [NIST algorithm AES OIDs](http://oid-info.com/get/2.16.840.1.101.3.4.1) for the [CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)) modes
* [2.16.840.1.101.3.4.1.2](http://oid-info.com/get/2.16.840.1.101.3.4.1.2),
* [2.16.840.1.101.3.4.1.22](http://oid-info.com/get/2.16.840.1.101.3.4.1.22), and
* [2.16.840.1.101.3.4.1.42](http://oid-info.com/get/2.16.840.1.101.3.4.1.42)
are implemented by the `SunJCE` provider as Cipher transformations that do not perform padding. It assumes that the input data is pre-padded to a multiple of the block size.
The `JipherJCE` provider implements these OIDs as Cipher transformations that perform [PKCS #7 padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS#5_and_PKCS#7).
Using a `SunJCE` implementation of one these OIDs to encrypt some plaintext and then using a `JipherJCE` implementation of the same OID to decrypt the resulting ciphertext will likely cause a [BadPaddingException](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/crypto/BadPaddingException.html) to be thrown.
Using a `JipherJCE` implementation of one these OIDs to encrypt some plaintext and then using the `SunJCE` provider's implementation of the same OID to decrypt the ciphertext will result in incorrect recovered text. The recovered text will include up to one additional block of padding.
* _Using `JipherJCE` with the `SunJSSE` provider_ — If `JipherJCE` is registered as the highest priority provider, i.e., at position 1 in the list of registered providers, then the lower-level cryptographic primitives it provides will automatically be used by the `SunJSSE` provider.
Any provider that underpins `SunJSSE` must access these internal JDK classes:
* [sun.security.internal.spec.TlsKeyMaterialParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java),
* [sun.security.internal.spec.TlsMasterSecretParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java),
* [sun.security.internal.spec.AlgorithmParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java), and
* [sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec](https://github.com/openjdk/jdk/blob/jdk-17-ga/src/java.base/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java).
Internal JDK classes are [strongly encapsulated by default](https://openjdk.org/jeps/396). Consequently, if `JipherJCE` accesses any of these classes, an [IllegalAccessException](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/IllegalAccessException.html) is thrown.
This can be avoided by adding a directive to the `java` launcher command line. If the `jipher-jce` JAR file is on the class path:
```
--add-exports=java.base/sun.security.internal.spec=ALL-UNNAMED
```
Otherwise, if the JAR file is on the module path:
```
--add-exports=java.base/sun.security.internal.spec=com.oracle.jipher
```
### Differences between `JipherJCE` and other FIPS providers
- _FIPS 140 enforcement_ — By default, the [Bouncy Castle FIPS provider](https://www.bouncycastle.org/download/bouncy-castle-java-fips/) (`BCFIPS`) provides cryptographic functions that are not approved in the FIPS 140 standard. It can be configured to provide only FIPS 140 approved functions.
Unlike `BCFIPS`, `JipherJCE` provides only FIPS 140 approved cryptographic functions. It requires no configuration to activate FIPS 140 enforcement.
- _Providing access to unauthenticated recovered plaintext_ — By default, `BCFIPS` processes ciphertext passed to the `Cipher.update` method immediately to produce unauthenticated recovered plaintext, before the AEAD tag is validated.
Unlike `BCFIPS`, `JipherJCE`, by default, buffers such ciphertext, producing authenticated recovered plaintext only after the AEAD tag is validated. The system property `jipher.cipher.AEAD.stream` can be used to request the `BCFIPS` behavior, as described [above](#stream).
### Thread safety
`JipherJCE` implementations of the [SecureRandom](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/SecureRandom.html) class are safe for use by multiple concurrent threads, as are all key and domain parameters.
Otherwise, `JipherJCE`-provided cryptographic objects are not safe for use by multiple concurrent threads.
Future Work
-----------
* _Support additional platforms_ — macOS/AArch64, macOS/x64, and Windows/x64.
* _Support additional JDK versions_ — JDK 11 and, possibly, JDK 8.
* _FIPS 140-3_ — Transition to a [FIPS 140-3](https://en.wikipedia.org/wiki/FIPS_140-3) certified cryptographic module.
Alternatives
------------
We could, instead, submit the JDK's [built-in providers](https://docs.oracle.com/en/java/javase/25/security/oracle-providers.html#GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313) for certification as a FIPS 140 cryptographic module. Doing so would require us to:
* Define the cryptographic module boundary, which would be challenging since the JDK providers rely on classes throughout the JDK, and they leverage intrinsification for performance;
* Define a testing interface so that a certification laboratory can run test vectors against the cryptographic module, obtain intermediate values not normally exposed via the public API, and inject errors not normally achievable via the public API;
* Potentially update cryptographic algorithm implementations to comply with FIPS 140 requirements, which would require devising a means to preserve existing behavior for compatibility; and
* Spend a significant sum of money to hire a certification laboratory, and then spend a significant amount of time interacting with the laboratory.
It is more efficient to create a cryptographic provider that simply wraps an existing certified cryptographic module.
Testing
-------
Since `JipherJCE` uses native code, namely the OpenSSL FIPS module, we must build and test it on each supported platform.
### Functional testing
* `JipherJCE` must pass a suite of API (integration) tests that use test vectors, generated using the JDK providers and third-party Java cryptographic providers, to ensure that it produces the same output as other providers when performing the same operation on the same inputs.
* `JipherJCE` must pass a copy of the [jdk_security](https://github.com/openjdk/jdk/blob/jdk-21-ga/test/jdk/TEST.groups#L236) JDK regression test group which has been modified so that
* Tests use only FIPS 140-2 allowed key sizes, domain parameters, and algorithms;
* Tests name `JipherJCE` as the provider of cryptographic services instead of the JDK providers; and
* The default security provider list contains `JipherJCE` as the highest priority provider.
### Stability testing
* `JipherJCE` must pass all of the integration tests while using a leak-detecting native memory allocator.
### Performance testing
* The performance of `JipherJCE` should be similar to or better than the JDK's built-in providers, as measured by microbenchmarks using [JMH](https://github.com/openjdk/jmh).
There is some overhead in creating OpenSSL objects to process data, and in forwarding application data to these OpenSSL objects via FFM. For operations that process a variable amount of data, the relative performance of `JipherJCE` is a function of the amount of data processed. Processing small amounts of data using a low-cost operation, e.g., digesting two bytes, is significantly slower with `JipherJCE` than with the JDK's providers. Processing larger quantities of data should have similar or better performance than the JDK's providers.
* The performance of `JipherJCE` should be better than pure-Java third-party FIPS certified Java cryptographic service providers, as measured by the same microbenchmarks. It should be more than ten times better when OpenSSL takes advantage of processor instructions specifically designed to perform cryptographic operations efficiently.
Risks and Assumptions
---------------------
`JipherJCE` calls into native code, namely the OpenSSL FIPS module. Loading native code into the JVM and running it makes the JVM vulnerable to security and stability flaws in the native code.
These risks are mitigated by the following factors:
* OpenSSL is a mature code base. Its binaries are widely deployed and tested for stability and security issues.
* The FFM interface to OpenSSL is lean and carefully scrutinized for stability and security issues.
* We will perform stress testing to help identify any security or memory management issues.