Java ™ 暗号化アーキテクチャー
での
プロバイダの実装方法


はじめに

このドキュメントの対象読者

関連ドキュメント

用語に関する注記

エンジンクラスおよび対応する SPI クラス

プロバイダの実装および統合までのステップ

ステップ 1: サービス実装コードの記述

ステップ 1.1: 暗号化実装のための JCA プロバイダの追加要件および推奨事項

ステップ 2: プロバイダの命名

ステップ 3: プロバイダのサブクラスである「マスタークラス」の記述

ステップ 3.1: Cipher 実装の追加手順

ステップ 4: コードのコンパイル

ステップ 5: Jar ファイルへのプロバイダの記述

ステップ 6: オプション -- JAR ファイルの署名

ステップ 6.1: コード署名証明書の取得

ステップ 6.2: プロバイダの署名

ステップ 7: テストの準備

ステップ 7.1: プロバイダのインストール

ステップ 7.2: プロバイダアクセス権の設定

ステップ 8: テストプログラムの記述とコンパイル

ステップ 9: テストプログラムの実行

ステップ 10: 米国政府による輸出承認の申請 (必要な場合)

ステップ 11: プロバイダおよびそのサポート対象サービスのドキュメント化

メッセージダイジェストおよび MAC

ステップ 12: クラスファイルおよびドキュメントをクライアントから利用可能にする

プロバイダによる自己整合性チェックの実行方法

サンプルコードについて

プロバイダ JAR ファイルの検索: 基本

プロバイダの JAR ファイル URL の確認

JAR ファイルを参照する JarFile の作成

プロバイダ JAR ファイルの検証: 基本

検証の設定

JAR ファイル署名のチェック

署名の検証

署名者の信頼性の確認

証明書リストの取得

個々の署名者の識別と信頼できる署名者の特定

myJCE サンプルコードについて

実装の詳細および要件

別名

サービスの相互依存性

デフォルトの初期化

デフォルトの鍵ペアジェネレータのパラメータの要件

Provider.Service クラス

署名フォーマット

DSA インタフェースおよびその実装要件

RSA インタフェースおよびその実装要件

Diffie-Hellman インタフェースおよびその実装要件

他のアルゴリズムタイプ用インタフェース

アルゴリズムパラメータの仕様のインタフェースおよびクラス

鍵ファクトリにより要求される鍵仕様のインタフェースおよびクラス

非公開鍵の生成

エクスポート機能の保証

付録 A: SUN プロバイダのマスタークラス

付録 B: SunJCE プロバイダのマスタークラス

付録 C: java.security プロパティーファイル


はじめに

Java プラットフォームは、暗号化、公開鍵インフラストラクチャー、認証、安全な通信、アクセス制御など、主要なセキュリティー領域に関する API のセットを定義します。これらの API によって、開発者はアプリケーションコードにセキュリティーを簡単に統合できます。これらは、次の方針に基づいて設計されました。

  1. 実装の独立性

    アプリケーションでセキュリティーを実装する必要はありません。Java プラットフォームからセキュリティーサービスを要求できます。セキュリティーサービスはプロバイダ (下記を参照) に実装されています。プロバイダは、標準インタフェースによって Java プラットフォームにプラグインされます。アプリケーションは、複数の独立したプロバイダにセキュリティー機能を依存する場合があります。
  2. 実装の相互運用性

    プロバイダは、アプリケーション間で相互運用できます。具体的には、アプリケーションは特定のプロバイダにバインドされず、プロバイダは特定のアプリケーションにバインドされません。
  3. アルゴリズムの拡張性

    Java プラットフォームには、現在広く使用されている基本的なセキュリティーサービスを実装する多数の組み込みプロバイダが含まれています。ただし、一部のアプリケーションは、まだ実装されていない普及しつつある規格や独自のサービスに依存している場合があります。Java プラットフォームは、そのようなサービスを実装するカスタムプロバイダのインストールをサポートします。

「暗号化サービスプロバイダ」(プロバイダ) は、JDK Security API の暗号化に関するサブセットの具体的な実装を提供するパッケージ (またはパッケージセット) です。

java.security.Provider クラスは、セキュリティープロバイダの概念を Java プラットフォームでカプセル化します。プロバイダの名前を指定し、実装するセキュリティーサービスを一覧します。複数のプロバイダが同時に構成される場合があり、それらは優先順に一覧されます。セキュリティーサービスが要求されると、そのサービスを実装する、優先順位が一番高いプロバイダが選択されます。

図 1 および図 2 は、MD5 メッセージダイジェスト実装を要求するための、これらのオプションを示しています。どちらの図も、メッセージダイジェストアルゴリズムを実装する 3 つのプロバイダを示しています。プロバイダは、左から右への優先順位 (1~3) で並べられています。図 1 では、アプリケーションはプロバイダ名を指定せずに MD5 アルゴリズム実装を要求しています。プロバイダが優先順位に従って検索され、そのアルゴリズムを提供する最初のプロバイダ ProviderB から実装が返されます。図 2 では、アプリケーションは特定のプロバイダ ProviderC から MD5 アルゴリズム実装を要求しています。この場合は、優先順位の高いプロバイダ ProviderB も MD5 実装を提供しますが、指定されたプロバイダから実装が返されます。

<一般的な JCA アーキテクチャーの画像>

図 1: プロバイダの検索 図 2: 特定のプロバイダの要求

各インストールでは 1 つ以上のプロバイダパッケージがインストールされます。クライアントは異なるプロバイダを用いて実行環境を構成し、各プロバイダの「優先順位」を指定できます。優先順位とは、特定プロバイダの指定がないときに、要求アルゴリズムについてプロバイダを検索する順序です。

Sun が提供する Java Runtime Environment には、SUN という名前のデフォルトのプロバイダが標準で搭載されています。ほかの Java Runtime Environment には、SUN プロバイダが含まれない場合があります。

このドキュメントの対象読者

Java Security API を使って既存の暗号化アルゴリズムや他のサービスにアクセスするだけであれば、このドキュメントを読む必要はありません。

このドキュメントは、暗号化サービス実装を提供する独自のプロバイダパッケージを作成する上級プログラマを対象としています。ここでは、Java Security API クライアントが、作成されたアルゴリズムやほかのサービスを要求する際にそれらを検出できるよう、プロバイダを Java に統合するための方法がドキュメント化されています。

関連ドキュメント

このドキュメントは、読者がすでに「Java 暗号化アーキテクチャーリファレンスガイド」を読んでいることを前提としています。

Security API のさまざまなクラスおよびインタフェースを含むパッケージについてドキュメント化されています。

用語に関する注記

このドキュメントでは、「JCA」という語は、JCA フレームワークを指して使用されています。このドキュメントで特定の JCA プロバイダを取り上げる場合は、常にプロバイダ名で明示的に指定されます。

エンジンクラスおよび対応する Service Provider Interface クラス

「エンジンクラス」は、具体的な実装のない抽象的な方法で暗号化サービスを定義します。

「暗号化サービス」は、常に特定のアルゴリズムまたはタイプに関連付けられています。このサービスによって、暗号化の操作 (デジタル署名またはメッセージダイジェスト、暗号または鍵協定プロトコルなどのための操作) の提供、暗号化の操作に必要な暗号化データ (鍵またはパラメータ) の生成や提供、あるいは暗号化の操作で使用する暗号化鍵を安全にカプセル化するデータオブジェクト (キーストアまたは証明書) の生成が行われます。

たとえば、次の 4 つのエンジンクラスがあります。

Java 暗号化アーキテクチャーには、エンジンクラスなど、暗号化に関連するセキュリティーパッケージを構成するクラスが含まれています。API のユーザーは、エンジンクラスを要求および利用して対応する処理を実行します。JDK は、次のエンジンクラスを定義します。


注:   「ジェネレータ (generator)」は、最新の内容でオブジェクトを作成しますが、「ファクトリ (factory)」は既存の構成要素 (符号化法など) からオブジェクトを作成します。


「エンジン」クラスは、(特定の暗号化アルゴリズムに依存しない) 特定の型の暗号化サービス機能へのインタフェースを提供します。これにより、Application Programming Interface (API) メソッドが定義され、API が提供する特定の種類の暗号化サービスにアプリケーションがアクセスできるようになります。実際の実装 (1 つ以上のプロバイダから) は特定アルゴリズムのためのものです。たとえば、Signature エンジンクラスは、デジタル署名アルゴリズムの機能へのアクセスを提供します。SignatureSpi サブクラス (次の段落を参照) に実際に提供される実装は、DSA を使用する SHA-1、RSA を使用する SHA-1、または RSA を使用する MD5 などの特定の種類の署名アルゴリズムとなります。

エンジンクラスが提供するアプリケーションインタフェースは、Service Provider Interface (SPI) として実装されます。つまり、各エンジンクラスに対応する抽象 SPI クラスが存在し、抽象 SPI クラスによって暗号化サービスプロバイダが実装しなければならない Service Provider Interface のメソッドが定義されます。

エンジンクラスのインスタンスである「API オブジェクト」は、対応する SPI クラスのインスタンス「SPI オブジェクト」を private フィールドとしてカプセル化します。API オブジェクトのすべての API メソッドは、final として宣言し、それらを実装することによって、カプセル化される SPI オブジェクトの対応する SPI メソッドが呼び出されます。エンジンクラス (およびそれに対応する SPI クラス) のインスタンスは、エンジンクラスの getInstance ファクトリメソッドへの呼び出しによって作成されます。

SPI クラスの名前は、対応するエンジンクラス名のあとに「Spi」を追加した名前になります。たとえば、Signature エンジンクラスに対応する SPI クラスは、SignatureSpi クラスです。

各 SPI クラスは、抽象クラスです。指定したアルゴリズムに対する特定の型のサービスの実装を提供するには、プロバイダは、対応する SPI クラスをサブクラス化して、すべての抽象メソッドの実装を提供する必要があります。

エンジンクラスの別の例に MessageDigest クラスがあります。このクラスは、メッセージダイジェストアルゴリズムへのアクセスを提供します。MessageDigestSpi サブクラスでのこのクラスの実装は、SHA-1、MD5、または MD2 などの各種メッセージダイジェストアルゴリズムにできます。

さらに別の例として、KeyFactory エンジンクラスは、不透明な鍵から透明な鍵仕様への変換、またはその逆の変換をサポートします。詳細は、「鍵ファクトリにより要求される鍵仕様のインタフェースおよびクラス」を参照してください。KeyFactorySpi サブクラスで提供される現実の実装は、DSA 公開鍵または非公開鍵などの、特定の種類の鍵のための実装です。

プロバイダの実装および統合までのステップ

次の手順に従って、プロバイダを実装し JCA フレームワークに統合します。

ステップ 1: サービス実装コードの記述

ステップ 1.1: 暗号化実装のための JCA プロバイダの追加要件および推奨事項

ステップ 2: プロバイダの命名

ステップ 3: プロバイダのサブクラスである「マスタークラス」の記述

ステップ 4: コードのコンパイル

ステップ 5: JAR ファイルへのプロバイダの記述

ステップ 6: オプション -- JAR ファイルの署名

ステップ 6.1: コード署名証明書の取得

ステップ 6.2: プロバイダの署名

ステップ 7: テストの準備

ステップ 7.1: プロバイダのインストール

ステップ 7.2: プロバイダアクセス権の設定

ステップ 8: テストプログラムの記述とコンパイル

ステップ 9: テストプログラムの実行

ステップ 10: 米国政府による輸出承認の申請 (必要な場合)

ステップ 11: プロバイダおよびそのサポート対象サービスのドキュメント化

ステップ 12: クラスファイルおよびドキュメントをクライアントから利用可能にする

ステップ 1: サービス実装コードの記述

最初に、サポートする暗号化サービスのアルゴリズム固有の実装を提供するコードを記述する必要があります。

プロバイダは、JDK の 1 つ以上のセキュリティーコンポーネントですでに使用可能になっている暗号化サービス実装を提供できます。

JCA には定義されていない暗号化サービス (署名やメッセージダイジェストなど) に関しては、「Java 暗号化アーキテクチャーリファレンスガイド」を参照してください。

実装する暗号化サービスごとに、適切な SPI クラスのサブクラスを作成します。JCA は、次のエンジンクラスを定義します。

JCA およびその他の暗号化クラスについては、このドキュメントの「エンジンクラスおよび対応する SPI クラス」を参照してください。

サブクラスで、以下を実行する必要があります。

  1. 通常 engine で始まる名前を持つ抽象メソッド用の実装を提供します。詳細は、「実装の詳細および要件」を参照してください。
  2. 引数を持たない public コンストラクタの存在を確認します。理由は次のとおりです。これが必要な理由は、サービスの要求時に、Java Security が、マスタークラス内のプロパティーによる指定に従って、そのサービスを実装するサブクラスをルックアップするためです (ステップ 3 を参照)。その後、Java Security は、サブクラスに関連付けられた Class オブジェクトを作成し、その Class オブジェクトに対して newInstance メソッドを呼び出すことにより、サブクラスのインスタンスを作成します。newInstance はサブクラスがパラメータを持たない public コンストラクタを保持することを要求します。
  3. サブクラスがコンストラクタを持たない場合、引数を持たないデフォルトのコンストラクタが自動的に生成されます。ただし、サブクラスがコンストラクタを定義する場合、引数を持たない public コンストラクタを明示的に定義する必要があります。

ステップ 1.1: 暗号化実装のための JCA プロバイダの追加要件および推奨事項

プロバイダによる Cipher、KeyAgreement、KeyGenerator、MAC、または SecretKey ファクトリの実装 (クラス) をインスタンス化する際、フレームワークはプロバイダのコードベース (JAR ファイル) を判定し、その署名を検証します。このようにして、JCA はプロバイダを認証して、信頼されたエンティティーにより署名されたプロバイダだけが JCA にプラグインできるようにします。このため、暗号化プロバイダは署名付きにする必要があります。詳細はあとのステップで説明します。

また、各プロバイダは自己整合性チェックを実行して、プロバイダメソッドを JCA を介さずに直接呼び出そうとして、コードを含む JAR ファイルが操作されていないことを保証する必要があります。詳細は、「プロバイダによる自己整合性チェックの実行方法」を参照してください。

JCA を介さずに直接アプリケーションからインスタンス化が行われた場合に、プロバイダクラスを使用不可にするため、プロバイダは次の実装を行う必要があります。

プロバイダを米国以外に輸出する場合、CipherSpi 実装に、Key を指定すると鍵のサイズを返す engineGetKeySize メソッドの実装を含める必要があります。管轄ポリシーファイルで指定された利用可能な暗号化強度に制限が設定されている場合、Cipher 初期化メソッドは engineGetKeySize を呼び出して、実行中のアプレットまたはアプリケーションの特定位置および状況での鍵の最大有効サイズと結果を比較します。鍵のサイズが大きすぎる場合には、初期化メソッドにより例外がスローされます。

プロバイダが実装可能な「オプション」機能を、次に示します。

ステップ 2: プロバイダの命名

使用するプロバイダの名前を特定します。これは、クライアントアプリケーションがプロバイダを参照する際に使用する名前です。

ステップ 3: プロバイダのサブクラスである「マスタークラス」の記述

3 番目のステップは、java.security.Provider クラスのサブクラスを作成することです。

このサブクラスは final にする必要があり、そのコンストラクタは以下を実行する必要があります。

これらのどの場合にも、algName、certType、storeType、または attrName は、アルゴリズム、証明書のタイプ、キーストアタイプ、または属性の「標準」名です。使用する必要がある標準名については、「Java 暗号化アーキテクチャーリファレンスガイド」の「付録 A」を参照してください。

上記の形式のプロパティーの場合、プロパティーの値は、対応する属性に応じた値である必要があります。(各標準属性の定義については、「Java 暗号化アーキテクチャー API 仕様&リファレンス」の「付録 A」を参照してください。)

たとえば、SUN という名前のデフォルトプロバイダは、SHA1withDSA デジタル署名アルゴリズムをソフトウェア内で実装します。プロバイダ SUN のマスタークラスでは、次のようにして、Signature.SHA1withDSA ImplementedIn が値 Software を保持するように設定が行われます。

    put("Signature.SHA1withDSA ImplementedIn", "Software")

マスタークラスプロパティーの設定例の詳細は、「付録 A」を参照して現在の Sun.java のソースファイルを閲覧するか、「付録 B」を参照して SunJCE プロバイダを参照してください。これらのファイルでは、Sun および SunJCE プロバイダがプロパティーをどのように設定しているかがわかります。

ステップ 3.1: Cipher 実装の追加手順

