Jipher JCEとネイティブ・イメージ

Jipher JCEは、Oracleが開発したJava Cryptography Architecture (JCA)プロバイダで、事前構成され、FIPS検証済のOpenSSL 3.0バージョンをパッケージ化しています。Jipherプロバイダは、OpenSSL 3.0のFIPSプロバイダを含む、FIPSで認められたアルゴリズムをサポートしています。Jipherは、Bouncy CastleまたはデフォルトのJDKプロバイダと比較して、競争力のあるパフォーマンスを提供します。FIPSで認められたアルゴリズムのみを使用するコンテキストで、ネイティブ・イメージを使用するJipherを有効にすることをお薦めします。一部のアルゴリズムは、特定のユース・ケースについてのみFIPSで認められていることに注意してください。そのため、Jipherによって提供されるアルゴリズムの中には、すべての目的についてFIPSで認められているわけではないものもあります。

ノート: Jipherは、GraalVM Community Editionでは使用できません。AMD64とAArch64アーキテクチャのLinuxとmacOS (macOS 10.15以上)でサポートされています。

Jipher JARファイルは、lib/jipher/jipher-jce.jarおよびlib/jipher/jipher-pki.jarにあるOracle GraalVMコア・パッケージに含まれています。Jipherを有効にするには、これらのJARファイルをアプリケーション・クラス・パスに渡します。

このページでは、GraalVMネイティブ・イメージでJipherを使用する方法を説明します。

Jipherを使用したネイティブ実行可能ファイルのビルド

JCAアルゴリズムはリフレクションに依存します。事前コンパイル時に必要なすべてのコード・パスをネイティブ実行可能ファイルに含めるには、native-imageツールで、リフレクションによって実行時に動的にアクセスされるJavaコードと、呼び出される可能性のあるネイティブ・コードを認識する必要があります。(詳細は、こちらを参照してください)。これを行うには、JSONベースのエージェントによって収集されたメタデータを指定します。Jipherを介して動的にアクセスされるJCAサービスも、エージェントによって自動的に登録されます。

次のステップは、RSAベースの署名の作成および検証を実行する単純なJavaアプリケーションを使用して、ネイティブ実行可能ファイルにJipherを埋め込む方法を示しています。

  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でアプリケーションを実行します。トレース・エージェントは、テスト実行中に検出されたすべての動的機能を捕捉して複数の*-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で認められたアルゴリズムのみを使用する場合は、GraalVMネイティブ・イメージにJipherをお薦めします。ネイティブ・イメージでのJCAサービスのサポートの詳細は、こちらを参照してください。