Jipher JCEとネイティブ・イメージ
Jipher JCEはオラクル社が開発したJava暗号化アーキテクチャ(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以上)でサポートされています。
このページでは、GraalVMネイティブ・イメージでJipherを使用する方法を説明します。
Jipherのインストール
Jipherは、個別のコンポーネントとして配布され、GraalVMアップデータ・ツールを使用してGraalVMに追加できます。
次のコマンドを実行して、Jipherをインストールします:
gu install jipher
これにより、GraalVMのlibディレクトリ(lib/jipher/jipher-jce.JAR
およびlib/jipher/jipher-pki.JAR
)にJipher JARファイルが追加されます。
Jipherを使用したネイティブ実行可能ファイルのビルド
JCAアルゴリズムはリフレクションに依存します。事前コンパイル時に必要なすべてのコード・パスをネイティブ実行可能ファイルに含めるには、native-image
ツールで、リフレクションによって実行時に動的にアクセスされるJavaコードと、呼び出される可能性のあるネイティブ・コードを認識する必要があります。(詳細は、こちらを参照してください)。これを行うには、JSONベースのエージェントによって収集されたメタデータを指定します。Jipherを介して動的にアクセスされるJCAサービスも、エージェントによって自動的に登録されます。
次のステップは、RSAベースの署名の作成および検証を実行する単純なJavaアプリケーションを使用して、ネイティブ実行可能ファイルにJipherを埋め込む方法を示しています。
-
次のコードを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); } }
-
クラスパスにJipher JARを指定してアプリケーションをコンパイルします:
javac -cp $GRAALVM_HOME/lib/jipher/jipher-jce.jar:$GRAALVM_HOME/lib/jipher/jipher-pki.jar JipherExample.java
-
エージェントを有効にしてJVMでアプリケーションを実行します。トレース・エージェントは、テスト実行中に検出されたすべての動的機能を捕捉して複数の*-config.jsonファイルに書き込みます。
java 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アプリケーションの場合、エージェントは複数の構成ファイルを作成します。確認する内容は次のとおりです:
- resource-config.json: Jipherは、JAR内にOpenSSLライブラリ(サポートされているすべてのプラットフォーム用)をバンドルします。このファイルには、libjipher.so、fips.so、およびopenssl.cnfのエントリが、対応するチェックサム・ファイルとともにリストされます。特定のエントリは、エージェントが実行されるプラットフォームに関連し、ネイティブ実行可能ファイルがビルドされるプラットフォームに対応している必要があります。たとえば、Linux x64では、内容は次のようになります:
{ "resources":{ "includes":[ { "pattern":"\\Qlibs/linux_x64/fips.so.crc32\\E" }, { "pattern":"\\Qlibs/linux_x64/fips.so\\E" }, { "pattern":"\\Qlibs/linux_x64/libjipher.so.crc32\\E" }, { "pattern":"\\Qlibs/linux_x64/libjipher.so\\E" }, { "pattern":"\\Qlibs/linux_x64/openssl.cnf.crc32\\E" }, { "pattern":"\\Qlibs/linux_x64/openssl.cnf\\E" }, { "pattern":"\\Qlibs\\E" } ]}, "bundles":[] }
- jni-config.json: このファイルには、ネイティブ・メソッド宣言を含むJavaクラスのJipher内部OpenSSLパッケージのエントリがリストされます。内容は次のようになります:
{ "name":"[B"} , { "name":"[[B"} , { "name":"com.oracle.jipher.internal.openssl.JniOpenSsl"} , { "name":"java.lang.Boolean", "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }] }
- reflect-config.json: このファイルには、JCE SPIを実装するJavaクラスのJipher内部SPIパッケージのエントリがリストされます。内容は次のようになります:
[ { "name":"com.oracle.jipher.internal.spi.KeyPairGen$Rsa", "methods":[{"name":"<init>","parameterTypes":[] }]} , { "name":"com.oracle.jipher.internal.spi.RsaDigestSig$Sha512WithRsa", "methods":[{"name":"<init>","parameterTypes":[] }]} , ...]
- resource-config.json: Jipherは、JAR内にOpenSSLライブラリ(サポートされているすべてのプラットフォーム用)をバンドルします。このファイルには、libjipher.so、fips.so、およびopenssl.cnfのエントリが、対応するチェックサム・ファイルとともにリストされます。特定のエントリは、エージェントが実行されるプラットフォームに関連し、ネイティブ実行可能ファイルがビルドされるプラットフォームに対応している必要があります。たとえば、Linux x64では、内容は次のようになります:
-
エージェントがJipherへのすべての可能なコールを検出するには、JVM上のエージェントを使用してアプリケーションを再実行します(エージェントは必要な回数再実行できます)。これにより、ネガティブ・テスト・ケースを含む構成スイート全体が生成されます(例外クラスを取得できます)。後続の実行では、次のコマンドを使用します:
java -agentlib:native-image-agent=config-merge-dir=<path> JipherExample
config-merge-dir
コマンドは、新しい構成を以前のテスト実行の構成とマージします。 -
提供された構成でネイティブ実行可能ファイルをビルドします:
native-image JipherExample
構成ファイルが
/META-INF/native-image/
とは異なるディレクトリに配置されている場合は、ビルド時にフラグ-H:ConfigurationFileDirectories=<path>
を渡して、native-image
ツールに新しい場所を通知します:native-image -H:ConfigurationFileDirectories=<path> JipherExample
-
ネイティブ実行可能ファイルを実行します:
./jipherexample
Jipherがネイティブ実行可能ファイルに埋め込まれておらず、かわりにJVMによってロードされる場合、ネイティブ・ライブラリおよびJARに埋め込まれたopenssl.cnfファイルをファイルシステムに抽出し、それらを動的にJVMプロセスにロードします。Jipherがネイティブ実行可能ファイルに埋め込まれている場合、ネイティブ・ライブラリおよびopenssl.cnfファイルをファイルシステムに抽出し、ネイティブ・プロセスに動的にロードします。FIPSで認められたアルゴリズムのみを使用する場合は、GraalVMネイティブ・イメージにJipherをお薦めします。ネイティブ・イメージでのJCAサービスのサポートの詳細は、こちらを参照してください。