すでに説明したように、Cipher プロパティーの場合、algName は実際には「変換」を表します。「変換」は、指定された入力に対して Cipher オブジェクトによって実行される操作 (または操作のセット) を説明する文字列です。変換には、暗号化アルゴリズム (DES など) の名前が必ず含まれます。それにモードおよびパディング方式が続く場合もあります。

変換は、次の書式で記述されます。

後者の場合、モードおよびパディング方式には、プロバイダ固有のデフォルト値が使用されます。たとえば、以下は有効な変換です。

    Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding"); 

ストリーム暗号モードでブロック暗号を要求する (たとえば CFB または OFB モードで DES を要求する) 場合、クライアントは、数値をモード名に追加することにより、一度に処理するビット数をオプションで指定できます。次に変換のサンプルを示します。

    Cipher c1 = Cipher.getInstance("DES/CFB8/NoPadding");
    Cipher c2 = Cipher.getInstance("DES/OFB32/PKCS5Padding");

数値がストリーム暗号モードに準拠していない場合、プロバイダ固有のデフォルト値が使用されます。たとえば、SunJCE プロバイダではデフォルトの 64 ビットが使用されます。

プロバイダは、algorithm/mode/padding の組み合わせごとに別々のクラスを提供できます。または、algorithm、algorithm/mode、algorithm//padding (ダブルスラッシュを使用する点に注意) のいずれかに対応する下位変換を表すより一般的なクラスを提供できます。この場合、要求されたモードやパディングは、CiphergetInstance メソッドによって自動的に設定されます。getInstance メソッドは、プロバイダの CipherSpi のサブクラスから engineSetMode メソッドと engineSetPadding メソッドを呼び出します。

つまり、プロバイダマスタークラスの Cipher プロパティーは、以下の表に示すいずれかの形式になります。

Cipher プロパティーの形式 説明
Cipher.algName プロバイダの CipherSpi のサブクラスは、プラグイン可能モードとパディングを利用して algName を実装します。
Cipher.algName/mode プロバイダの CipherSpi のサブクラスは、指定された mode とプラグイン可能なパディングを利用して algName を実装します。
Cipher.algName//padding プロバイダの CipherSpi のサブクラスは、指定された padding とプラグイン可能モードを利用して algName を実装します。
Cipher.algName/mode/padding プロバイダの CipherSpi のサブクラスは、指定された modepadding を利用して algName を実装します。

使用する必要がある標準アルゴリズム名、モード、およびパディング方式については、「Java 暗号化アーキテクチャーリファレンスガイド」の「付録 A」を参照してください。

たとえば、プロバイダは DES/ECB/PKCS5Padding、DES/CBC/PKCS5Padding、DES/CFB/PKCS5Padding、さらに DES/OFB/PKCS5Padding をそれぞれ実装する CipherSpi のサブクラスを提供可能です。このプロバイダは、マスタークラス内に次の Cipher プロパティーを保持します。

別のプロバイダは、上記の各モードに対応したクラス (ECB、CBC、CFB、および OFB 用にそれぞれ 1 つのクラス) を実装できます。また、PKCS5Padding に対応する 1 つのクラス、および CipherSpi からサブクラス化された総称 DES クラスも実装できます。このプロバイダは、マスタークラス内に次の Cipher プロパティーを保持します。

「algorithm」形式の変換の場合、Cipher エンジンクラスの getInstance ファクトリメソッドは、次の規則に従ってプロバイダの CipherSpi 実装をインスタンス化します。

  1. プロバイダが、指定された「algorithm」に対応する CipherSpi のサブクラスを登録済みかどうかをチェックする。

    登録済みの場合、このクラスをインスタンス化して、このモードおよびパディング方式のデフォルト値 (プロバイダにより提供) を使用可能にします。

    未登録の場合、例外 NoSuchAlgorithmException をスローします。

「algorithm/mode/padding」形式の変換の場合、Cipher エンジンクラスの getInstance ファクトリメソッドは、次の規則に従ってプロバイダの CipherSpi 実装をインスタンス化します。

  1. プロバイダが、指定された「algorithm/mode/padding」変換に対応する CipherSpi のサブクラスを登録済みかどうかをチェックする。

    登録済みの場合、このクラスをインスタンス化します。

    未登録の場合、次のステップに進みます。

  2. プロバイダが、サブ変換「algorithm/mode」に対応する CipherSpi のサブクラスを登録済みかどうかをチェックする。

    登録済みの場合、このクラスをインスタンス化してから、新規インスタンスに対し engineSetPadding(padding) を呼び出します。

    未登録の場合、次のステップに進みます。
  3. プロバイダが、サブ変換「algorithm//padding」 (ダブルスラッシュに注意) に対応する CipherSpi のサブクラスを登録済みかどうかをチェックする。

    登録済みの場合、このクラスをインスタンス化してから、新規インスタンスに対し engineSetMode(mode) を呼び出します。

    未登録の場合、次のステップに進みます。
  4. プロバイダが、サブ変換「algorithm」に対応する CipherSpi のサブクラスを登録済みかどうかをチェックする。

    登録済みの場合、このクラスをインスタンス化してから、新規インスタンスに対し engineSetMode(mode) および engineSetPadding(padding) を呼び出します。

    未登録の場合、例外 NoSuchAlgorithmException をスローします。

ステップ 4: コードのコンパイル

実装コードの作成 (ステップ 1)、プロバイダの命名 (ステップ 2)、およびマスタークラスの作成 (ステップ 3) が完了したら、Java コンパイラを使ってファイルをコンパイルします。

ステップ 5: JAR ファイルへのプロバイダの記述

次のステップ (JAR ファイルへの署名) の準備として、JAR ファイルにプロバイダコードを記載します。jar ツールの詳細については、jar (Solaris 用) (Microsoft Windows 用) を参照してください。

    jar cvf <JAR file name> <list of classes, separated by spaces>

このコマンドにより、指定されたクラスを含む、指定された名前の JAR ファイルが作成されます。

ステップ 6: オプション -- JAR ファイルの署名

プロバイダが Cipher KeyAgreement、KeyGenerator、Mac、または SecretKeyFactory クラスによって暗号化アルゴリズムを提供している場合、実行時に JCA がコードを認証できるように、JAR ファイルに署名する必要があります。詳細は、ステップ 1.1 を参照してください。このタイプの実装を提供してない場合は、このステップはスキップできます。

ステップ 6.1: コード署名証明書の取得

次のステップは、コード署名証明書の要求です。テストに先立ち、コード署名証明書を使用してプロバイダへの署名を行います。証明書は、テスト環境と製作環境の両方で利用できます。有効期間は 5 年間です。

次に、コード署名証明書の取得方法を示します。keytool ツールの詳細は、keytool (Solaris 用) (Microsoft Windows 用) を参照してください。

  1. keytool を使用して、DSA 鍵ペアを生成します。例として、DSA アルゴリズムを使用します。
        keytool -genkeypair -alias <alias> \
    	-keyalg DSA -keysize 1024 \
    	-dname "cn=<Company Name>, \
    	ou=Java Software Code Signing,\
    	o=Sun Microsystems Inc" \
    	-keystore <keystore file name>\
    	-storepass <keystore password>
    	
    これにより、DSA 鍵ペア (公開鍵および関連する非公開鍵) が生成され、指定されたキーストアのエントリに格納されます。公開鍵は、自己署名証明書に格納されます。これ以降、キーストアのエントリには、指定された別名を使用してアクセスできます。

    角括弧 (「<」 と「>」) 内のオプション値には、実際の値を指定する必要があります。たとえば、<alias> は、新しく生成するキーストアのエントリを参照する際に使用する任意の別名で置き換え、<keystore file name> は、使用するキーストアの名前で置き換えます。注: 実際の値には、角括弧を付けないでください。たとえば、別名を myTestAlias にする場合、-alias オプションを次のように指定します。

        -alias myTestAlias
    まだ存在しないキーストアを指定すると、そのキーストアが作成されます。


    注: 入力するコマンド行を、実行する keytool -genkeypair コマンドと同じ長さにできない場合 (Microsoft Windows の DOS プロンプトに入力する場合など)、コマンドを含むプレーンテキストのバッチファイルを作成して実行できます。つまり、keytool -genkeypair コマンドだけを含むテキストファイルを新規作成します。なお、コマンドは、全体を 1 行に入力してください。拡張子 .bat を付けてファイルを保存します。DOS ウィンドウで、ファイル名を (必要に応じてパスを付けて) 入力します。これで、バッチファイルに記述されたコマンドが実行されます。

  2. keytool を使用して、証明書署名要求を生成します。
        keytool -certreq -alias <alias> \
    	-file <csr file name> \
    	-keystore <keystore file name> \
    	-storepass <keystore password> 
    ここで、<alias> には、前のステップで作成した DSA 鍵ペアエントリの別名を指定します。このコマンドにより、証明書署名要求 (CSR) が PKCS#10 形式で生成されます。<csr file name> で指定した名前のファイルに CSR が格納されます。
  3. CSR、連絡情報、および他の必須ドキュメントを JCA コード署名証明書発行局に送ります。CSR および連絡情報 (以下を参照) を、電子メールで javasoft-cert-request@sun.com に送ってください。電子メールメッセージの件名行には、以下を入力します。
        Request a Certificate for Signing a JCA Provider 
    メッセージの本文に連絡情報を入力し、メッセージに CSR ファイルを添付して送信します。添付に使用するエンコーディングを指定するオプションがメールソフトに存在する場合、「MIME」を選択します。


    注: CSR ファイルは、Base 64 でエンコーディングされたプレーンテキストです。人間が読むことができるのは、最初と最後の行だけです。

    メッセージの本文に次の連絡情報を含めます。
    • Company Name
    • Street Address (Not a post office box)
    • City
    • State/Province
    • Company Telephone Number
    • Company Fax Number
    • Requester Name
    • Requester Telephone Number
    • Requester Email Address
    • Brief description of your company (size, line of business, etc.)

    上記の情報をすべて入力する必要があります。

  4. 電子メールメッセージを受信すると、JCA コード署名証明書発行局は、要求番号を電子メールで返信します。処理に 5 営業日かかります。

    この要求番号を受信したら、Certification Form for CSPs を印刷して記入し、送ります。このフォームは、以下のアドレスに郵送します。フォームに要求番号を記入し、郵送したフォームが電子メールのメッセージに記載した CSR および連絡先情報と一致するようにします。

    Sun Microsystems, Inc.
    International Trade Services/Export Compliance
    Attn:Encryption Export
    10 Network Circle MS:UMPK10-144
    Menlo Park, CA 94025
    U.S.A.

    JCA コード署名証明書は、電子メールメッセージと必要なフォームの両方を受信後に、要求者の認証を行います。その後、5 年間有効なコード署名証明書を作成および署名します。2 つのプレーンテキストファイルの添付された電子メールメッセージが要求者に送信されます。1 つはこのコード署名証明書を含むファイルで、もう 1 つは独自の CA 証明書を含むファイルで公開鍵の認証に使用します。要求を受け取ってから、処理に 5 営業日かかります。
  5. keytool を使用して CA から受信した証明書をインポートします。

    JCA コード署名証明書発行局から 2 つの証明書を受信したら、keytool を使用してキーストアにそれらをインポートできます。

    最初に、CA の証明書を「信頼できる証明書」としてインポートします。
        keytool -import -alias <alias for the CA cert> \
    	-file <CA cert file name> \
    	-keystore <keystore file name> \
    	-storepass <keystore password>
    次に、コード署名証明書をインポートします。
        keytool -import -alias <alias> \
    	-file <code-signing cert file name> \
    	-keystore <keystore file name> \
    	-storepass <keystore password>
    ここで、<alias> にはステップ 1 (DSA 鍵ペアの生成) で作成したのと同じ別名を指定します。このコマンドにより、<alias> で指定されたキーストアエントリ内の自己署名証明書が、JCA コード署名証明書発行局が署名した証明書で置き換えられます。

これで、JCA により信頼されたエンティティー (JCA コード署名証明書発行局) からの証明書がキーストア内に保存されたため、JAR ファイル内にプロバイダコードを記述し (ステップ 5)、この証明書を使用して JAR ファイルに署名できます (ステップ 6.2)。

ステップ 6.2: プロバイダの署名

ステップ 6 で取得したコード署名証明書を使用して、ステップ 5 で作成した JAR ファイルに署名します。jarsigner ツールの詳細は、jarsigner (Solaris 用) (Microsoft Windows 用) を参照してください。

    jarsigner -keystore <keystore file name> \
	-storepass <keystore password> \
	<JAR file name> <alias>

ここで、<alias> には、JCA コード署名証明書発行局から受け取ったコード署名証明書を含むエントリ用キーストアの別名 (ステップ 6.1 のコマンドで指定した別名) を指定します。

次の方法で、署名を検証できます。

    jarsigner -verify <JAR file name> 

検証が成功すると、「jar verified」というテキストが表示されます。

ステップ 7: テストの準備

次の手順では、新しいプロバイダを JCA で使用できるようにインストールおよび構成する方法について説明します。

ステップ 7.1: プロバイダのインストール

プロバイダのテスト準備を行うために、プロバイダを使用するクライアントが行うのと同じ方法で、プロバイダをインストールする必要があります。インストールを実行すると、Java Security はクライアントの要求に応じてアルゴリズムの実装を検出できるようになります。

プロバイダのインストールには、つまり、プロバイダパッケージクラスのインストールとプロバイダの構成です。

プロバイダクラスのインストール

最初に行う事柄は、作成したクラスを利用可能にして、要求時に検出できるようにすることです。プロバイダクラスは Jar (Java ARchive) ファイルの形式で提供します。

プロバイダクラスのインストール方法は 2 種類あります。

プロバイダ JAR ファイルは、次に示すインストール型拡張機能 JAR ファイルの標準位置に配置された場合、インストール型拡張機能と見なされます。

    <java-home>/lib/ext		[Solaris]
    <java-home>\lib\ext		[Windows]

ここで、<java-home> は、ランタイムソフトウェアのインストール先ディレクトリ (JavaTM 2 Runtime Environment (JRE) のトップレベルディレクトリまたは JavaTM SE (JDK) ソフトウェアの jre ディレクトリ) を指します。たとえば、JDK 6 を /home/user1/jdk1.6.0 ディレクトリ (Solaris)、または C:\jdk1.6.0 ディレクトリ (Microsoft Windows) にインストールした場合、JAR ファイルを次のディレクトリにインストールする必要があります。

    /home/user1/jdk1.6.0/jre/lib/ext	[Solaris]
    C:\jdk1.6.0\jre\lib\ext		[Windows]

同様に、JRE 6 を /home/user1/jre1.6.0 ディレクトリ (Solaris)、または C:\jre1.6.0 ディレクトリ (Microsoft Windows) にインストールした場合、JAR ファイルを次のディレクトリにインストールする必要があります。

    /home/user1/jre1.6.0/lib/ext	[Solaris]
    C:\jre1.6.0\lib\ext			[Windows]

「インストール型」拡張機能の詳細は、「インストール型拡張機能」を参照してください。

「バンドル型」拡張機能の詳細は、「バンドル型拡張機能」を参照してください。

プロバイダの構成

次の手順では、認可プロバイダのリストにこのプロバイダを追加します。これは、セキュリティープロパティーファイルを編集することにより、静的に行われます。

    <java-home>/lib/security/java.security	[Solaris]
    <java-home>\lib\security\java.security	[Windows]

ここで、<java-home> は JRE がインストールされているディレクトリを指します。たとえば、JDK 6 を /home/user1/jdk1.6.0 ディレクトリ (Solaris)、または C:\jdk1.6.0 ディレクトリ (Microsoft Windows) にインストールした場合、次のファイルを編集する必要があります。

    /home/user1/jdk1.6.0/jre/lib/security/java.security	[Solaris]
    C:\jdk1.6.0\jre\lib\security\java.security		[Windows]

同様に、JRE 6 を Solaris の /home/user1/jre1.6.0 ディレクトリにインストールしている場合、または Windows の C:\jre1.6.0 ディレクトリにインストールしている場合は、次のファイルを編集する必要があります。

    /home/user1/jre1.6.0/lib/security/java.security	[Solaris]
    C:\jre1.6.0\lib\security\java.security		[Windows]

プロバイダごとに、このファイルは次の形式の文を保持します。

    security.provider.n=masterClassName 

これはプロバイダを宣言し、その優先順位 n を指定します。優先順位とは、特定プロバイダの指定がないときに、要求されたアルゴリズムについてプロバイダを検索する順序です。順位は 1 から始まり、1 が最優先で次に 2、3 ...と続きます。

