理系学生日記

おまえはいつまで学生気分なのか

JCAとは何であるのか

Java SDK というのは、膨大な機能セットを提供してくれていますが、その中には暗号化に関するものがあり、このうち、暗号化に関する機能についてのフレームワークセットを JCA (Java Cryptography Architecture) と呼びます。 ちょっとこういう機能セットを利用したい状況にあるのですが、イマイチ JCA というものが分かっていないので、調査しまとめてみました。

** JCA の概要 JCA は、デジタル署名やメッセージダイジェスト、証明書とその検証、暗号化と復号化、鍵管理、乱数生成といったセキュリティに纏わる一連の API を含むフレームワークです。 これらの暗号化機能は、歴史的に Sun や SunJSSE 等、様々な実装が提供されてきましたが、JCA ではこれら実装に対して統一的にアクセスできるインタフェースを定義し、それらを、後述する「プロパイダ」からアクセスできるようにしています。

JCA の根本にある設計方針は次の 2 つです。 - 実装の独立性と相互操作性 - アルゴリズムの独立性と拡張性 前述のように、暗号化機能に対する複数の実装があり今後も増えることを念頭に、JCA では、Provider を利用することで各実装が互いに干渉しないようにこれらの実装を利用することができます。また、アルゴリズムの独立性については、個々の機能に対するエンジン(メッセージダイジェストについては MessageDigest クラス、暗号化については Cipher クラス、… というようになっています) が独立して提供されることで実現しています。

抽象論だと分かりづらいのですが、Java 暗号化アーキテクチャ(JCA) リファレンス・ガイドに分かりやすい図があったので、こちらをベースに説明します。

この図は、アプリケーションが JCA を利用してメッセージダイジェストを利用するユースケースを説明しています。 左側の図は、「アプリケーションが特定のメッセージ・ダイジェストの実装に依存せず、MD5 ハッシュを取得したい」というユースケースで、右側の図は「アプリケーションが Provider C の提供するメッセージ・ダイジェストの実装を利用して MD5 ハッシュを取得したい」といったユースケースの図になります。

左側の図では、アプリケーションが MessageDigest.getInstance("MD5") を実行することで、Provider Framework (JCA) に対し「適切な MD5 実装を取得しろ」という要求を出しています。JCA は、事前に定義された優先度に基いて、Provider A, B, C が MD5 実装を提供しているかを調べ、提供する Provider の中で最も優先度の高い Provider B が提供する MD5 実装を返します。 右側の図では、アプリケーションが MessageDigest.getInstance("MD5", "ProviderC") を実行することで、Provider Framework (JCA) に対し「"Provider C" の提供する MD5 実装を取得しろ」という要求を出しています。JCA は、その要求に基き、Provider C が提供する MD5 実装を返します。

このように、JCA では以下の 2 つのコンポーネントを提供しているといって良いと思います。 + 暗号化関連のインタフェースを定義し、適切な実装を返却するフレームワーク + 暗号化関連のインタフェースを実装する暗号化 Provider

** JCA で提供されるエンジン JCA では、以下のようなエンジンを提供しています (抜粋です) + SecureRandom: 安全な乱数/疑似乱数の提供 + MessageDigest: メッセージダイジェストの計算 + Signature: データの署名、および、検証 + Cipher: データの暗号化/復号化 + MAC: メッセージの整合性を保証するためのハッシュ計算 + KeyFactory: プログラムで表現される抽象的な鍵の概念を具体的な鍵の仕様に変換 + SecretKeyFactory: 秘密鍵のみを作成する KeyFactory + KeyPairGenerator: 公開鍵・秘密鍵ペアの生成 + KeyAgreement: 鍵の合意・確立 + KeyStore: 鍵の作成・管理

個々のエンジンについては詳細な使い方はもちろん異なりますが、getInstance メソッドを呼び出して実装を取得する点など、概要的な使い方は似ている部分も多いので、一つのエンジンを使えたら他のエンジンを使用する際も大きな隔絶は無いかなと思います。

** Provider の優先順位

冒頭に記載したように、Provider には優先順位を指定することができます。JCA に対して明示的に Provider を指定しない限り、JCA から取得される暗号化関連機能の実装は、この優先順位によって決定します。 では、優先順位をどこに定義するのか、ですが、この優先順位については静的に設定する方法と動的に設定する方法があります。多く使われているのは静的な設定で、これは、$JAVA_HOME/lib/security/java.security ファイルに指定します。

当該ファイルで security.provider.n (※n は数字) というキーが定義されている箇所があるかと思いますが、この値がプロパイダを示すクラス、n が優先順位になります。(1 始まり。数字が小さいほど、優先順位が高い) このあたりの構成は、むしろ、Java PKCS#11 あたりを参照した方が良いかもしれません。このへんはまた別途エントリを起こそうと思います。