Native Image 与 Jipher JCE

Jipher JCE 是 Oracle 开发的 Java Cryptography Architecture (JCA) 提供程序,它封装了一个预配置且经过 FIPS 验证的 OpenSSL 3.0 版本。Jipher 提供程序支持 FIPS 允许的算法,包括 OpenSSL 3.0 的 FIPS 提供程序。与 Bouncy Castle 或默认的 JDK 提供程序相比,Jipher 提供了具有竞争力的性能。建议在仅允许使用 FIPS 算法的上下文中使用 Native Image 启用 Jipher。请注意,某些算法仅在特定用例中才被 FIPS 允许。因此,Jipher 提供的一些算法可能不适用于所有目的的 FIPS。

注意:Jipher 在 GraalVM Community Edition 中不可用。它在 Linux 和 macOS(macOS 10.15 及更高版本)上,同时支持 AMD64 和 AArch64 架构。

Jipher JAR 文件包含在 Oracle GraalVM 核心包中:lib/jipher/jipher-jce.jarlib/jipher/jipher-pki.jar。要启用 Jipher,请在应用程序类路径中传入这些 JAR 文件。

本页介绍了如何将 Jipher 与 GraalVM Native Image 结合使用。

使用 Jipher 构建原生可执行文件 #

JCA 算法依赖于反射。要在提前编译期间将所有必需的代码路径包含在原生可执行文件中,native-image 工具需要了解运行时通过反射动态访问的任何 Java 代码,以及可能调用的原生代码。(在此了解更多)。这可以通过提供基于 JSON 的由代理收集的元数据来完成。通过 Jipher 动态访问的任何 JCA 服务也会自动由代理注册。

以下步骤展示了如何将 Jipher 嵌入到原生可执行文件中,使用一个执行一些基于 RSA 签名创建和验证的简单 Java 应用程序。

  1. 将以下代码保存到名为 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);
         }
     }
    
  2. 在类路径上使用 Jipher JAR 文件编译应用程序

     javac -cp $GRAALVM_HOME/lib/jipher/jipher-jce.jar:$GRAALVM_HOME/lib/jipher/jipher-pki.jar JipherExample.java
    
  3. 在启用代理的 JVM 上运行应用程序。Tracing Agent 会捕获并将在测试运行期间遇到的所有动态特性写入多个 *-config.json 文件。

     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
    

    其中 <path> 应指向存储配置文件所在的目录。建议输出目录为 /META-INF/native-image/(如果您使用 Maven 或 Gradle 构建,则为 /resources/META-INF/native-image/)。稍后,在构建原生可执行文件时,native-image 构建器将自动从该位置获取文件。

    对于此 Java 应用程序,代理会创建包含以下内容的 reachability-metadata.json 文件

     {
       "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"] }]}
       ]
     }
    
  4. 为了让代理发现对 Jipher 的所有可能调用,请在 JVM 上使用代理重新运行应用程序(您可以根据需要多次重新运行代理)。这将重新生成整个配置套件,包括任何负面测试用例(以允许捕获异常类)。对于后续运行,请使用此命令

     java -agentlib:native-image-agent=config-merge-dir=<path> JipherExample
    

    config-merge-dir 命令将新配置与之前测试运行的配置合并。

  5. 使用提供的配置构建原生可执行文件

     native-image JipherExample
    

    如果配置文件已放置在除 /META-INF/native-image/ 之外的其他目录中,请在构建时传递此标志 -H:ConfigurationFileDirectories=<path> 以告知 native-image 工具新位置。

     native-image -H:ConfigurationFileDirectories=<path> JipherExample
    
  6. 运行本机可执行文件:

     ./jipherexample
    

当 Jipher 嵌入到原生可执行文件中,而是由 JVM 加载时,它会将嵌入在 JAR 中的原生库和 openssl.cnf 文件提取到文件系统,然后将其动态加载到 JVM 进程中。当 Jipher 嵌入到原生可执行文件中时,它会继续将原生库和 openssl.cnf 文件提取到文件系统,并将它们动态加载到原生进程中。当只需要使用 FIPS 允许的算法时,推荐将 Jipher 用于 GraalVM Native Image。在此了解更多关于 Native Image 中 JCA 服务支持的信息。

联系我们