masterClassName には、ステップ 3 で実装したプロバイダの「マスタークラス」の完全修飾名を指定する必要があります。このクラスは、常に Provider クラスのサブクラスです。

Java には、SUN、SunRsaSign、および SunJCE という名前のプロバイダが標準で搭載されています。このプロバイダは、次に示すように、静的プロバイダとして java.security プロパティーファイル内で自動的に構成されます。

    security.provider.2=sun.security.provider.Sun
    security.provider.3=sun.security.rsa.SunRsaSign
    security.provider.4=sun.security.provider.SunJCE

SUN プロバイダのマスタークラスは、sun.security.provider パッケージ内の Sun クラスです。

JCA プロバイダ SunJCE および Java プラットフォームに含まれるほかのセキュリティー関連プロバイダは、静的プロバイダとして自動的に構成されます。

ほかの JCA プロバイダを使用する場合は、行を追加してプロバイダを登録し、SUN および SunRsaSign プロバイダよりも低い優先順位を設定します。

例として、マスタークラスが com.cryptox.provider パッケージの CryptoX クラスで、プロバイダを 4 番目の優先順位とする場合を考えてみましょう。そのためには、java.security ファイルを次のように編集します。

    security.provider.2=sun.security.provider.Sun
    security.provider.3=sun.security.rsa.SunRsaSign
    security.provider.4=com.cryptox.provider.CryptoX
    security.provider.5=sun.security.provider.SunJCE

注: プロバイダは動的に登録することもできます。その場合、プログラム (ステップ 8 で記述したテストプログラムなど) は、Security クラスの addProvider メソッドまたは insertProviderAt メソッドを呼び出します。こうした登録は持続的なものではありません。また、実行できるのは次の権限を付与されたコードだけです。

    java.security.SecurityPermission "insertProvider.{name}"

ここで、{name} には実際のプロバイダ名を指定します。

たとえば、プロバイダ名が「MyJCE」であり、プロバイダのコードが /localWork ディレクトリの myjce_provider.jar ファイル内に存在する場合、アクセス権を付与するサンプルポリシーファイルの grant 文は次のようになります。

    grant codeBase "file:/localWork/myjce_provider.jar" {
	permission java.security.SecurityPermission
	    "insertProvider.MyJCE";
    };

ステップ 7.2: プロバイダアクセス権の設定

プロバイダがインストール型拡張機能ではない場合、セキュリティーマネージャーがインストール済みの状態で、アプレットまたはアプリケーションを実行する際、常にプロバイダにアクセス権を付与する必要があります。通常、アプレットの実行時にはセキュリティーマネージャーが常にインストールされます。アプリケーションの場合でも、アプリケーション自体のコード内またはコマンド行引数で指定することにより、セキュリティーマネージャーをインストールできます。デフォルトシステムポリシーファイルは、インストール型拡張機能にすべてのアクセス権を付与するため、インストール型拡張機能にはアクセス権を付与する必要はありません。

クライアントがプロバイダをインストール型拡張機能としてインストールしない場合、クライアント環境で次のアクセス権をプロバイダに常に付与する必要があります。

セキュリティーマネージャーがインストールされていて、プロバイダがインストール型拡張機能でない場合は、プロバイダが正しく機能するかどうかを確認するため、インストールおよび実行環境をテストする必要があります。なお、テストを実施する前に、プロバイダとこのプロバイダが使用するすべてのプロバイダに適切なアクセス権を付与しておく必要があります。たとえば、名前が「MyJCE」で、コードが myjce_provider.jar 内に存在するプロバイダにアクセス権を付与するサンプルコードを次に示します。この種の文は、ポリシーファイルに記述されます。この例では、myjce_provider.jar ファイルは /localWork ディレクトリに格納されるものとします。

    grant codeBase "file:/localWork/myjce_provider.jar" {
	permission java.lang.RuntimePermission "getProtectionDomain";
	permission java.security.SecurityPermission
	    "putProviderProperty.MyJCE";
    };

ステップ 8: テストプログラムの記述とコンパイル

Security API へのプロバイダの統合、およびそのアルゴリズムをテストする 1 つ以上のテストプログラムの記述およびコンパイルを実行します。必要に応じて、暗号化の行われるテストデータ用ファイルなどのサポート用ファイルを作成します。

プログラムが実行する最初のテストでは、プロバイダの検出、およびその名前、バージョン番号、追加情報が予期された通りかどうかを確認します。このために、次のようなコードを記述できます。MyPro 部分は、独自のプロバイダ名に置き換えてください。

    import java.security.*;

    Provider p = Security.getProvider("MyPro");

    System.out.println("MyPro provider name is " + p.getName());
    System.out.println("MyPro provider version # is " + p.getVersion());
    System.out.println("MyPro provider info is " + p.getInfo());

次に、サービスが検出されることを確認します。たとえば、DES 暗号化アルゴリズムを実装した場合には、要求時にこのアルゴリズムが確実に検出されるかどうかを、次のコードを使ってチェックできます (ここでも「MyPro」は、独自のプロバイダ名に置き換えてください)。

    Cipher c = Cipher.getInstance("DES", "MyPro");

    System.out.println("My Cipher algorithm name is " + c.getAlgorithm());

getInstance への呼び出しでプロバイダ名を指定しない場合、そのアルゴリズムを実装するプロバイダが検出されるまで、登録されたすべてのプロバイダが優先順位に従って検索されます (「プロバイダの構成」を参照)。

プロバイダが免責機構を実装している場合、免責機構を使用するテストアプレットまたはアプリケーションを記述する必要があります。この種のアプレット/アプリケーションにも、署名、および「アクセス権ポリシーファイル」のバンドルが必要です。アプリケーションの作成およびテスト方法の詳細は、「Java 暗号化アーキテクチャーリファレンスガイド」の「アプリケーションの暗号化制限の「免責」を取得する方法」を参照してください。

ステップ 9: テストプログラムの実行

テストプログラムを実行します。コードをデバッグし、必要に応じてテストを続行します。Java Security API がアルゴリズムを検出できないようであれば、上記のステップを確認し、すべてのステップが完了していることを確認してください。

複数のインストールオプション (プロバイダをインストール型拡張機能にする、またはクラスパス内に配置するなど) および実行環境 (セキュリティー管理を実行する、または実行しない) を使用して、プログラムを確実にテストしてください。インストールオプションの詳細は、ステップ 7.1 を参照してください。特に、セキュリティーマネージャーをインストールし、かつプロバイダがインストール型拡張機能ではない (つまり、プロバイダにアクセス権を付与する必要がある) 場合、プロバイダが正しく機能するかどうかを確認するため、ステップ 7.2 の手順に従ってプロバイダおよびそのプロバイダが使用するほかのプロバイダに必要なアクセス権を付与したあと、インストールおよび実行環境をテストする必要があります。

テストの結果、コードの修正が必要になった場合には、変更および再コンパイル (ステップ 4)、JAR ファイルへの更新されたプロバイダコードの記載 (ステップ 6)、必要に応じた JAR ファイルへの署名 (ステップ 6.2)、プロバイダの再インストール (ステップ 7.1)、必要に応じたアクセス権の修正または追加 (Step 7.2) を実行してから、プログラムを再テストします。その後、必要に応じてこれらのステップを繰り返します。

ステップ 10: 米国政府による輸出承認の申請 (必要な場合)

プロバイダを米国外に輸出する可能性のある米国内のベンダーはすべて、米国商務省産業安全保障局に輸出承認申請を行う必要があります。詳細は、輸出問題を担当する顧問弁護士に確認してください。

注: プロバイダが Cipher.getInstance() を呼び出し、返される Cipher オブジェクトで、ユーザーがダウンロードした管轄ポリシーファイルで許可されている暗号化の強度に関係なく強力な暗号化を実行する必要がある場合は、その暗号化強度に対応したアクセス権が指定されている、JAR ファイルにバンドルする予定の cryptoPerms アクセス権ポリシーファイルのコピーを含める必要があります。このファイルが必要な理由は、アプレットおよびアプリケーションが暗号化制限を「免除される」ために、JAR ファイルに cryptoPerms アクセス権ポリシーファイルを含める必要があるのと同じ理由です。このようなファイルの作成と組み込みの詳細は、「Java 暗号化アーキテクチャーリファレンスガイド」の「アプリケーションの暗号化制限の「免責」を取得する方法」を参照してください。

役に立つと思われる URL を 2 つ紹介しておきます。

ステップ 11: プロバイダおよびそのサポート対象サービスのドキュメント化

次のステップは、クライアント用のドキュメントを記述することです。少なくとも、次の指定が必要です。

さらに、ドキュメント内で、デフォルトのアルゴリズムパラメータなどの、クライアントに関係する他の指定も行う必要があります。

メッセージダイジェストおよび MAC

メッセージダイジェストおよび MAC アルゴリズムごとに、実装が複製可能かどうかを指定します。これは、技術的には必須ではありませんが、複製による中間メッセージダイジェストまたは MAC が可能かどうかを指定することになるため、クライアントの費やす時間およびコードの記述にかかる手間が軽減されます。MessageDigest または Mac の実装が複製可能かどうかがわからない場合、クライアントはオブジェクトの複製を試みて、発生する可能性のある例外をキャッチすることにより、複製可能かどうかを識別できます。次にその例を示します。

    try {
	// try and clone it
	/* compute the MAC for i1 */
	mac.update(i1);
	byte[] i1Mac = mac.clone().doFinal();

	/* compute the MAC for i1 and i2 */
	mac.update(i2);
	byte[] i12Mac = mac.clone().doFinal();

	/* compute the MAC for i1, i2 and i3 */
	mac.update(i3);
	byte[] i123Mac = mac.doFinal();
    } catch (CloneNotSupportedException cnse) {
	// have to use an approach not involving cloning
    } 

説明

  • mac は、Mac.getInstance への呼び出しを介して要求が行われた場合に、受け取られる MAC オブジェクトです。

  • i1i2 および i3 は、入力バイト配列です。

  • 次について、別々のハッシュを計算します。
    • i1
    • i1 および i2
    • i1、i2、および i3

鍵ペアジェネレータ

鍵ペアジェネレータアルゴリズムでは、クライアントが (initialize メソッドの呼び出しを介して) 明示的に鍵ペアジェネレータを初期化しない場合、各プロバイダはデフォルトの初期化を提供およびドキュメント化する必要があります。たとえば、SunJCE により提供される Diffie-Hellman 鍵ペアジェネレータは、1024 ビットのデフォルトプライムモジュラスサイズ (keysize) を使用します。

鍵ファクトリ

プロバイダは、その (非公開) 鍵ファクトリがサポートするすべての鍵仕様をドキュメント化する必要があります。

アルゴリズムパラメータジェネレータ

クライアントが AlgorithmParameterGenerator エンジンクラスの init メソッドの呼び出しを介してアルゴリズムパラメータジェネレータを明示的に初期化しない場合、各プロバイダはデフォルトの初期化を行い、これをドキュメント化する必要があります。たとえば、SunJCE プロバイダは、Diffie-Hellman パラメータの生成に 1024 ビットのデフォルトプライムモジュラスサイズ (keysize) を使用し、SUN プロバイダは、DSA パラメータの生成に 1024 ビットのデフォルトモジュラスプライムサイズを使用します。

署名アルゴリズム

署名アルゴリズムを実装する場合、署名 (sign メソッドの 1 つを使って生成される) を符号化する形式をドキュメント化する必要があります。たとえば、SUN プロバイダにより提供される SHA1withDSA 署名アルゴリズムは、署名を、2 つの整数 r および s の標準 ASN.1 SEQUENCE として符号化します。

乱数生成 (SecureRandom) アルゴリズム

乱数生成アルゴリズムの場合、生成される数がどのように「ランダム」なのかを示す情報、および乱数ジェネレータの自己シード時のシードの質に関する情報を提供します。同時に、SecureRandom オブジェクト (およびそのカプセル化された SecureRandomSpi 実装オブジェクト) の直列化解除時に、何が発生するかにも留意してください。復元されたオブジェクトの nextBytes メソッド (カプセル化された SecureRandomSpi オブジェクトの engineNextBytes メソッドを呼び出す) への続く呼び出しにより、元のオブジェクトが生成するのと正確に同じ (ランダム) バイトが生成される場合、この動作が望ましくないのであれば、setSeed メソッドを呼び出して復元されたランダムオブジェクトにシードをするよう、ユーザーに通知してください。

証明書ファクトリ

プロバイダは、ファクトリが作成可能な証明書の種類 (および必要に応じてそのバージョン番号) をドキュメント化する必要があります。

キーストア

プロバイダは、キーストアの実装に関するすべての関連情報 (基礎となるデータ形式など) をドキュメント化する必要があります。

ステップ 12: クラスファイルおよびドキュメントをクライアントから利用可能にする

プロバイダソフトウェアの記述、構成、テスト、インストール、およびドキュメント化のあとで、ドキュメントをカスタマから利用可能にします。

プロバイダによる自己整合性チェックの実行方法

各プロバイダは自己整合性チェックを実行して、プロバイダメソッドを JCA を介さずに直接呼び出すなどの操作により、コードを含む JAR ファイルが改変されていないことを保証する必要があります。暗号化サービス (Cipher、KeyAgreement、KeyGenerator、MAC、または SecretKey ファクトリ) の実装を提供するプロバイダは、デジタル署名され、「信頼できる」証明書発行局が発行する証明書で署名されている必要があります。現状では、次の 2 種類の証明書発行局が「信頼できる」とされています。

Sun Microsystems の JCA コード署名 CA からコード署名証明書を取得する方法については、ステップ 6.2 を参照してください。

署名済み証明書を上記の証明書発行局から入手したあと、プロバイダパッケージに署名する証明書用のバイトを埋め込む必要があります。 たとえば、後述する「個々の署名者の識別と信頼できる署名者の特定」で解説する、bytesOfProviderCert 配列のような配列です。実行時には、埋め込まれた証明書を使用して、プロバイダコードが認証されたものかどうかが判断されます。

プロバイダが自らの整合性チェックに使用する基本的な方法を、次に示します。

  1. プロバイダコードを含む JAR ファイルの URL を特定します。
  2. JAR ファイルのデジタル署名を検証して、JAR ファイルの各エントリの少なくとも 1 つの署名者が信頼できることを確認します。

以下のセクションでは、具体的な手順を示します。

サンプルコードについて

プロバイダ JAR ファイルの検索: 基本

プロバイダの JAR ファイル URL の確認

JAR ファイルを参照する JarFile の作成

プロバイダ JAR ファイルの検証: 基本

検証の設定

JAR ファイル署名のチェック

署名の検証

署名者の信頼性の確認

証明書リストの取得

個々の署名者の識別と信頼できる署名者の特定

myJCE サンプルコードについて




サンプルコードについて


注: サンプルコード MyJCE.java は、これらのステップを実装する完全なコード例です。このコードは参照用としてダウンロードできます。上記の概念がどのようにしてサンプルコードに実装されているかについては、「サンプルコードについて」を参照してください。


重要: JCE 1.2.x (JDK 1.2.x および 1.3.x とともに使用される) のバンドルされていないバージョンでは、プラグインする JCA の整合性および信頼性を保証するため、JCA フレームワークの認証用コードをプロバイダに含める必要がありました。JDK 6 では、これは必要なくなりました。

これにより、JCE フレームワークコードはプロバイダの期待する場所に存在しなくなるため、プロバイダの JCE フレームワーク認証チェックが機能しなくなります。このため、JCE 1.2.2 専用に記述されたプロバイダは、JDK 6 では動作しなくなります。プロバイダが JDK 6 でのみ動作するようにするには、JCE フレームワークを認証するコードをプロバイダに含めないようにしてください。プロバイダを JCE 1.2.2 と JDK 6 の両方で動作させる場合は、条件文を追加します。こうしておけば、プロバイダを JCE 1.2.2 で実行する場合にのみ JCE フレームワークを認証するプロバイダコードが実行されるようになります。次に、サンプルコードを示します。

    Class cipherCls = Class.forName("javax.crypto.Cipher");

    CodeSource cs = cipherCls.getProtectionDomain().getCodeSource();
    if (cs != null) {
	// Authenticate JCE framework
. . . }

プロバイダ JAR ファイルの検索: 基本

プロバイダの JAR ファイル URL の確認

