- GraalVM for JDK 23 (Latest)
- GraalVM for JDK 24 (Early Access)
- GraalVM for JDK 21
- GraalVM for JDK 17
- Archives
- Dev Build
Jipher JCE with Native Image
Jipher JCE is an Oracle-developed Java Cryptography Architecture (JCA) provider that packages a preconfigured and FIPS validated version of OpenSSL 3.0. The Jipher provider supports algorithms which are allowed by FIPS, including the OpenSSL 3.0’s FIPS provider. Jipher provides competitive performance compared to Bouncy Castle or the default JDK providers. It is recommended to enable Jipher with Native Image in contexts where only FIPS-allowed algorithms should be used. Note that some algorithms are allowed by FIPS for specific use cases only. As a result, some algorithms provided by Jipher might not be allowed by FIPS for all purposes.
Note: Jipher is not available in GraalVM Community Edition. It is supported on Linux and macOS (macOS 10.15 and higher) on both AMD64 and AArch64 architectures.
Jipher JAR files are included in the Oracle GraalVM core package at: lib/jipher/jipher-jce.jar and lib/jipher/jipher-pki.jar. To enable Jipher, pass these JAR files on the application class path.
This page describes how to use Jipher with GraalVM Native Image.
Build a Native Executable with Jipher #
JCA algorithms rely on reflection.
To include all required code paths in the native executable during ahead-of-time compilation, the native-image
tool needs to be made aware of any dynamically accessed Java code at run time, via reflection, as well as the native code which may be invoked. (Learn more here).
This can be done by providing the JSON-based metadata collected by the agent.
Any dynamically-accessed JCA services through Jipher are automatically registered by the agent too.
The steps below show how to embedded Jipher in a native executable, using a simple Java application that does some RSA based signature creation and validation.
-
Save the following code into the file named JipherExample.java:
import java.security.*; import java.util.*; import com.oracle.jipher.provider.*; class JipherExample { public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Provider jipher = new JipherJCE(); Security.insertProviderAt(jipher, 1); byte[] data = new byte[1024]; new Random().nextBytes(data); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", jipher); keyGen.initialize(4096); KeyPair keypair = keyGen.generateKeyPair(); Signature signer = Signature.getInstance("SHA512withRSA", jipher); signer.initSign(keypair.getPrivate()); signer.update(data); byte[] signature = signer.sign(); Signature verifier = Signature.getInstance("SHA512withRSA", jipher); verifier.initVerify(keypair.getPublic()); verifier.update(data); boolean isValid = verifier.verify(signature); assert(isValid); } }
-
Compile the application with Jipher JAR files on the class path:
javac -cp $GRAALVM_HOME/lib/jipher/jipher-jce.jar:$GRAALVM_HOME/lib/jipher/jipher-pki.jar JipherExample.java
-
Run the application on the JVM with the agent enabled. The Tracing Agent captures and writes down all the dynamic features encountered during a test run into multiple *-config.json files.
java -cp $GRAALVM_HOME/lib/jipher/jipher-jce.jar:$GRAALVM_HOME/lib/jipher/jipher-pki.jar:. -agentlib:native-image-agent=config-output-dir=<path> JipherExample
Where
<path>
should point to the directory in which to store the configuration files. It is recommended that the output directory is/META-INF/native-image/
(if you build with Maven or Gradle, then/resources/META-INF/native-image/
). Later, when building a native executable, thenative-image
builder will pick up the files from that location automatically.For this Java application, the agent creates the reachability-metadata.json file with the following contents:
{ "reflection":[ { "type":"com.oracle.jipher.internal.spi.KeyPairGen$Rsa", "methods":[{"name":"<init>","parameterTypes":[] }] }, { "type":"com.oracle.jipher.internal.spi.RsaDigestSig$Sha512WithRsa", "methods":[{"name":"<init>","parameterTypes":[] }] } ], "resources":[ {"glob":"libs/linux_x64/fips.so.crc32"}, {"glob":"libs/linux_x64/fips.so"}, {"glob":"libs/linux_x64/libjipher.so.crc32"}, {"glob":"libs/linux_x64/libjipher.so"}, {"glob":"libs/linux_x64/openssl.cnf.crc32"}, {"glob":"libs/linux_x64/openssl.cnf"}, {"glob":"libs"} ], "jni":[ {"type":"[B"}, {"type":"[[B"}, {"type":"com.oracle.jipher.internal.openssl.JniOpenSsl"}, {"type":"java.lang.Boolean","methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]} ] }
-
For the agent to discover all possible calls to Jipher, re-run the application with the agent on the JVM (you can re-run the agent as many times as needed). This will regenerate the entire configuration suite including any negative test cases (to allow for exception classes to be captured). For the subsequent runs, use this command:
java -agentlib:native-image-agent=config-merge-dir=<path> JipherExample
The
config-merge-dir
command will merge the new configuration with configuration from previous test runs. -
Build a native executable with the provided configuration:
native-image JipherExample
If the configuration files have been placed in a different directory than
/META-INF/native-image/
, pass this flag-H:ConfigurationFileDirectories=<path>
at build time to inform thenative-image
tool of a new location:native-image -H:ConfigurationFileDirectories=<path> JipherExample
-
Run the native executable:
./jipherexample
When Jipher is not embedded in a native executable, but is instead being loaded by the JVM, it extracts the native libraries and the openssl.cnf file embedded in the JAR to the filesystem and then dynamically loads them into the JVM process. When Jipher is embedded in a native executable, it continues to extract the native libraries and the openssl.cnf file to the filesystem and dynamically load them into the native process. Jipher is recommended for GraalVM Native Image when only FIPS-allowed algorithm should be used. Learn more about JCA services support in Native Image here.