プロバイダの JAR ファイルの URL は、プロバイダの CodeSource を確認し、CodeSource に対して getLocation メソッドを呼び出すことにより取得できます。

    URL providerURL = (URL) AccessController.doPrivileged(
	new PrivilegedAction) {
	    public Object run() {
		CodeSource cs =
		    MyJCE.class.getProtectionDomain().getCodeSource();
		return cs.getLocation();
	    }
	}); 

JAR ファイルを参照する JarFile の作成

プロバイダの JAR ファイルの URL を取得したら、JAR ファイルを参照する java.util.jar.JarFile を作成できます。これは、「プロバイダ JAR ファイルの検証」で必要になります。

JAR ファイルを作成するには、まず、openConnection メソッドを呼び出し、指定された URL への接続を確立します。URL は JAR URL であるため、java.net.JarURLConnection 型になります。標準的なコードは以下のとおりです。

    // Prep the url with the appropriate protocol.
    jarURL =
	url.getProtocol().equalsIgnoreCase("jar") ? url :
	    new URL("jar:" + url.toString() + "!/");

    // Retrieve the jar file using JarURLConnection
    JarFile jf = (JarFile) AccessController.doPrivileged(
	new PrivilegedExceptionAction() {
	    public Object run() throws Exception {
		JarURLConnection conn =
		    (JarURLConnection) jarURL.openConnection();
	...  

JarURLConnection を取得できたら、getJarFile メソッドを呼び出して JAR ファイルを取得します。

    // Always get a fresh copy, so we don't have to
    // worry about the stale file handle when the
    // cached jar is closed by some other application.
    conn.setUseCaches(false);
    jf = conn.getJarFile(); 

プロバイダ JAR ファイルの検証: 基本

上記のステップに従ってプロバイダ JAR ファイルの URL を確認し、JAR ファイルを参照する JarFile を作成したら、ファイルの検証を行います。

基本的な方法は以下のとおりです。

  1. 各エントリの署名者の証明書の少なくとも 1 つが、プロバイダ自身のコード署名証明書と等価であることを確認します。
  2. JAR ファイルのすべてのエントリを確認して、各エントリの署名が適切であることを検証します。
  3. 各エントリの署名者の証明書の少なくとも 1 つから、信頼できる証明書発行局までたどれることを確認します。

これらのステップで使用するサンプルコードについては、以下のセクションを参照してください。

検証の設定

JAR ファイル署名のチェック

署名の検証

署名者の信頼性の確認

証明書リストの取得

個々の署名者の識別と信頼できる署名者の特定


検証の設定

ここでは、クラス JarVerifier を定義して指定された URL からの JAR ファイル取得を処理し、JAR ファイルが指定された証明書で署名されているかどうかを検証します。

JarVerifier のコンストラクタはプロバイダ URL をパラメータとして取ります。 これを使用して、JAR ファイルが取得されます。

実際の JAR 検証は、プロバイダコード署名証明書をパラメータとする verify メソッドで実装されます。

    public void verify(X509Certificate targetCert) throws IOException {
	// variable 'jarFile' is a JarFile object created
	// from the provider's Jar URL.
	...
	Vector entriesVec = new Vector(); 

verify は、基本的に JAR ファイルエントリを 2 回使用します。1 回目は各エントリの署名をチェックし、2 回目は署名者が信頼できることを検証します。

注: このコードでは、jarFile 変数は、プロバイダの jar ファイルの JarFile オブジェクトです。

JAR ファイル署名のチェック

認証されたプロバイダ JAR ファイルが署名されます。このため、署名されない JAR ファイルは、改変されています。

    // Ensure the jar file is signed.
    Manifest man = jarFile.getManifest();
    if (man == null) {
	throw new SecurityException("The provider is not signed");
    } 

署名の検証

次のステップでは、JAR ファイルのすべてのエントリを確認して、各エントリの署名が適切であることを検証します。JAR ファイルエントリの署名を検証する 1 つの方法は、単純なファイルの読み取りです。JAR ファイルが署名されていると、read メソッドが自動的に署名の検証を実行します。サンプルコードを次に示します。

    // Ensure all the entries' signatures verify correctly
    byte[] buffer = new byte[8192];
    Enumeration entries = jarFile.entries();

    while (entries.hasMoreElements()) {
	JarEntry je = (JarEntry) entries.nextElement();

	// Skip directories.
	if (je.isDirectory())
	    continue;

	entriesVec.addElement(je);
	InputStream is = jarFile.getInputStream(je);

	// Read in each jar entry. A security exception will
	// be thrown if a signature/digest check fails.
	int n;
	while ((n = is.read(buffer, 0, buffer.length)) != -1) {
	    // Don't care
	}
	is.close();
    }
    

署名者の信頼性の確認

前のセクションのコードでは、すべてのプロバイダ JAR ファイルエントリの署名を検証しました。すべてを適正に検証することは必須ですが、JAR ファイルの認証を確認するだけでは十分ではありません。最終的に、署名がこのプロバイダを構築したものと同じエントリから生成されたことを確認する必要があります。署名が信頼できることをテストするために、JAR ファイル内の各エントリをループ処理し (今回は前のステップで作成した entriesVec を使用)、署名の必要なエントリ (META-INF ディレクトリ内に存在しないディレクトリ以外のエントリ) ごとに次の操作を実行します。

  1. エントリの署名者証明書のリストを取得します。
  2. 個々の証明書チェーンを特定し、信頼できる証明書チェーンがあるかどうかを判定します。信頼できる証明書チェーンが 1 つ以上存在しなければなりません。

ループの設定方法を、次に示します。

    Enumeration e = entriesVec.elements();
    while (e.hasMoreElements()) {
	JarEntry je = (JarEntry) e.nextElement();
	...
    } 

証明書リストの取得

JAR ファイルエントリ JarEntry の署名者の証明書は、JarEntrygetCertificates メソッドを呼び出すだけで取得できます。

    Certificate[] certs = je.getCertificates();

前のループ設定コードに、上記のコードおよび META-INF ディレクトリ内のディレクトリおよびファイルを無視するコードを追加すると、次のようになります。

    while (e.hasMoreElements()) {
	JarEntry je = (JarEntry) e.nextElement();

	// Every file must be signed except files in META-INF.
	Certificate[] certs = je.getCertificates();
	if ((certs == null) || (certs.length == 0)) {
	    if (!je.getName().startsWith("META-INF"))
		throw new SecurityException(
		    "The provider has unsigned class files.");
	    } else {
		// Check whether the file is signed by the expected
		// signer. The jar may be signed by multiple signers.
		// See if one of the signers is 'targetCert'.
		...
	    }
	...  

個々の署名者の識別と信頼できる署名者の特定

JarEntrygetCertificates メソッドが返す証明書配列には、1 つ以上の証明書チェーンが含まれます。エントリの署名者ごとに 1 つのチェーンが存在します。各チェーンには、1 つ以上の証明書が含まれます。チェーン内の各証明書は、前の証明書の公開鍵を認証します。

チェーン内の最初の証明書には、エントリの署名に実際に使用される非公開鍵に対応する公開鍵を含む、署名者の証明書です。そのあとに続く証明書は、それぞれ前の証明書の発行者の証明書になります。自己整合性チェックは、JAR ファイルがプロバイダの署名証明書で署名されているかどうかを基準にしているため、信頼性の判断は最初の証明書である署名者の証明書のみで決定されます。

証明書チェーンの配列内で、「信頼できる」エンティティーが見つかるまで各チェーンおよび関連する署名者をチェックします。JAR ファイルエントリごとに、信頼できる署名者が少なくとも 1 人必要です。署名者が「信頼できる」と判断されるのは、証明書が、埋め込まれたプロバイダ署名証明書と等価である場合に限ります。

次のサンプルコードでは、すべての証明書チェーンでループ処理を行い、チェーンの最初の証明書と埋め込まれたプロバイダ署名証明書とを比較し、一致した場合に true だけを返します。

    int startIndex = 0;
    X509Certificate[] certChain;
    boolean signedAsExpected = false;

    while ((certChain = getAChain(certs, startIndex)) != null) {
	if (certChain[0].equals(targetCert)) {
	    // Stop since one trusted signer is found.
	    signedAsExpected = true;
	    break;
	}

	// Proceed to the next chain.
	startIndex += certChain.length;
    }

    if (!signedAsExpected) {
	throw new SecurityException(
	    "The provider is not signed by a trusted signer");
    }
    

getAChain メソッドは、次のように定義されます。

    /**
     * Extracts ONE certificate chain from the specified certificate array
     * which may contain multiple certificate chains, starting from index
     * 'startIndex'.
     */
    private static X509Certificate[] getAChain(
	    Certificate[] certs, int startIndex) {

	if (startIndex > certs.length - 1)
	    return null;

	int i;
	// Keep going until the next certificate is not the
	// issuer of this certificate.
	for (i = startIndex; i < certs.length - 1; i++) {
	    if (!((X509Certificate)certs[i + 1]).getSubjectDN().
		    equals(((X509Certificate)certs[i]).getIssuerDN())) {
		break;
	    }
	}

	// Construct and return the found certificate chain.
	int certChainSize = (i-startIndex) + 1;
	X509Certificate[] ret = new X509Certificate[certChainSize];
	for (int j = 0; j < certChainSize; j++ ) {
	    ret[j] = (X509Certificate) certs[startIndex + j];
	}
	return ret;
    }
    

myJCE コードサンプルについて

サンプルコード MyJCE.java は、自動的に整合性チェックを実行する selfIntegrityChecking メソッドを備えたサンプルプロバイダです。このコードは、まず固有のプロバイダ JAR ファイルの URL を特定します。 次に、このプロバイダ JAR ファイルに、組み込み済みのコード署名証明書による署名があるかどうかを検証します。

注: selfIntegrityChecking メソッドは、整合性を確保するため、その暗号化エンジンクラスの全コンストラクタによって呼び出されます。

プロバイダ MyJCE は、次のステップで自動的に整合性チェックを行います。

  1. 固有のクラス MyJCE.class を使ってプロバイダ JAR ファイルにアクセスするための URL を特定する

  2. ステップ 1 で特定したプロバイダ URL を使って JarVerifier オブジェクトをインスタンス化します。

  3. 組み込みバイト配列 bytesOfProviderCert から X509Certificate オブジェクトを作成します。

  4. JarVerifier.verify メソッドを呼び出し、プロバイダ JAR ファイル内のすべてのエントリに、ステップ 3 でインスタンス化した同じ証明書による署名があることを検証する

注: JarVerifier クラスは、所定の URL から JAR ファイルを取得し、その JAR ファイルに署名があるか、すべてのエントリに有効な署名があるか、これらのエントリに指定された X509Certificate による署名があるかどうかを検証します。

場合によっては、JarVerifier.verify によってセキュリティー例外がスローされます。

サンプルコード MyJCE.java は、上記のコードで構成されます。さらに、エラー処理、サンプルコード署名証明書バイト、埋め込まれたサンプルコード署名証明書バイトからX509Certificate オブジェクトをインスタンス化するコードが含まれています。

AccessController.doPrivileged の使用については、「特権ブロックのための API」doPrivileged の使用に関する説明を参照してください。

実装の詳細および要件

別名

多くの暗号化のアルゴリズムおよびタイプには、「Java 暗号化アーキテクチャーリファレンスガイド」の「付録 A」で定義された公式な「標準名」が 1 つ存在します。

たとえば、「MD5」は、RFC 1321 の RSA DSI で定義された RSA-MD5 メッセージダイジェストアルゴリズムの標準名です。DiffieHellman は、PKCS3 で定義された Diffie-Hellman 鍵協定アルゴリズムの標準です。

JDK では、アルゴリズムまたはタイプへの参照時に、クライアントが標準名ではなく別名を使用することを可能にするエイリアス化方式が存在します。たとえば、「SUN」プロバイダのマスタークラス (Sun.java) は、標準名が「SHA1withDSA」であるアルゴリズムの別名「SHA1/DSA」を定義します。このため、次の文は同じ意味になります。

    Signature sig = Signature.getInstance("SHA1withDSA", "SUN");

    Signature sig = Signature.getInstance("SHA1/DSA", "SUN");

別名は、「マスタークラス」内で定義できます (ステップ 3 を参照)。別名を定義するには、次の名前のプロパティーを作成します。

    Alg.Alias.engineClassName.aliasName

engineClassName にはエンジンクラス (Signature など) の名前が、aliasName には設定する別名が当てはまります。プロパティーの値は、別名を設定するアルゴリズム (またはタイプ) の標準アルゴリズム (またはタイプ) 名でなければなりません。

例として、「SUN」プロバイダが、Alg.Alias.Signature.SHA1/DSA という名前のプロパティーに値 SHA1withDSA を設定することにより、標準名が SHA1withDSA である署名アルゴリズムに別名「SHA1/DSA」を定義する場合を考えましょう。次にそのコードを示します。

    put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA");

あるプロバイダによって定義された別名は、そのプロバイダのみが使用でき、その他のプロバイダは使用できません。したがって、SunJCE プロバイダによって定義された別名は、SunJCE プロバイダのみが使用できます。

サービスの相互依存性

アルゴリズムによっては、他の種類のアルゴリズムの使用を要求することがあります。たとえば、通常、PBE アルゴリズムは、メッセージダイジェストアルゴリズムを使用して、パスワードを鍵に変換する必要があります。

別のアルゴリズムを要求するアルゴリズムを実装している場合、次のいずれかを実行できます。

  1. どちらのアルゴリズムにも対応した独自の実装の提供。
  2. すべての Java SE プラットフォームのインストールに含まれるデフォルトの SUN プロバイダにより提供される場合のように、一方のアルゴリズムの実装が他方のアルゴリズムのインスタンスを使用するようにします。たとえば、実装している PBE アルゴリズムがメッセージダイジェストアルゴリズムを要求する場合、次の呼び出しを行うことにより、MD5 メッセージダイジェストアルゴリズムを実装するクラスのインスタンスを取得できます。

        MessageDigest.getInstance("MD5", "SUN")
  3. 別の特定のプロバイダにより提供される場合のように、一方のアルゴリズムの実装が他方のアルゴリズムのインスタンスを使用するようにします。これは、プロバイダを使用するすべてのクライアントが、インストールされた他方のプロバイダも保持する場合にだけ有効な方法です。
  4. 別の (無指定の) プロバイダにより提供される場合のように、一方のアルゴリズムの実装が他方のアルゴリズムのインスタンスを使用するようにします。つまり、アルゴリズムを名前で要求できます。ただし、特定のプロバイダは指定しません。次に例を示します。
        MessageDigest.getInstance("MD5")
    これは、プロバイダが使用される各 Java プラットフォームにインストールされた、要求されたアルゴリズムの実装 (この例では MD5) が少なくとも 1 つ存在することが確実な場合にだけ有効な方法です。

次に、アルゴリズムの相互依存の一般的な種類を示します。

署名アルゴリズムとメッセージダイジェストアルゴリズム

署名アルゴリズムは、メッセージダイジェストアルゴリズムを要求することがあります。たとえば、SHA1withDSA 署名アルゴリズムは、SHA-1 メッセージダイジェストアルゴリズムを要求します。

署名アルゴリズムと (擬似) 乱数生成アルゴリズム

署名アルゴリズムは、(擬似) 乱数生成アルゴリズムを要求することがあります。たとえば、DSA 署名を生成するためには、対応する乱数生成アルゴリズムが必要です。

鍵のペア生成アルゴリズムとメッセージダイジェストアルゴリズム

鍵のペア生成アルゴリズムは、メッセージダイジェストアルゴリズムを要求することがあります。たとえば、DSA 鍵は、SHA-1 メッセージダイジェストアルゴリズムを使って生成されます。

アルゴリズムパラメータ生成とメッセージダイジェストアルゴリズム

アルゴリズムパラメータジェネレータは、メッセージダイジェストアルゴリズムの使用を要求することがあります。たとえば、DSA パラメータは、SHA-1 メッセージダイジェストアルゴリズムを使って生成されます。

KeyStores とメッセージダイジェストアルゴリズム

キーストア実装は、メッセージダイジェストアルゴリズムを利用してキーハッシュ (key はユーザーが提供するパスワード) を計算し、キーストアの統合性検査、およびキーストアが改変されていないことを確認することがあります。

鍵のペア生成アルゴリズムとアルゴリズムパラメータジェネレータ

鍵のペア生成アルゴリズムは、新規アルゴリズムパラメータセットの生成を必要とする場合があります。パラメータは、直接生成するか、アルゴリズムパラメータジェネレータを使用して生成できます。

鍵のペア生成、アルゴリズムパラメータ生成、および (擬似) 乱数生成アルゴリズム

鍵のペア生成アルゴリズムは、新しい鍵ペアおよび (場合によっては) 鍵に関連付けられた新規パラメータセットの生成に、乱数の発生源を必要とする場合があります。乱数の発生源は、SecureRandom オブジェクトにより表されます。鍵ペア生成アルゴリズムの実装は、鍵パラメータ自体を生成する場合もあれば、アルゴリズムパラメータジェネレータを使って鍵パラメータを生成する場合もあります。これらの場合、乱数の発生源を使ってアルゴリズムパラメータジェネレータを初期化する場合もあれば、そうでない場合もあります。

アルゴリズムパラメータジェネレータおよびアルゴリズムパラメータ

アルゴリズムパラメータジェネレータの engineGenerateParameters メソッドは、AlgorithmParameters インスタンスを返す必要があります。

署名および鍵ペア生成アルゴリズムまたは鍵ファクトリ

署名アルゴリズムを実装している場合、実装の engineInitSign メソッドおよび engineInitVerify メソッドは、基礎となるアルゴリズム (DSS アルゴリズム用の DSA 鍵など) に対して有効な、引き渡しの行われる鍵を必要とします。次のいずれかを実行できます。

  1. 適切なインタフェースを実装する独自のクラス (java.security.interfaces パッケージから DSAPrivateKey および DSAPublicKey インタフェースを実装するクラスなど) も作成し、独自の鍵ペアのジェネレータとこれらのタイプの鍵を返す鍵ファクトリのどちらかまたは両方を作成します。engineInitSign および engineInitVerify に渡される鍵が、実装した鍵 (つまり、鍵ペアジェネレータまたは鍵ファクトリから生成された鍵) と同じタイプである必要があります。または、次の方法も可能です。

  2. 他の鍵ペアジェネレータまたは他の鍵ファクトリから鍵を受け取ります。これは、それらが署名の実装が必要な情報 (非公開鍵、公開鍵および鍵パラメータなど) を取得することを可能にする適切なインタフェースのインスタンスである場合に限り有効です。たとえば、DSS Signature クラス用の engineInitSign メソッドは、java.security.interfaces.DSAPrivateKey のインスタンスである任意の非公開鍵を受け取ることができます。

キーストアと 鍵および証明書ファクトリ

キーストアの実装は、鍵ファクトリを利用してキーストアに格納された鍵の構文解析を行うことがあります。また、証明書ファクトリを利用してキーストアに格納された証明書の構文解析を行います。

デフォルトの初期化

クライアントが明示的に鍵ペアジェネレータまたはアルゴリズムパラメータジェネレータを初期化しない場合、これらサービスの各プロバイダはデフォルトの初期化を提供 (およびドキュメント化) する必要があります。たとえば、Sun プロバイダは、DSA パラメータの生成に 1024 ビットのデフォルトモジュラスサイズ (強度) を使用し、SunJCE プロバイダは、Diffie-Hellman パラメータの生成に 1024 ビットのデフォルトモジュラスサイズ (キーサイズ) を使用します。

デフォルトの鍵ペアジェネレータのパラメータの要件

鍵ペアジェネレータを実装する場合、クライアントがパラメータを指定しない場合は、実装がデフォルトのパラメータを提供する必要があります。提供するドキュメント (ステップ 11) で、デフォルトパラメータを指定する必要があります。

たとえば、SUN プロバイダの DSA 鍵ペアジェネレータは、512、768、および 1024 ビットの鍵ペア生成用に、計算済みの pq、および g デフォルト値のセットを提供します。次の pq、および g 値は、1024 ビット DSA 鍵ペア生成用のデフォルト値として使用されます。

p = fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80
    b6512669 455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b
    801d346f f26660b7 6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6
    1bf83b57 e7c6a8a6 150f04fb 83f6d3c5 1ec30235 54135a16 9132f675
    f3ae2b61 d72aeff2 2203199d d14801c7

q = 9760508f 15230bcc b292b982 a2eb840b f0581cf5

g = f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b
    3d078267 5159578e bad4594f e6710710 8180b449 167123e8 4c281613
    b7cf0932 8cc8a6e1 3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f
    0bfa2135 62f1fb62 7a01243b cca4f1be a8519089 a883dfe1 5ae59f06
    928b665e 807b5525 64014c3b fecf492a

(ここで指定された p および q 値は、素数生成標準により、次の 160 ビットのシードを使って生成されます。

SEED:  8d515589 4229d5e6 89ee01e6 018a237e 2cae64cd

このシードでは、カウンタが 92 の時に p および q を検出しました。)

Provider.Service クラス

導入されて以来、セキュリティープロバイダは Hashtable エントリに入力された適切なフォーマットのキーと値の String ペアを使用して、サービス情報を公開してきました。この機構はシンプルで簡便ですが、カスタマイズの範囲が限られています。そのため、JDK 5.0 では、2 番目のオプションとして、Provider.Service クラスが導入されました。これを利用して、プロバイダはサービスおよびサポートに、以下で説明するような追加機能を通知できます。この追加機能は、String 値の HashTable エントリを使用する以前の方法と完全な互換性があることに留意してください。JDK 5.0 では、プロバイダはどちらの方法も選択でき、また同時に両方を使用することもできます。

Provider.Service オブジェクトは、サービスに関するすべての情報をカプセル化します。このプロバイダは、サービス、型 (MessageDigestSignature など)、アルゴリズム名、およびサービスを実装するクラス名を提供します。また、このサービス (別名) および属性に対する代替アルゴリズム名の一覧を持っています。 この一覧は、名前と値の String ペアのマップです。さらに、newInstance() および supportsParameter() メソッドを定義します。これらのメソッドはデフォルトで実装されていますが、プロバイダがハードウェアセキュリティートークンとのインタフェースとなる場合は、必要に応じてプロバイダによるオーバーライドが可能です。

newInstance() メソッドは、新しい実装インスタンスを生成する必要がある場合に、セキュリティーフレームワークによって使用されます。デフォルトの実装では、リフレクションを使用してサービス各種の標準的なコンストラクタが呼び出されます。CertStore を除くすべての標準サービスで、このコンストラクタは引数をとりません。newInstance()constructorParameter は、この場合 null である必要があります。CertStore 型のサービスでは、CertStoreParameters オブジェクトを使用するコンストラクタが呼び出されます。constructorParameter は、CertStoreParameters の null 以外のインスタンスである必要があります。セキュリティープロバイダは、newInstance() をオーバーライドして、その実装に適したインスタンス化を実装できます。直接呼び出すことも、Provider インスタンスまたはトークンに固有の追加情報を渡すコンストラクタを呼び出すこともできます。たとえば、システムに複数のスマートカードリーダがある場合、新しく作成されたサービスをどのリーダーに関連付けるかという情報を渡すことができます。ただし、カスタマイズした場合でも、すべての実装は、上述の constructorParameter に関する規約に従わなければなりません。

supportsParameter() は、Service が指定されたパラメータを使用できるかどうかをテストします。このサービスがパラメータを使用できない場合、false を返します。このサービスがパラメータを使用できる場合、すばやいチェックが実行できない場合、またはステータスが不明な場合、true を返します。これは、ある種のサービスに対してセキュリティーフレームワークにより使用され、一致しない実装が対象からすばやく除外されます。現状では、これは SignatureCipherMac、および KeyAgreement の標準サービスでのみ定義されています。この場合、parameterKey のインスタンスである必要があります。たとえば、Signature サービスの場合、フレームワークはサービスをインスタンス化する前に、サービスが指定された Key を使用できるかどうかをテストします。デフォルトの実装では、前述のように、属性 SupportedKeyFormats および SupportedKeyClasses が検査されます。ここでも、プロバイダはこのメソッドをオーバーライドして、追加テストを実装できます。

SupportedKeyFormats 属性は、符号化された鍵 (key.getFormat() によって返される) でサポートされる形式の一覧で、「|」(パイプ) 文字で区切られています。たとえば、X.509|PKCS#8 のようになります。SupportedKeyClasses 属性は、インタフェースまたはクラス名の一覧で、「|」文字で区切られています。鍵オブジェクトは、指定されたクラスまたはインタフェースの 1 つ以上に割り当て可能な場合に、受け入れ可能と認識されます。言い換えれば、鍵オブジェクトのクラスがリスト表示されたいずれかのクラスのサブクラス (またはクラス自体) である場合、またはリスト表示されたインタフェースを実装する場合です。たとえば、値 "java.security.interfaces.RSAPrivateKey|java.security.interfaces.RSAPublicKey" がこれに該当します。

サービスの追加および検索用の 4 つのメソッドが Provider クラスに追加されました。前述のように、これらのメソッドおよび既存の Properties メソッドの実装は、既存の Provider サブクラスとの互換性を保つように特別に設計されています。次のようにして実現されます。

既存の Properties メソッドをエントリの追加に使用する場合、Provider クラスは、プロパティー文字列を解析して等価な Service オブジェクトに変換してから、 getService() を使用して検索するようにします。同様に、putService() メソッドを使用する場合、等価なプロパティー文字列がプロバイダのハッシュテーブルに同時に配置されます。プロバイダ実装が Provider クラス内のメソッドをオーバーライドする場合、実装がこの変換に干渉しないようにする必要があります。問題を防止するため、実装によって Provider クラスのメソッドがオーバーライドされないようにすることをお勧めします。

署名フォーマット

署名アルゴリズムを実装する場合、提供するドキュメント (ステップ 11) で署名 (sign メソッドの 1 つを使って生成される) を符号化する形式を指定する必要があります。

たとえば、SUN プロバイダにより提供される SHA1withDSA 署名アルゴリズムは、署名を 2 つの ASN.1 INTEGER 値の標準 ASN.1 シーケンスとして符号化します。r および s (この順序):

SEQUENCE ::= {
	r INTEGER,
	s INTEGER }

DSA インタフェースおよびその実装要件

Java Security API には、DSA サービスを実装するプログラマが利用しやすいように、(java.security.interfaces パッケージ内の) 次のインタフェースが含まれます。

以降では、これらのインタフェースの実装要件について取り上げます。

DSAKeyPairGenerator 実装

このインタフェースは使用されていません。これは、クライアントに対し、実装が提供するデフォルトパラメータの代わりに DSA 固有のパラメータを使用することを可能にする上で必要でした。ただし、AlgorithmParameterSpec パラメータを取る新規 KeyPairGenerator initialize メソッドにより、クライアントがアルゴリズム固有のパラメータを示すことが可能になったため、Java ではこれは必要ではなくなりました。

DSAParams 実装

DSA 鍵ペアジェネレータを実装している場合、pq、および g パラメータを保持したり返したりするために、DSAParams を実装するクラスを必要とします。

DSAPrivateKey および DSAPublicKey インタフェースを実装する場合は、DSAParams 実装も必要です。DSAPublicKey および DSAPrivateKey は、どちらも DSAParams オブジェクトを返す getParams メソッドを含む DSAKey インタフェースを継承します。詳細は、「DSAPrivateKey および DSAPublicKey 実装」を参照してください。

注: JDK に組み込み済みの DSAParams 実装であるjava.security.spec.DSAParameterSpec クラスが存在します。

DSAPrivateKey および DSAPublicKey 実装

DSA 鍵ペアジェネレータまたは鍵ファクトリを実装する場合、DSAPrivateKey および DSAPublicKey インタフェースを実装するクラスを作成する必要があります。

DSA 鍵ペアジェネレータを実装する場合、(KeyPairGeneratorSpi サブクラスの) generateKeyPair メソッドはこれらのインタフェース実装のインスタンスを返します。

DSA 鍵ファクトリを実装する場合、(KeyFactorySpi サブクラスの) engineGeneratePrivate メソッドは DSAPrivateKey 実装のインスタンスを返し、engineGeneratePublic メソッドは DSAPublicKey 実装のインスタンスを返します。

また、engineGetKeySpec および engineTranslateKey メソッドは、引き渡される鍵が DSAPrivateKey または DSAPublicKey 実装のインスタンスであることを求めます。インタフェース実装により提供される getParams メソッドは、鍵からパラメータを取得および抽出し、その後パラメータを使用する上で有用です。たとえば、DSAParameterSpec コンストラクタへのパラメータとして使用して、DSA 用の KeyPairGenerator オブジェクトの初期化に使用可能なパラメータ値からパラメータ仕様を作成することができます。

DSA 署名アルゴリズムを実装する場合、(SignatureSpi サブクラスの) engineInitSign メソッドは DSAPrivateKey が渡されることを期待し、engineInitVerify メソッドは DSAPublicKey が渡されることを期待します。

注 -DSAPublicKey および DSAPrivateKey インタフェースはそれぞれ、DSA 公開鍵および非公開鍵に対する非常に一般的なプロバイダ非依存のインタフェースを定義します。KeyFactorySpi サブクラスの engineGetKeySpec メソッドと engineTranslateKey メソッドは、プロバイダ固有の実装の詳細を利用するなどの目的で、引き渡される鍵が実際にプロバイダ独自の DSAPrivateKey または DSAPublicKey 実装のインスタンスであるかどうかをチェックすることもできます。SignatureSpi サブクラスの DSA 署名アルゴリズム engineInitSign および engineInitVerify メソッドについても、同様のことが当てはまります。

DSAPublicKey および DSAPrivateKey インタフェースを実装するクラスを使用してどのようなメソッドを実装する必要があるかについては、次のインタフェース署名に注目してください。

java.security.interfaces パッケージ内:

   public interface DSAPrivateKey extends DSAKey,
		java.security.PrivateKey

   public interface DSAPublicKey extends DSAKey,
		java.security.PublicKey

   public interface DSAKey 

java.security パッケージ内:

   public interface PrivateKey extends Key

   public interface PublicKey extends Key

   public interface Key extends java.io.Serializable 

DSAPrivateKey インタフェースと DSAPublicKey インタフェースを実装するには、これらによって定義されるメソッドと、直接または間接的にこれらによって拡張されるインタフェースによって定義されたメソッドを実装する必要があります。

このため、非公開鍵の場合、以下を実装するクラスを提供する必要があります。

  • DSAPrivateKey インタフェースから getX メソッド。

  • java.security.interfaces.DSAKey インタフェースから getParams メソッド。これは、DSAPrivateKeyDSAKey を拡張するためです。注: getParams メソッドは、DSAParams オブジェクトを返します。このため、DSAParams 実装も保持する必要があります。

  • java.security.Key インタフェースの getAlgorithmgetEncoded、および getFormat メソッド (DSAPrivateKeyjava.security.PrivateKey を拡張し、PrivateKeyKey を拡張するため)。

      同様に、公開 DSA 鍵の場合、次のものを実装するクラスを提供する必要があります。

      • DSAPublicKey インタフェースから getY メソッド。

      • java.security.interfaces.DSAKey インタフェースから getParams メソッド。これは、DSAPublicKey が DSAKey を拡張するためです。注: getParams メソッドは、DSAParams オブジェクトを返します。このため、DSAParams 実装も保持する必要があります。

      • java.security.Key インタフェースの getAlgorithmgetEncoded、および getFormat メソッド (DSAPublicKeyjava.security.PublicKey を拡張し、PublicKeyKey を拡張するため)。

    RSA インタフェースおよびその実装要件

    Java Security API には、RSA サービスを実装するプログラマが利用しやすいように、(java.security.interfaces パッケージ内の) 次のインタフェースが含まれます。

    以降では、これらのインタフェースの実装要件について取り上げます。

    RSAPrivateKey RSAPrivateCrtKey、および RSAPublicKey 実装

    RSA 鍵ペアジェネレータまたは鍵ファクトリを実装する場合、RSAPrivateKey (と RSAPrivateCrtKey のどちらかまたは両方) および RSAPublicKey インタフェースを実装するクラスを作成する必要があります。(RSAPrivateCrtKey は、中国剰余定理 (CRT) 表現を使用した、RSA 非公開鍵へのインタフェースです。

    RSA 鍵ペアジェネレータを実装する場合、(KeyPairGeneratorSpi サブクラスの) generateKeyPair メソッドはこれらのインタフェース実装のインスタンスを返します。

    RSA 鍵ファクトリを実装する場合、(KeyFactorySpi サブクラスの) engineGeneratePrivate メソッドは RSAPrivateKey (または RSAPrivateCrtKey) 実装のインスタンスを返し、engineGeneratePublic メソッドは RSAPublicKey 実装のインスタンスを返します。

    また、engineGetKeySpec および engineTranslateKey メソッドは、引き渡される鍵が RSAPrivateKeyRSAPrivateCrtKey、または RSAPublicKey 実装のインスタンスであることを求めます。

    RSA 署名アルゴリズムを実装する場合、(SignatureSpi サブクラスの) engineInitSign メソッドは RSAPrivateKey または RSAPrivateCrtKey が渡されることを期待し、engineInitVerify メソッドは RSAPublicKey が渡されることを期待します。

    注 -RSAPublicKeyRSAPrivateKey、および RSAPrivateCrtKey インタフェースはそれぞれ、RSA 公開鍵および非公開鍵に対する非常に一般的なプロバイダ非依存のインタフェースを定義します。KeyFactorySpi サブクラスの engineGetKeySpec メソッドと engineTranslateKey メソッドは、プロバイダ固有の実装の詳細を利用するなどの目的で、引き渡される鍵が実際にプロバイダ独自の RSAPrivateKeyRSAPrivateCrtKey、または RSAPublicKey 実装のインスタンスであるかどうかをチェックすることもできます。SignatureSpi サブクラスの RSA 署名アルゴリズム engineInitSign および engineInitVerify メソッドについても、同様のことが当てはまります。

    RSAPublicKeyRSAPrivateKey、および RSAPrivateCrtKey インタフェースを実装するクラスを使用してどのようなメソッドを実装する必要があるかについては、次のインタフェース署名に注目してください。

    java.security.interfaces パッケージ内:

        public interface RSAPrivateKey extends java.security.PrivateKey
    
        public interface RSAPrivateCrtKey extends RSAPrivateKey
    
        public interface RSAPublicKey extends java.security.PublicKey
    
    

    java.security パッケージ内:

        public interface PrivateKey extends Key
    
        public interface PublicKey extends Key
    
        public interface Key extends java.io.Serializable
    

    RSAPrivateKeyRSAPrivateCrtKey、および RSAPublicKey インタフェースを実装するには、これらによって定義されるメソッドと、直接または間接的にこれらによって拡張されるインタフェースによって定義されたメソッドを実装する必要があります。

    このため、RSA 非公開鍵の場合、次のものを実装するクラスを提供する必要があります。

    同様に、中国剰余定理 (CRT) 表現を使用する RSA 非公開鍵の場合、次のものを実装するクラスを提供する必要があります。

    公開 RSA 鍵の場合、次のものを実装するクラスを提供する必要があります。

    JCA には、よく使用される暗号化および鍵協定アルゴリズムパラメータの AlgorithmParameterSpec 実装が多数含まれています。JCA から提供されない、種類の異なるアルゴリズムに対応したアルゴリズムパラメータを操作する場合は、その種類に適した独自の AlgorithmParameterSpec 実装を提供する必要があります。

    Diffie-Hellman インタフェースおよびその実装要件

    Diffie-Hellman サービスを実装するプログラマのために、JCA には次のインタフェースが (javax.crypto.interfaces パッケージ内に) 用意されています。

    以降では、これらのインタフェースの実装要件について取り上げます。

    DHPrivateKey および DHPublicKey の実装

    Diffie-Hellman 鍵ペアジェネレータまたは鍵ファクトリを実装する場合、DHPrivateKey および DHPublicKey インタフェースを実装するクラスを作成する必要があります。

    Diffie-Hellman 鍵ペアジェネレータを実装する場合、(KeyPairGeneratorSpi サブクラスの) generateKeyPair メソッドはこれらのインタフェース実装のインスタンスを返します。

    Diffie-Hellman 鍵ファクトリを実装する場合、(KeyFactorySpi サブクラスの) engineGeneratePrivate メソッドは DHPrivateKey 実装のインスタンスを返し、engineGeneratePublic メソッドは DHPublicKey 実装のインスタンスを返します。

    また、engineGetKeySpec および engineTranslateKey メソッドは、引き渡される鍵が DHPrivateKey または DHPublicKey 実装のインスタンスであることを求めます。インタフェース実装によって提供された getParams メソッドは、鍵からパラメータを取得および抽出する場合に便利です。その後、これらのパラメータを、パラメータ値からパラメータ仕様を作成するために呼び出される DHParameterSpec コンストラクタのパラメータとして利用することにより、KeyPairGenerator オブジェクトを Diffie-Hellman 用として初期化できます。

    Diffie-Hellman 鍵協定アルゴリズムを実装する場合、KeyAgreementSpi サブクラスの engineInit メソッドは DHPrivateKey が渡されることを求めます。また、engineDoPhase メソッドは DHPublicKey が渡されることを求めます。

    注: DHPublicKey および DHPrivateKey インタフェースはそれぞれ、Diffie-Hellman 公開鍵および非公開鍵に対する非常に一般的なプロバイダ非依存のインタフェースを定義します。KeyFactorySpi サブクラスの engineGetKeySpec メソッドと engineTranslateKey メソッドは、プロバイダ固有の実装の詳細を利用するなどの目的で、引き渡される鍵が実際にプロバイダ独自の DHPrivateKey または DHPublicKey 実装のインスタンスであるかどうかをチェックすることもできます。KeyAgreementSpi サブクラスに含まれている Diffie-Hellman アルゴリズムの engineInit メソッドと engineDoPhase メソッドについても同じことが言えます。

    DHPublicKey および DHPrivateKey インタフェースを実装するクラスを使ってどんなメソッドを実装する必要があるかについては、次のインタフェース署名に注目してください。

    javax.crypto.interfaces パッケージ内:

        public interface DHPrivateKey extends DHKey, java.security.PrivateKey
    
        public interface DHPublicKey extends DHKey, java.security.PublicKey
    
        public interface DHKey 

    java.security パッケージ内:

        public interface PrivateKey extends Key
    
        public interface PublicKey extends Key
    
        public interface Key extends java.io.Serializable 

    DHPrivateKey インタフェースと DHPublicKey インタフェースを実装するには、これらによって定義されるメソッドと、直接または間接的にこれらによって拡張されるインタフェースによって定義されたメソッドを実装する必要があります。

    このため、非公開鍵の場合、以下を実装するクラスを提供する必要があります。

    • DHPrivateKey インタフェースの getX メソッド。
    • javax.crypto.interfaces.DHKey インタフェースの getParams メソッド (DHPrivateKeyDHKey を拡張するため)。
    • java.security.Key インタフェースの getAlgorithmgetEncoded、および getFormat メソッド (DHPrivateKeyjava.security.PrivateKey を拡張し、PrivateKeyKey を拡張するため)。

    同様に、公開 Diffie-Hellman 鍵の場合、以下を実装するクラスを提供する必要があります。

    • DHPublicKey インタフェースの getY メソッド。
    • javax.crypto.interfaces.DHKey インタフェースの getParams メソッド (DHPublicKeyDHKey を拡張するため)。
    • java.security.Key インタフェースの getAlgorithmgetEncoded、および getFormat メソッド (DHPublicKeyjava.security.PublicKey を拡張し、PublicKeyKey を拡張するため)。

    他のアルゴリズムタイプ用インタフェース

    これまでに説明したとおり、Java Security API には、DSA、RSA、ECC などのサービスを実装するプログラマの利用に便利なインタフェースが含まれます。API サポートがないサービスがある場合、独自の API を定義する必要があります。

    異なるアルゴリズム用の鍵ペアジェネレータを実装する場合、実装が提供するデフォルトパラメータではなく、アルゴリズム固有のパラメータをクライアントが提供して使用する場合にクライアントが呼び出すことのできる 1 つ以上の initialize メソッドを使ってインタフェースを作成する必要があります。KeyPairGeneratorSpi のサブクラスは、このインタフェースを実装する必要があります。

    直接の API サポートがないアルゴリズムの場合は、同様のインタフェースを作成して、実装クラスを提供することをお勧めします。公開鍵のインタフェースは、 PublicKey インタフェースを継承する必要があります。同様に、非公開鍵のインタフェースは、PrivateKey インタフェースを継承する必要があります。

    アルゴリズムパラメータの仕様のインタフェースおよびクラス

    アルゴリズムパラメータの仕様は、アルゴリズムとともに使われるパラメータのセットの透明な表現です。

    パラメータのセットの「透明な」表現とは、対応する仕様クラスに定義された get メソッドの 1 つを使用して、各値に個々にアクセスできるということです。たとえば、DSAParameterSpec は、getPgetQgetG メソッドを定義して、パラメータ p、q、g にアクセスします。

    これと対照的なのが、AlgorithmParameters エンジンクラスによって提供される場合のような「不透明な」表現です。この場合は、鍵データ値に直接アクセスすることはできません。パラメータセットに関連付けられたアルゴリズム名の取得 (getAlgorithm による)、およびそのパラメータセット用のある種の符号化の取得 (getEncoded による) しかできません。

    AlgorithmParametersSpiAlgorithmParameterGeneratorSpiKeyPairGeneratorSpi のいずれかの実装を提供する場合、AlgorithmParameterSpec インタフェースを利用する必要があります。理由は、これらの各クラスに、AlgorithmParameterSpec パラメータをとるメソッドが含まれるからです。この種のメソッドは、インタフェースのどの実装が実際に引き渡されるかを判定し、それに応じて動作する必要があります。

    JCA には、よく使用される署名、暗号化、および鍵協定アルゴリズムパラメータの AlgorithmParameterSpec 実装が多数含まれています。JCA から提供されない、種類の異なるアルゴリズムに対応したアルゴリズムパラメータを操作する場合は、その種類に適した独自の AlgorithmParameterSpec 実装を提供する必要があります。

    Java は、次のアルゴリズムパラメータ仕様インタフェースおよびクラスを、java.security.spec および javax.crypto.spec パッケージ内で定義します。

    AlgorithmParameterSpec インタフェース

    AlgorithmParameterSpec は、暗号化パラメータの透明な仕様へのインタフェースです。

    このインタフェースには、メソッドまたは定数が含まれていません。このインタフェースの唯一の目的は、すべてのパラメータの仕様をグループ化すること (およびそれらのパラメータに安全な型を提供すること) です。すべてのパラメータの仕様で、このインタフェースを実装する必要があります。

    DSAParameterSpec クラス

    AlgorithmParameterSpec および DSAParams インタフェースを実装するこのクラスは、DSA アルゴリズムで使用されるパラメータのセットを指定します。このクラスには、次のメソッドがあります。

        public BigInteger getP()
    
        public BigInteger getQ()
    
        public BigInteger getG()
    

    これらのメソッドは、DSA アルゴリズムパラメータであるプライムの p、サブプライムの q、およびベースの g を返します。

    多くの DSA サービスタイプは、このクラスを有用とみなします。たとえば、このクラスは、SUN プロバイダが実装する DSA 署名、鍵ペアジェネレータ、アルゴリズムパラメータジェネレータ、およびアルゴリズムパラメータクラスにより利用されます。具体例を挙げると、アルゴリズムパラメータ実装は、AlgorithmParameterSpec を返す getParameterSpec メソッド用の実装を含む必要があります。SUN により提供される DSA アルゴリズムパラメータ実装は、DSAParameterSpec クラスのインスタンスを返します。

    IvParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、フィードバックモードでの暗号化に使用される初期化ベクトル (IV) を指定します。

    IvParameterSpec のメソッド
    メソッド 説明
    byte[] getIV() 初期化ベクトル (IV) を返します。

    OAEPParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、フィードバックモードでの暗号化に使用される初期化ベクトル (IV) を指定します。

    IvParameterSpec のメソッド
    メソッド 説明
    byte[] getIV() 初期化ベクトル (IV) を返します。

    PBEParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、パスワードベースの暗号化 (PBE) アルゴリズムで使用されるパラメータのセットを指定します。

    PBEParameterSpec のメソッド
    メソッド 説明
    int getIterationCount() 繰り返し処理の回数を返します。
    byte[] getSalt() salt を返します。

    RC2ParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、RC2 アルゴリズムで使われるパラメータのセットを指定します。

    RC2ParameterSpec のメソッド
    メソッド 説明
    boolean equals (Object obj) 指定されたオブジェクトと現在のオブジェクトが等価であるかどうかをテストします。
    int getEffectiveKeyBits() 有効なキーサイズをビット単位で返します。
    byte[] getIV() IV を返します。このパラメータセットに IV が含まれない場合は null を返します。
    int hashCode() オブジェクトのハッシュコード値を計算します。

    RC5ParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、RC5 アルゴリズムで使われるパラメータのセットを指定します。

    RC5ParameterSpec のメソッド
    メソッド 説明
    boolean equals (Object obj) 指定されたオブジェクトと現在のオブジェクトが等価であるかどうかをテストします。
    byte[] getIV() IV を返します。このパラメータセットに IV が含まれない場合は null を返します。
    int getRounds() ラウンド回数を返します。
    int getVersion() バージョンを返します。
    int getWordSize() ワードサイズをビット単位で返します。
    int hashCode() オブジェクトのハッシュコード値を計算します。

    DHParameterSpec クラス

    このクラス (AlgorithmParameterSpec インタフェースを実装) は、Diffie-Hellman アルゴリズムで使われるパラメータのセットを指定します。

    DHParameterSpec のメソッド
    メソッド 説明
    BigInteger getG() ベースジェネレータ g を返します。
    int getL() ランダム指数 (非公開の値) のサイズ l をビット単位で返します。
    BigInteger getP() prime モジュール p を返します。

    このクラスは、多くの Diffie-Hellman サービス型にとって有用です。たとえば、このクラスは、「SunJCE」プロバイダが実装する Diffie-Hellman 鍵協定、鍵ペアジェネレータ、アルゴリズムパラメータジェネレータ、およびアルゴリズムパラメータクラスにより利用されます。具体例を挙げると、アルゴリズムパラメータ実装は、AlgorithmParameterSpec を返す getParameterSpec メソッド用の実装を含む必要があります。「SunJCE」により提供される Diffie-Hellman アルゴリズムパラメータ実装は、DHParameterSpec クラスのインスタンスを返します。

    鍵ファクトリにより要求される鍵仕様のインタフェースおよびクラス

    鍵ファクトリは、不透明な鍵 (Key タイプ) と鍵仕様との間の双方向変換を提供します。このため、鍵ファクトリを実装する場合には、鍵仕様を理解して利用することが必要になります。場合によっては、独自の鍵仕様を実装する必要もあります。

    鍵仕様、Java で提供されるインタフェースとクラス、および仕様に関する鍵ファクトリの要件についての詳細は、後述します。

    鍵仕様は、鍵を構成する鍵データの透明な表現です。鍵がハードウェアデバイス上に格納されている場合は、その鍵仕様には、デバイス上の鍵の識別を助ける情報が含まれていることがあります。

    鍵の「透明な」表現とは、対応する仕様クラスで定義された get メソッドの 1 つを使用して、各鍵データに個々にアクセスできるということです。たとえば、java.security.spec.DSAPrivateKeySpec は、getXgetPgetQ、および getG メソッドを定義し、非公開鍵 x および鍵の計算に使用する DSA アルゴリズムのパラメータにアクセスします。プライムの p、サブプライムの q、およびベースの g を返します。

    これと対照的なのが、Key インタフェースによって定義されるような、「不透明な」表現です。「不透明な」表現では、パラメータフィールドに直接アクセスできません。つまり、「不透明」さにより、鍵へのアクセスが、Key インタフェースによって定義されるgetAlgorithmgetEncoded、および getFormat の 3 つのメソッドだけに制限されます。

    鍵は、アルゴリズム特定型か、またはアルゴリズム独立型の符号化形式 (ASN.1 など) の方法で指定できます。たとえば、DSA 非公開鍵は、非公開鍵のコンポーネント xpq、および g によって指定するか (DSAPrivateKeySpec を参照)、または、非公開鍵の DER 符号化を使って指定することが可能です (PKCS8EncodedKeySpec を参照)。

    Java は、次の鍵仕様インタフェースおよびクラスを、java.security.spec および javax.crypto.spec パッケージ内で定義します。

    KeySpec インタフェース

    このインタフェースには、メソッドまたは定数が含まれていません。このインタフェースの唯一の目的は、すべての鍵仕様をグループ化すること (およびそれらのグループに安全な型を提供すること) です。すべての鍵仕様で、このインタフェースを実装する必要があります。

    Java は、KeySpec インタフェースであるDSAPrivateKeySpecDSAPublicKeySpecRSAPrivateKeySpecRSAPublicKeySpecEncodedKeySpecPKCS8EncodedKeySpec、および X509EncodedKeySpec を実装するいくつかのクラスを提供します。

    JDK が対応する KeySpec クラスを提供していない鍵タイプ (Your_PublicKey_type および Your_PrivateKey_type など) をプロバイダが使用する場合、2 とおりの対処方法が考えられます。1 つは、独自の鍵仕様を実装する方法です。

    1. ユーザーが特定の鍵データ値にアクセスする必要が一切ない場合、その鍵タイプ用の KeySpec クラスを提供する必要はありません。

      この方法では、ユーザーは常に、プロバイダが提供する該当する鍵タイプ用の適切な KeyPairGenerator を使用して Your_PublicKey_type および Your_PrivateKey_type 鍵を作成します。あとで使用する目的で生成された鍵を格納する場合には、(Key インタフェースの getEncoded メソッドを使用して) 鍵の符号化を取得します。符号化から Your_PublicKey_type または Your_PrivateKey_type 鍵を作成する場合 (署名または検証目的で Signature オブジェクトを初期化する場合など) は、符号化から X509EncodedKeySpec または PKCS8EncodedKeySpec のインスタンスを作成して、プロバイダが提供する適切な KeyFactory に渡します。KeyFactory の generatePublic および generatePrivate メソッドは、要求された PublicKey (Your_PublicKey_type のインスタンス) または PrivateKey (Your_PrivateKey_type のインスタンス) オブジェクトをそれぞれ返します。
    2. ユーザーが鍵タイプの特定の鍵データ値にアクセスするか、上記の場合のようにエンコーディングからではなく鍵データおよび関連するパラメータ値から鍵タイプの鍵を構築する必要が予想される場合、適切なコンストラクタメソッドおよび get メソッドを使用して、新しい KeySpec クラス (KeySpec インタフェースを実装するクラス) を指定して、鍵タイプ用の鍵データフィールドおよび関連するパラメータ値を返すようにする必要があります。これらのクラスは、JDK 6 で提供される DSAPrivateKeySpec および DSAPublicKeySpec クラスが行うのと同様の方法で指定します。これらのクラスは、プロバイダクラスとともに (たとえば、プロバイダ JAR ファイルの一部として) 提供する必要があります。

    DSAPrivateKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、関連付けられたパラメータを使って DSA 非公開鍵を指定します。このクラスには、次のメソッドがあります。

    DSAPrivateKeySpec のメソッド 説明
    public BigInteger getX() 非公開鍵 x を返します。
    public BigInteger getP() プライム p を返します。
    public BigInteger getQ() サブプライム q を返します。
    public BigInteger getG() ベース g を返します。

    これらのメソッドは、非公開鍵 x、および鍵の計算に使用される DSA アルゴリズムパラメータであるプライムの p、サブプライムの q、およびベースの g を返します。

    DSAPublicKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、関連付けられたパラメータを使って DSA 公開鍵を指定します。このクラスには、次のメソッドがあります。

    DSAPublicKeySpec のメソッド 説明
    public BigInteger getY() 公開鍵 y を返します。
    public BigInteger getP() プライム p を返します。
    public BigInteger getQ() サブプライム q を返します。
    public BigInteger getG() ベース g を返します。

    これらのメソッドは、公開鍵 y、および鍵の計算に使用される DSA アルゴリズムパラメータであるプライムの p、サブプライムの q、およびベースの g を返します。

    RSAPrivateKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、RSA 非公開鍵を指定します。このクラスには、次のメソッドがあります。

    RSAPrivateKeySpec のメソッド 説明
    public BigInteger getModulus() モジュラスを返します。
    public BigInteger getPrivateExponent() 非公開指数を返します。

    これらのメソッドは、RSA 非公開鍵を構成する RSA モジュラス n および非公開指数 d の値を返します。

    RSAPrivateCrtKeySpec クラス

    このクラス (RSAPrivateKeySpec クラスを継承) は、PKCS#1 標準で定義されているように、中国剰余定理 (CRT) 情報の値を使って、RSA 非公開鍵を指定します。このクラスには、スーパークラスの RSAPrivateKeySpec から継承したメソッドのほかに、次のメソッドがあります。

    RSAPrivateCrtKeySpec のメソッド 説明
    public BigInteger getPublicExponent() 公開指数を返します。
    public BigInteger getPrimeP() プライム P を返します。
    public BigInteger getPrimeQ() プライム Q を返します。
    public BigInteger getPrimeExponentP() primeExponentP を返します。
    public BigInteger getPrimeExponentQ() primeExponentQ を返します。
    public BigInteger getCrtCoefficient() crtCoefficient を返します。

    これらのメソッドは、公開指数 e および CRT 情報の整数を返します。CRT 情報の整数は、モジュラス n の素因数 pn の素因数 q、指数 d mod (p-1)、指数 d mod (q-1)、および中国剰余定理係数 (q の逆数) mod p です。

    RSA 非公開鍵は、論理的にはモジュラスと非公開の指数だけで構成されます。CRT 値は、効率を向上させる目的で存在します。

    RSAPublicKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、RSA 公開鍵を指定します。このクラスには、次のメソッドがあります。

    RSAPublicKeySpec のメソッド 説明
    public BigInteger getModulus() モジュラスを返します。
    public BigInteger getPublicExponent() 公開指数を返します。

    これらのメソッドは、RSA 公開鍵を構成する RSA モジュラス n および公開指数 e の値を返します。

    EncodedKeySpec クラス

    この abstract クラス (KeySpec インタフェースを実装する) は、符号化された形式の公開鍵または非公開鍵を表します。

    EncodedKeySpec のメソッド 説明
    public abstract byte[] getEncoded() 符号化された鍵を返します。
    public abstract String getFormat() 符号化形式の名前を返します。

    JDK 6 は、EncodedKeySpec インタフェースである PKCS8EncodedKeySpec および X509EncodedKeySpec を実装する 2 つのクラスを提供します。必要に応じて、これらの、または他の鍵エンコーディング用に独自の EncodedKeySpec 実装を提供することもできます。

    PKCS8EncodedKeySpec クラス

    このクラスは、EncodedKeySpec のサブクラスで、PKCS #8 標準で指定された形式に従って、非公開鍵の DER 符号化を表現します。

    このクラスの getEncoded メソッドは、PKCS #8 標準に従って符号化された鍵のバイトを返します。このクラスの getFormat メソッドは、文字列 PKCS#8 を返します。

    X509EncodedKeySpec クラス

    このクラスは、EncodedKeySpec のサブクラスで、X.509 標準で指定された形式に従って、公開鍵または非公開鍵の DER 符号化を表現します。

    このクラスの getEncoded メソッドは、X.509 標準に従って符号化された鍵のバイトを返します。このクラスの getFormat メソッドは、文字列 X.509 を返します。 DHPrivateKeySpecDHPublicKeySpecDESKeySpecDESedeKeySpecPBEKeySpecSecretKeySpec を定義します。

    DHPrivateKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、関連付けられたパラメータを使って Diffie-Hellman 非公開鍵を指定します。

    DHPrivateKeySpec のメソッド 説明
    BigInteger getG() ベースジェネレータ g を返します。
    BigInteger getP() prime モジュール p を返します。
    BigInteger getX() 非公開の値 x を返します。

    DHPublicKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、関連付けられたパラメータを使って Diffie-Hellman 公開鍵を指定します。

    DHPublicKeySpec のメソッド 説明
    BigInteger getG() ベースジェネレータ g を返します。
    BigInteger getP() prime モジュール p を返します。
    BigInteger getY() 公開の値 y を返します。

    DESKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、DES 鍵を指定します。

    DESKeySpec のメソッド 説明
    byte[] getKey() DES 鍵のバイト数を返します。
    static boolean isParityAdjusted(byte[] key, int offset) 所定の DES 鍵データがパリティー対応であるかどうかをチェックします。
    static boolean isWeak(byte[] key, int offset) 所定の DES 鍵データが脆弱 (weak) または準脆弱 (semi-weak) のどちらであるかをチェックします。

    DESedeKeySpec クラス

    このクラス (KeySpec インタフェースを実装) は、DES-EDE (トリプル DES) 鍵を指定します。

    DESedeKeySpec のメソッド 説明
    byte[] getKey() DES-EDE 鍵を返します。
    static boolean isParityAdjusted(byte[] key, int offset) 所定の DES-EDE 鍵がパリティー対応であるかどうかをチェックします。

    PBEKeySpec クラス

    このクラスは、KeySpec インタフェースを実装します。パスワードベースの暗号化 (PBE) で使用するパスワードは、ユーザーが選択できます。このパスワードは、生の鍵データの型として参照されます。このクラスを使用する暗号化機構は、生の鍵データから暗号鍵を引き出すことができます。

    PBEKeySpec のメソッド 説明
    void clearPassword パスワードの内部コピーを消去します。
    int getIterationCount 繰り返し処理の回数を返します。指定がない場合は 0 を返します。
    int getKeyLength 引き出される鍵の長さを返します。指定がない場合は 0 を返します。
    char[] getPassword パスワードのコピーを返します。
    byte[] getSalt salt のコピーを返します。指定がない場合は null を返します。

    SecretKeySpec クラス

    このクラスは、KeySpec インタフェースを実装します。このクラスは SecretKey インタフェースも実装するため、このクラスを使用するなら、SecretKey オブジェクトをプロバイダに依存しない方法で (プロバイダベースの SecretKeyFactory を使用せずに) 構築できます。

    SecretKeySpec のメソッド 説明
    boolean equals (Object obj) このオブジェクトと「等価」になるオブジェクトがあるかどうかを示します。
    String getAlgorithm() この秘密鍵に関連付けられているアルゴリズム名を返します。
    byte[] getEncoded() この秘密鍵の鍵データを返します。
    String getFormat() この秘密鍵の符号化方式の名前を返します。
    int hashCode() オブジェクトのハッシュコード値を計算します。

    非公開鍵の生成

    特定の非公開鍵アルゴリズムに対して非公開鍵ジェネレータ (javax.crypto.KeyGeneratorSpi のサブクラス) を提供する場合、生成された非公開鍵オブジェクト (javax.crypto.SecretKey のインスタンスであることが必要。engineGenerateKey を参照) を次のいずれかの方法で返すことができます。

    • 鍵ジェネレータと関連付けられたアルゴリズムの非公開鍵を表すインスタンスを保持するクラスを実装します。鍵ジェネレータ実装により、そのクラスのインスタンスが返されます。鍵ジェネレータにより生成された鍵がプロバイダ固有のプロパティーを保持する場合、この方法は有用です。
    • 鍵ジェネレータは、javax.crypto.SecretKey インタフェースをすでに実装している SecretKeySpec のインスタンスを返します。未加工の鍵のバイトおよび鍵ジェネレータに関連付けられた非公開鍵アルゴリズムの名前を、SecretKeySpec コンストラクタに渡します。基盤となる未加工の鍵のバイトをバイト配列で表すことができ、関連付けられた鍵パラメータが存在しない場合、この方法は有用です。

    新規オブジェクト識別子の追加

    次の情報は、「Java 暗号化アーキテクチャーリファレンスガイド」の「付録 A」で標準アルゴリズムとして挙げられていないアルゴリズムを提供するプロバイダに当てはまります。

    OID から名前へのマッピング

    JCA が、暗号化アルゴリズム実装について、アルゴリズム識別子から (たとえば、証明書内で符号化されたものとして) インスタンスの生成を行う必要がある場合があります。アルゴリズム識別子には、定義上、アルゴリズムのオブジェクト識別子 (OID) が含まれます。たとえば、X.509 証明書の署名を検証するために、JCA は証明書内で符号化された署名アルゴリズム識別子から署名アルゴリズムを判別し、そのアルゴリズムの Signature オブジェクトについてインスタンスを生成してから、検証のために初期化します。

    JCA でアルゴリズムを検索するには、プロバイダマスターファイルで、アルゴリズムの別名エントリとしてアルゴリズム識別子を指定します。

        put("Alg.Alias.<engine_type>.1.2.3.4.5.6.7.8",
    	"<algorithm_alias_name>");
    

    アルゴリズムが複数のオブジェクト識別子で知られている場合、オブジェクト識別子ごとに別名エントリを作成する必要があります。

    JCA によるこの種のマッピングの例として、アルゴリズム (Foo) が署名アルゴリズムで、ユーザーが keytool コマンドを実行して (署名) アルゴリズムの別名を指定する場合を考えます。

        % keytool -genkeypair -sigalg 1.2.3.4.5.6.7.8
    

    この場合、プロバイダのマスターファイルには、次のエントリを含める必要があります。

        put("Signature.Foo", "com.xyz.MyFooSignatureImpl");
        put("Alg.Alias.Signature.1.2.3.4.5.6.7.8", "Foo");
    

    この種のマッピングの別の例として、(1) アルゴリズムがキータイプアルゴリズムで、プログラムが (SUN プロバイダの X.509 実装を使って) 証明書を構文解析し、証明書から公開鍵を抽出して、Signature オブジェクトを初期化する場合、および (2) keytool ユーザーが、対応する鍵のペアの生成後に (デジタル署名を実行するために) キータイプの非公開鍵にアクセスしようとする場合、を挙げることができます。これらの場合、プロバイダのマスターファイルには、次のエントリを含める必要があります。

        put("KeyFactory.Foo", "com.xyz.MyFooKeyFactoryImpl");
        put("Alg.Alias.KeyFactory.1.2.3.4.5.6.7.8", "Foo");
    

    名前から OID へのマッピング

    JCA が逆マッピング (つまり、アルゴリズム名からその関連付けられた OID への) を実行する必要がある場合、アルゴリズムと関連付けられた OID の 1 つに対して、次の形式の別名エントリを提供する必要があります。

        put("Alg.Alias.Signature.OID.1.2.3.4.5.6.7.8", "MySigAlg");
    

    アルゴリズムが複数のオブジェクト識別子で知られている場合、優先度の高いものに接頭辞「OID」を追加します。

    JCA がこの種のマッピングを実行する一例として、ユーザーが keytool を、-sigalg オプションを取る任意のモードで実行する場合を挙げることができます。たとえば、-genkeypair および -certreq コマンドが呼び出されると、ユーザーは -sigalg オプションを使用して (署名) アルゴリズムを指定できます。

    エクスポート機能の保証

    JCA では、特定の条件が満たされる場合に、JCA フレームワークおよびプロバイダ暗号化実装をエクスポート可能になります。これは JCA の重要な機能です。

    輸入管理制限があるため、Java 2 SDK, v 6 に同梱された管轄ポリシーファイルは「強固」ですが、暗号化の使用には制限があります。適格国 (大半の国が該当) の在住者は、暗号化機能に制限のない「無制限」のバージョンを利用できます。ただし、政府が制限を課しているこれらの国が輸入できるのは「強力な」バージョンだけです。JCA フレームワークでは、インストール済みの管轄ポリシーファイルで指定された制限が施行されます。

    他の部分で説明したように、最も強力な暗号化を実装する、1 つのバージョンのプロバイダソフトウェアだけを実装できます。位置の異なるアプレット/アプリケーションから、利用可能な暗号化アルゴリズムおよび暗号化の最大強度に関して管轄ポリシーファイルに規定された制限を施行するのは、プロバイダではなく、JCA です。

    JCA へのプラグインを可能にするために、プロバイダが満たす必要がある条件を次に示します。

    • 「プロバイダによる自己整合性チェックの実行方法」で説明したように、各 SPI 実装クラスのコンストラクタが、自己整合性チェックを実行する必要があります。

    • プロバイダコードを、JCA をバイパスして、アプリケーションから直接インスタンス化する場合には、プロバイダクラスが無効になるようにプロバイダコードを記述する必要があります。「プロバイダの実装および統合までのステップ」セクションの「ステップ 1: サービス実装コードの記述」を参照

    • プロバイダパッケージは、JCA フレームワークにより信頼されたエンティティーを使用して署名する必要があります(ステップ 6.1 からステップ 6.2 を参照)。プロバイダを米国外に輸出する可能性のある米国内のベンダーは、輸出承認を米国政府に申請する必要があります(ステップ 10 を参照)。

    付録 A: SUN プロバイダのマスタークラス

    次に示すのは、編集済みの Sun.java ファイルです。このファイルには、Sun という名前のプロバイダ用のマスタークラスである Sun というクラスが含まれます。

    すべてのマスタークラスの場合と同様、このクラスは Provider のサブクラスです。これは、SUN プロバイダが提供するすべてのサービス実装のクラス名およびパッケージ位置を指定します。さまざまなアルゴリズムおよび他のサービスが要求された場合、エンジンクラスの getInstance メソッドはこの情報を使用して検索を行います。

    次に示すコードは、プロバイダマスタークラスの例です。

    /*
     * @(#)Sun.java	1.28 99/05/27
     *
     * Copyright 1996-1998 by Sun Microsystems, Inc.,
     * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
     * All rights reserved.
     *
     * This software is the confidential and proprietary information
     * of Sun Microsystems, Inc. ("Confidential Information").  You
     * shall not disclose such Confidential Information and shall use
     * it only in accordance with the terms of the license agreement
     * you entered into with Sun.
     */
    
    package sun.security.provider;
    
    import java.io.*;
    import java.util.*;
    import java.security.*;
    
    /**
     * The SUN Security Provider.
     *
     * @author Benjamin Renaud
     *
     * @version 1.28, 05/27/99
     */
    
    /**
     * Defines the SUN provider.
     *
     * Algorithms supported, and their names:
     *
     * - SHA is the message digest scheme described in FIPS 180-1.
     *   Aliases for SHA are SHA-1 and SHA1.
     *
     * - SHA1withDSA is the signature scheme described in FIPS 186.
     *   (SHA used in DSA is SHA-1: FIPS 186 with Change No 1.)
     *   Aliases for SHA1withDSA are DSA, DSS, SHA/DSA, SHA-1/DSA, SHA1/DSA,
     *   SHAwithDSA, DSAWithSHA1, and the object
     *   identifier strings "OID.1.3.14.3.2.13", "OID.1.3.14.3.2.27" and
     *   "OID.1.2.840.10040.4.3".
     *
     * - DSA is the key generation scheme as described in FIPS 186.
     *   Aliases for DSA include the OID strings "OID.1.3.14.3.2.12"
     *   and "OID.1.2.840.10040.4.1".
     *
     * - MD5 is the message digest scheme described in RFC 1321.
     *   There are no aliases for MD5.
     */
    
    public final class Sun extends Provider {
    
        private static final String INFO = "SUN " +
        "(DSA key/parameter generation; DSA signing; " +
        "SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore)";
    
        public Sun() {
    	/* We are the SUN provider */
    	super("SUN", 1.2, INFO);
    
    	AccessController.doPrivileged(new java.security.PrivilegedAction() {
    	    public Object run() {
    
    		/*
    		 * Signature engines
    		 */
    		put("Signature.SHA1withDSA", "sun.security.provider.DSA");
    
    		put("Alg.Alias.Signature.DSA", "SHA1withDSA");
    		put("Alg.Alias.Signature.DSS", "SHA1withDSA");
    		put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
    		put("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA");
    		put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA");
    		put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA");
    		put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
    		put("Alg.Alias.Signature.OID.1.2.840.10040.4.3",
    		    "SHA1withDSA");
    		put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
    		put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA");
    		put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA");
    
    		/*
    		 *  Key Pair Generator engines
    		 */
    		put("KeyPairGenerator.DSA",
    		    "sun.security.provider.DSAKeyPairGenerator");
    		put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA");
    		put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA");
    		put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA");
    
    		/*
    		 * Digest engines
    		 */
    		put("MessageDigest.MD5", "sun.security.provider.MD5");
    		put("MessageDigest.SHA", "sun.security.provider.SHA");
    
    		put("Alg.Alias.MessageDigest.SHA-1", "SHA");
    		put("Alg.Alias.MessageDigest.SHA1", "SHA");
    
    		/*
    		 * Algorithm Parameter Generator engines
    		 */
    		put("AlgorithmParameterGenerator.DSA",
    		    "sun.security.provider.DSAParameterGenerator");
    
    		/*
    		 * Algorithm Parameter engines
    		 */
    		put("AlgorithmParameters.DSA",
    		    "sun.security.provider.DSAParameters");
    		put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA");
    		put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA");
    
    		/*
    		 * Key factories
    		 */
    		put("KeyFactory.DSA", "sun.security.provider.DSAKeyFactory");
    		put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA");
    		put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
    
    		/*
    		 * SecureRandom
    		 */
    		 put("SecureRandom.SHA1PRNG",
    		     "sun.security.provider.SecureRandom");
    
    		/*
    		 * Certificates
    		 */
    		put("CertificateFactory.X509",
    		    "sun.security.provider.X509Factory");
    		put("Alg.Alias.CertificateFactory.X.509", "X509");
    
    		/*
    		 * KeyStore
    		 */
    		put("KeyStore.JKS", "sun.security.provider.JavaKeyStore");
    
    		/*
    		 * KeySize
    		 */
    		put("Signature.SHA1withDSA KeySize", "1024");
    		put("KeyPairGenerator.DSA KeySize", "1024");
    		put("AlgorithmParameterGenerator.DSA KeySize", "1024");
    
    		/*
    		 * Implementation type: software or hardware
    		 */
    		put("Signature.SHA1withDSA ImplementedIn", "Software");
    		put("KeyPairGenerator.DSA ImplementedIn", "Software");
    		put("MessageDigest.MD5 ImplementedIn", "Software");
    		put("MessageDigest.SHA ImplementedIn", "Software");
    		put("AlgorithmParameterGenerator.DSA ImplementedIn",
    		    "Software");
    		put("AlgorithmParameters.DSA ImplementedIn", "Software");
    		put("KeyFactory.DSA ImplementedIn", "Software");
    		put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
    		put("CertificateFactory.X509 ImplementedIn", "Software");
    		put("KeyStore.JKS ImplementedIn", "Software");
    
    		return null;
    	    }
    	});
        }
    }
    

    付録 B: SunJCE プロバイダのマスタークラス

    次に示すのは、編集済みの SunJCE.java ファイルです。このファイルには、SunJCE という名前のプロバイダ用のマスタークラスである SunJCE というクラスが含まれます。

    すべてのマスタークラスの場合と同様、このクラスは Provider のサブクラスです。これは、SunJCE プロバイダが提供するすべての暗号化サービス実装のクラス名およびパッケージ位置を指定します。さまざまなアルゴリズムおよび他のサービスが要求された場合、エンジンクラスの getInstance メソッドはこの情報を使用して検索を行います。

    次に示すコードは、プロバイダマスタークラスの例です。

    /*
     * @(#)SunJCE.java	1.73 05/12/13
     *
     * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
     * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    
    package com.sun.crypto.provider;
    
    import java.security.*;
    import java.security.cert.*;
    import java.net.URL;
    import java.io.ByteArrayInputStream;
    
    /**
     * The "SunJCE" Cryptographic Service Provider.
     *
     * @author Jan Luehe
     * @author Sharon Liu
     *
     * @version 1.73, 12/13/05
     */
    
    /**
     * Defines the "SunJCE" provider.
     *
     * Supported algorithms and their names:
     *
     * ...edited for space...
     *
     */
    
    public final class SunJCE extends Provider {
    
        private static final String info = "SunJCE Provider " +
        "(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, "
        + "Diffie-Hellman, HMAC)";
    
        private static final String OID_PKCS5_MD5_DES = "1.2.840.113549.1.5.3";
        private static final String OID_PKCS3 = "1.2.840.113549.1.3.1";
    
        public SunJCE() {
    	/* We are the "SunJCE" provider */
    	super("SunJCE", 1.6d, info);
    
    	final String BLOCK_MODES = "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" +
    	    "|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" +
    	    "|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64";
    	final String BLOCK_MODES128 = BLOCK_MODES +
    	    "|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" +
    	    "|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128";
    	final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING";
    
    	AccessController.doPrivileged(new java.security.PrivilegedAction() {
    		public Object run() {
    
    		/*
    		 * Cipher engines
    		 */
    		put("Cipher.RSA", "com.sun.crypto.provider.RSACipher");
    		put("Cipher.RSA SupportedModes", "ECB");
    		put("Cipher.RSA SupportedPaddings",
    			"NOPADDING|PKCS1PADDING|OAEPWITHMD5ANDMGF1PADDING"
    			+ "|OAEPWITHSHA1ANDMGF1PADDING"
    			+ "|OAEPWITHSHA-1ANDMGF1PADDING"
    			+ "|OAEPWITHSHA-256ANDMGF1PADDING"
    			+ "|OAEPWITHSHA-384ANDMGF1PADDING"
    			+ "|OAEPWITHSHA-512ANDMGF1PADDING");
    		put("Cipher.RSA SupportedKeyClasses",
    			"java.security.interfaces.RSAPublicKey" +
    			"|java.security.interfaces.RSAPrivateKey");
    
    		put("Cipher.PBEWithMD5AndDES",
    		    "com.sun.crypto.provider.PBEWithMD5AndDESCipher");
    		put("Alg.Alias.Cipher.OID."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    		put("Alg.Alias.Cipher."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    
    		put("Cipher.AES", "com.sun.crypto.provider.AESCipher");
    		put("Alg.Alias.Cipher.Rijndael", "AES");
    		put("Cipher.AES SupportedModes", BLOCK_MODES128);
    		put("Cipher.AES SupportedPaddings", BLOCK_PADS);
    		put("Cipher.AES SupportedKeyFormats", "RAW");
    
    		put("Cipher.AESWrap", "com.sun.crypto.provider.AESWrapCipher");
    		put("Cipher.AESWrap SupportedModes", "ECB");
    		put("Cipher.AESWrap SupportedPaddings", "NOPADDING");
    		put("Cipher.AESWrap SupportedKeyFormats", "RAW");
    
    		put("Cipher.ARCFOUR",
    		    "com.sun.crypto.provider.ARCFOURCipher");
    		put("Alg.Alias.Cipher.RC4", "ARCFOUR");
    		put("Cipher.ARCFOUR SupportedModes", "ECB");
    		put("Cipher.ARCFOUR SupportedPaddings", "NOPADDING");
    		put("Cipher.ARCFOUR SupportedKeyFormats", "RAW");
    
    		/*
    		 *  Key(pair) Generator engines
    		 */
    		put("KeyGenerator.AES",
    		    "com.sun.crypto.provider.AESKeyGenerator");
    		put("Alg.Alias.KeyGenerator.Rijndael", "AES");
    
    		put("KeyGenerator.ARCFOUR",
    		    "com.sun.crypto.provider.KeyGeneratorCore$" +
    		    "ARCFOURKeyGenerator");
    		put("Alg.Alias.KeyGenerator.RC4", "ARCFOUR");
    
    		put("KeyGenerator.HmacMD5",
    		    "com.sun.crypto.provider.HmacMD5KeyGenerator");
    
    		put("KeyGenerator.HmacSHA256",
    		    "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA256KG");
    
    		put("KeyPairGenerator.DiffieHellman",
    		    "com.sun.crypto.provider.DHKeyPairGenerator");
    		put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman");
    		put("Alg.Alias.KeyPairGenerator.OID."+OID_PKCS3,
    		    "DiffieHellman");
    		put("Alg.Alias.KeyPairGenerator."+OID_PKCS3,
    		    "DiffieHellman");
    
    		/*
    		 * Algorithm parameter generation engines
    		 */
    		put("AlgorithmParameterGenerator.DiffieHellman",
    		    "com.sun.crypto.provider.DHParameterGenerator");
    		put("Alg.Alias.AlgorithmParameterGenerator.DH",
    		    "DiffieHellman");
    		put("Alg.Alias.AlgorithmParameterGenerator.OID."+OID_PKCS3,
    		    "DiffieHellman");
    		put("Alg.Alias.AlgorithmParameterGenerator."+OID_PKCS3,
    		    "DiffieHellman");
    
    		/*
    		 * Key Agreement engines
    		 */
    		put("KeyAgreement.DiffieHellman",
    		    "com.sun.crypto.provider.DHKeyAgreement");
    		put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");
    		put("Alg.Alias.KeyAgreement.OID."+OID_PKCS3, "DiffieHellman");
    		put("Alg.Alias.KeyAgreement."+OID_PKCS3, "DiffieHellman");
    
    		put("KeyAgreement.DiffieHellman SupportedKeyClasses",
    		    "javax.crypto.interfaces.DHPublicKey" +
    		    "|javax.crypto.interfaces.DHPrivateKey");
    
    		/*
    		 * Algorithm Parameter engines
    		 */
    		put("AlgorithmParameters.DiffieHellman",
    		    "com.sun.crypto.provider.DHParameters");
    		put("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman");
    		put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS3,
    		    "DiffieHellman");
    		put("Alg.Alias.AlgorithmParameters."+OID_PKCS3,
    		    "DiffieHellman");
    
    		put("AlgorithmParameters.PBEWithMD5AndDES",
    		    "com.sun.crypto.provider.PBEParameters");
    		put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    		put("Alg.Alias.AlgorithmParameters."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    
    		put("AlgorithmParameters.OAEP",
    		    "com.sun.crypto.provider.OAEPParameters");
    
    		/*
    		 * Key factories
    		 */
    		put("KeyFactory.DiffieHellman",
    		    "com.sun.crypto.provider.DHKeyFactory");
    		put("Alg.Alias.KeyFactory.DH", "DiffieHellman");
    		put("Alg.Alias.KeyFactory.OID."+OID_PKCS3,
    		    "DiffieHellman");
    		put("Alg.Alias.KeyFactory."+OID_PKCS3, "DiffieHellman");
    
    		/*
    		 * Secret-key factories
    		 */
    		put("SecretKeyFactory.PBEWithMD5AndDES",
    		    "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES"
    		    );
    		put("Alg.Alias.SecretKeyFactory.OID."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    		put("Alg.Alias.SecretKeyFactory."+OID_PKCS5_MD5_DES,
    		    "PBEWithMD5AndDES");
    
    		/*
    		 * MAC
    		 */
    		put("Mac.HmacMD5", "com.sun.crypto.provider.HmacMD5");
    		put("Mac.HmacSHA256",
    		    "com.sun.crypto.provider.HmacCore$HmacSHA256");
    
    		put("Mac.HmacMD5 SupportedKeyFormats", "RAW");
    		put("Mac.HmacSHA256 SupportedKeyFormats", "RAW");
    
    		/*
    		 * KeyStore
    		 */
    		put("KeyStore.JCEKS", "com.sun.crypto.provider.JceKeyStore");
    
    		return null;
    	    }
    	});
        }
    }
     

    付録 C: java.security.properties ファイル

    次に示すのは、インストールされているプロバイダのデフォルトのリストを示す java.security ファイルの一部です。これは、すべての JRE インストールで表示されます。ファイルにはその他のエントリも含まれていますが、簡潔にするために、ここでは一部のみを示します。完全なファイルは次の場所にあります。

    <java-home>/lib/security/java.security	 [Solaris]
    <java-home>\lib\security\java.security	 [Win32]
    

    ここで、<java-home> は JRE がインストールされているディレクトリを指します。

    このファイルにプロバイダに関する情報を追加する例については、ステップ 5 を参照してください。

    #
    # This is the "master security properties file".
    #
    # In this file, various security properties are set for use by
    # java.security classes. This is where users can statically register
    # Cryptography Package Providers ("providers" for short). The term
    # "provider" refers to a package or set of packages that supply a
    # concrete implementation of a subset of the cryptography aspects of
    # the Java Security API. A provider may, for example, implement one or
    # more digital signature algorithms or message digest algorithms.
    #
    # Each provider must implement a subclass of the Provider class.
    # To register a provider in this master security properties file,
    # specify the Provider subclass name and priority in the format
    #
    #    security.provider.=
    #
    # This declares a provider, and specifies its preference
    # order n. The preference order is the order in which providers are
    # searched for requested algorithms (when no specific provider is
    # requested). The order is 1-based; 1 is the most preferred, followed
    # by 2, and so on.
    #
    # <className> must specify the subclass of the Provider class whose
    # constructor sets the values of various properties that are required
    # for the Java Security API to look up the algorithms or other
    # facilities implemented by the provider.
    #
    # There must be at least one provider specification in java.security.
    # There is a default provider that comes standard with the JDK. It
    # is called the "SUN" provider, and its Provider subclass
    # named Sun appears in the sun.security.provider package. Thus, the
    # "SUN" provider is registered via the following:
    #
    #    security.provider.1=sun.security.provider.Sun
    #
    # (The number 1 is used for the default provider.)
    #
    # Note: Providers can be dynamically registered instead by calls to
    # either the addProvider or insertProviderAt method in the Security
    # class.
    
    #
    # List of providers and their preference orders (see above):
    #
    
    security.provider.1=sun.security.pkcs11.SunPKCS11 \
        ${java.home}/lib/security/sunpkcs11-solaris.cfg
    security.provider.2=sun.security.provider.Sun
    security.provider.3=sun.security.rsa.SunRsaSign
    security.provider.4=com.sun.net.ssl.internal.ssl.Provider
    security.provider.5=com.sun.crypto.provider.SunJCE
    security.provider.6=sun.security.jgss.SunProvider
    security.provider.7=com.sun.security.sasl.Provider
    security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
    security.provider.9=sun.security.smartcardio.SunPCSC
    
    # Rest of file deleted