mCertForm.txt Java 暗号化拡張機能用プロバイダの実装方法

JavaTM 暗号化拡張機能用プロバイダの実装方法

JavaTM 2 SDK, Standard Edition, v 1.4



はじめに
このドキュメントの対象読者
関連ドキュメント
用語に関する注記

Java 2 SDK, v 1.4 における JCE の新機能

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

プロバイダの実装および統合までのステップ
ステップ 1:サービス実装コードの記述
ステップ 2:プロバイダの命名
ステップ 3:プロバイダのサブクラスである「マスタークラス」の記述
ステップ 4:コードのコンパイル
ステップ 5:テストの準備
ステップ 6:テストプログラムの記述とコンパイル
ステップ 7:テストプログラムの実行
ステップ 8:米国政府による輸出承認の申請 (必要な場合)
ステップ 9:プロバイダおよびそのサポート対象サービスのドキュメント化
ステップ 10:プロバイダソフトウェアおよびドキュメントをクライアントから利用可能にする

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

実装の詳細および要件
アルゴリズムの別名
サービスの相互依存性
デフォルトの初期化
Diffie-Hellman インタフェースおよびその実装要件
アルゴリズムパラメータ仕様クラス
鍵ファクトリにより要求される鍵仕様クラス
非公開鍵の生成
エクスポート機能の保証

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

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

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

はじめに

JavaTM 暗号化拡張機能 (JCE) は、暗号化、鍵生成と鍵協定、およびメッセージ認証コード (MAC) アルゴリズム用のフレームワークおよび実装を提供します。暗号化サポートには、対称、非対称、ブロック、およびストリーム暗号が含まれます。このソフトウェアは、セキュリティ保護されたストリームおよびシールされたオブジェクトもサポートします。

JavaTM 2 SDK, Standard Edition (Java 2 SDK) バージョン 1.2.x および 1.3.x では、JCE はオプションパッケージ (拡張機能) でした。Java 2 SDK, v 1.4 には JCE が統合されています。

JCE の設計方針は、実装非依存および可能な場合には常にアルゴリズム非依存です。これは、Java 2 プラットフォームの暗号化関連セキュリティコンポーネントすべてで利用されている Java 暗号化アーキテクチャフレームワーク内の設計方針と同じです。 これは、暗号化サービスプロバイダ (略して「プロバイダ」) という概念を使用する、同一の「プロバイダ」アーキテクチャを使用します。これは、Java Security API の暗号化に関するサブセットの固定実装を提供するパッケージ (またはパッケージセット) です。

JCE は、プロバイダが実装を提供可能な暗号化サービスのリストを拡張します。このため、たとえば、1 つ以上のデジタル署名アルゴリズムの実装、および 1 つ以上の暗号化アルゴリズムをプロバイダに含めることができます。

暗号化機能を使用しようとするプログラムは、単に特定のアルゴリズム (DES など) を実装する特定型のオブジェクト (Cipher オブジェクトなど) を要求するだけで、インストールされているプロバイダの 1 つから実装を取得できます。特定のプロバイダからの実装が望ましい場合、プログラムはそのプロバイダを名前で要求し、同時に目的のアルゴリズムを要求することができます。

Java 2 SDK では 1 つ以上のプロバイダパッケージがインストールされます。 各プロバイダパッケージは、Java 2 SDK の 1 つ以上のセキュリティコンポーネント (JCE を含む) で定義された暗号化サービスの実装を提供します。

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

Java 2 SDK, v 1.4 リリースでは、「SunJCE」という名前の標準 JCE プロバイダがあらかじめインストールおよび登録されています。SunJCE は、次の暗号化サービスを提供します。

新たなプロバイダは、静的にも動的にも追加できます。クライアントは、現在どのプロバイダがインストールされているかを問い合わせることができます。

実装が違うと、特徴も違ってくる場合があります。ソフトウェアベースのものもあれば、ハードウェアベースのものもあります。プラットフォーム独立のものもあれば、プラットフォーム固有のものもあります。また、レビューや評価用に使えるプロバイダコードもあれば、使えないものもあります。

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

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

このドキュメントは、暗号化サービスプロバイダの開発者を対象としています。ここでは、Java Security API クライアントが、作成されたアルゴリズムや他のサービスを要求する際にそれらを検出できるよう、プロバイダを Java Security に統合するための方法がドキュメント化されています。

JCE フレームワークにプラグインできるのは、信頼できるエンティティにより署名されたプロバイダだけです。

関連ドキュメント

このドキュメントでは、読者がすでに次のドキュメントを読んでいることを前提としています。

Java Security API のさまざまなクラスおよびインタフェースについての説明も含まれます。 これらのパッケージの完全なリファレンスドキュメントを以下に示します。

用語に関する注記

Java 2 SDK, v 1.4 の JCE には、次の 2 つのソフトウェアコンポーネントが含まれます。

このドキュメントでは、「JCE」という語は、Java 2 SDK, v 1.4 の JCE フレームワークを指して使われています。 Java 2 SDK, v 1.4 とともに提供される JCE プロバイダに言及する場合、常に「SunJCE」プロバイダのことを明示的に指しています。

Java 2 SDK, v 1.4 における JCE の新機能

プロバイダに影響を及ぼす、JCE 1.2.1 の JCE と Java 2 SDK, v 1.4 の JCE の相違点を次に示します。

Java 2 SDK に含まれる新しい JCE

JavaTM 2 SDK, Standard Edition (Java 2 SDK) バージョン 1.2.x および 1.3.x では、JCE はオプションパッケージ (拡張機能) でした。Java 2 SDK, v 1.4 には JCE が統合されています。 SunJCE プロバイダは、Java 2 SDK, v 1.4 に含まれる セキュリティプロパティファイル java.security にも含まれ、自動的に登録されます。

強力な暗号化機能をデフォルトで装備し、無制限に利用可能

輸入管理制限があるため、Java 2 SDK, v 1.4 に同梱された管轄ポリシーファイルは「強固」ですが、暗号化の使用には制限があります。適格国 (大半の国が該当) の在住者は、暗号化機能に制限のない「無制限」のバージョンを利用できます。無制限のバージョンをダウンロードし、Java 2 SDK, v1.4 に同梱されている強力な暗号化機能を持つバージョンに置き換えることも可能です。無制限のバージョンのダウンロード方法の詳細は、以下を参照してください。

http://java.sun.com/products/jce/index-14.html

管轄ポリシーファイルは、次の場所に移されました。

<java-home>¥lib¥security         [Win32]
<java-home>/lib/security         [Solaris]
ここで、<java-home> は、ランタイムソフトウェアのインストール先ディレクトリ (JavaTM 2 Runtime Environment のトップレベルディレクトリまたは JavaTM 2 SDK ソフトウェアの jre ディレクトリ) を指します。 Java 2 SDK, v 1.4 に含まれる強力な暗号化機能のバージョンを機能無制限のバージョンと簡単に置き換えることができるように、これらのファイルは標準的な位置に移動されました。

不要になった JCE フレームワークのプロバイダ認証

JCE 1.2.1 では、プラグインする JCE の完全性および信頼性を保証するため、JCE フレームワークの認証用コードをプロバイダに含める必要がありました。 JCE が Java 2 SDK, v 1.4 に統合されることにより、この操作は不要になりました。

「How to Implement a Provider for the Java Cryptography Extension 1.2.1」 のガイダンスに従う JCE 1.2.1 プロバイダは、Java 2 SDK, v 1.4 の JCE フレームワークでも引き続き使用できます。

しかし、JCE 1.2.1 の JCE プロバイダドキュメント (前述) の推奨条件に従わず、保護ドメインから JCE フレームワークを特定するようなフレームワーク認証コードを持つプロバイダは、Java 2 SDK, v 1.4 では使用できません。 JCE が Java 2 SDK, v 1.4 に統合されたため、JCE フレームワークは、Java 2 SDK, v 1.4 のその他のクラスと同様に null コードのソースを持つようになりました。 推奨条件に従ってフレームワークの認証を実施できるように、プロバイダを変更できます。また、条件式を挿入して、プロバイダを JCE 1.2.1 で使用する場合以外はフレームワーク認証コードが実行されないようにすることもできます。


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

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

暗号化サービスは、常に特定のアルゴリズムに関連付けられています。このサービスにより、暗号化操作 (暗号または鍵協定プロトコル用の操作) の提供、または暗号化操作に必要な暗号化データ (鍵またはパラメータ) の生成や提供が行われます。 たとえば、Cipher クラスおよび KeyAgreement クラスは、エンジンクラスです。 Cipherクラスは暗号化アルゴリズム機能 (DES など) へのアクセスを提供し、KeyAgreement クラスは鍵協定プロトコル機能 (Diffie-Hellman など) へのアクセスを提供します。

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

JavaTM 2 SDK, Standard Edition (Java 2 SDK) バージョン 1.2.x および 1.3.x では、JCE はオプションパッケージ (拡張機能) でした。Java 2 SDK, v 1.4 には JCE が統合されています。

JCE では、次のエンジンクラスが定義されています。

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

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

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

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

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

エンジンクラスのもう 1 つの例として、鍵協定 (鍵交換) アルゴリズムへのアクセスを提供する KeyAgreement クラスを紹介します。 KeyAgreementSpi サブクラス内では、Diffie-Hellman などのさまざまな鍵協定アルゴリズムを実装することが可能です。

最後に紹介するのは、SecretKeyFactory エンジンクラスです。このエンジンクラスは、不透明な非公開鍵から透明な鍵仕様への変換、またはその逆の変換をサポートします (「鍵ファクトリにより要求される鍵仕様のクラス」を参照)。 SecretKeyFactorySpi サブクラスで提供される現実の実装は、DES 鍵などの特定の非公開鍵用の実装です。


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

プロバイダの実装および JCE への統合までのステップは、次のとおりです。

ステップ 1:サービス実装コードの記述
ステップ 2:プロバイダの命名
ステップ 3:プロバイダのサブクラスである「マスタークラス」の記述
ステップ 4:コードのコンパイル
ステップ 5:テストの準備
ステップ 5a:コード署名証明書の取得
ステップ 5b:JAR ファイルへのプロバイダの記述
ステップ 5c:プロバイダの署名
ステップ 5d:プロバイダのインストール
ステップ 5e:プロバイダアクセス権の設定
ステップ 6:テストプログラムの記述とコンパイル
ステップ 7:テストプログラムの実行
ステップ 8:米国政府による輸出承認の申請 (必要な場合)
ステップ 9:プロバイダおよびそのサポート対象サービスのドキュメント化
ステップ 10:プロバイダソフトウェアおよびドキュメントをクライアントから利用可能にする

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

最初に行うべきことは、サポートする暗号化サービスのアルゴリズム固有の実装を提供するコードを記述することです。

プロバイダは、Java 2 SDK v 1.4 の 1 つ以上のセキュリティコンポーネント (JCE を含む) で定義された暗号化サービス実装を提供できます。

Java 2 SDK, v 1.4 の JCE では、以前の JCE 1.2.1 リリースと同様、非公開鍵ファクトリ、非公開鍵生成サービス、免責機構の実装だけでなく、暗号、鍵協定、MAC アルゴリズムを提供できます。

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

Java 2 SDK の暗号化サービスごとに (JCE で定義されている暗号化サービスを含む)、以下のような適切な SPI クラスのサブクラスを作成する必要があります。JCE では、エンジンクラス CipherSpiKeyAgreementSpiKeyGeneratorSpiMacSpiSecretKeyFactorySpiExemptionMechanismSpi が定義されています (「エンジンクラスと対応する SPI クラス」を参照)。

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

  1. 通常 engine で始まる名前を持つ抽象メソッド用の実装を提供します。詳細は、「実装の詳細および要件」を参照してください。

  2. 引数を持たない public コンストラクタの存在を確認します。 これが必要な理由は、サービスの要求時に、Java Security が、マスタークラス内のプロパティによる指定に従って、そのサービスを実装するサブクラスをルックアップするためです (ステップ 3 を参照)。 その後、Java Security は、サブクラスに関連付けられた Class オブジェクトを作成し、その Class オブジェクトに対して newInstance メソッドを呼び出すことにより、サブクラスのインスタンスを作成します。newInstance はサブクラスがパラメータを持たない public コンストラクタを保持することを要求します。

    サブクラスがコンストラクタを持たない場合、引数を持たないデフォルトのコンストラクタが自動的に生成されます。ただし、サブクラスがコンストラクタを定義する場合、引数を持たない public コンストラクタを明示的に定義する必要があります。

JCE プロバイダの追加要件および推奨事項

プロバイダによる JCE サービス実装 (クラス) をインスタンス化する際、JCE フレームワークはプロバイダのコードベース (JAR ファイル) を判定し、その署名を検証します。このようにして、JCE はプロバイダを認証して、信頼されたエンティティにより署名されたプロバイダだけが JCE にプラグインできるようにします。このため、JCE プロバイダは署名付きでなければなりません。詳細は後のステップで説明します。

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

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

  • プロバイダパッケージ内のすべての SPI 実装クラスを final として宣言し (サブクラス化できないように)、SPI 実装メソッドを protected として宣言する必要があります。
  • プロバイダパッケージ内の暗号化関連ヘルパークラスはすべて、プロバイダパッケージ外からアクセスできないように、パッケージ独自のスコープを保持する必要があります。

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

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

  • CipherSpiengineWrap メソッドと engineUnwrap メソッド。鍵をラップすると、ある場所から別の場所へ安全に転送できます。 鍵のラップおよびラップの解除の詳細は、「Java 暗号化拡張機能 (JCE) リファレンスガイド」の「鍵のラッピングとアンラッピング」を参照してください。

  • 1 つ以上の「免責機構」。 免責機構には、鍵復元、鍵エスクロー、鍵弱化などが含まれます。この機構を実装および実行すると、これを利用するアプリケーション (またはアプレット) に対する暗号化の制限を緩めることができます。 免責機構を利用するアプリケーションの要件に関する詳細は、「Java 暗号化拡張機能 (JCE) リファレンスガイド」の「アプリケーションの暗号化制限の「免責」を取得する方法」を参照してください。

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

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

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

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

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

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

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

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

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

使用すべき標準アルゴリズム名、モード、およびパディング方式については、「Java 暗号化拡張機能 (JCE) リファレンスガイド」の「付録 A」を参照してください。

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

別のプロバイダは、上記の各モードに対応したクラス (ECBCBCCFB、および 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:テストの準備

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

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

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

  1. keytool を使用して、DSA 鍵ペアを生成します。
      keytool -genkey -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>
    

    (注: このコマンドは 1 行に入力しなければなりません。 上の例で複数行に分け、インデントを付けて記述してあるのは、読みやすくするためです。

    これにより、DSA 鍵ペア (公開鍵および関連する非公開鍵) が生成され、指定されたキーストアのエントリに格納されます。公開鍵は、自己署名証明書に格納されます。これ以降、キーストアのエントリには、指定された別名を使用してアクセスできます。

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

        -alias myTestAlias
    

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

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

  2. keytool を使用して、証明書署名要求を生成します。
    keytool -certreq -alias <alias> -sigalg DSA 
            -file <csr file name> 
            -keystore <keystore file name> 
            -storepass <keystore password>
    
    ここで、<alias> には、前のステップで作成した DSA 鍵ペアエントリの別名を指定します。このコマンドにより、証明書署名要求 (CSR) が PKCS#10 形式で生成されます。<csr file name> で指定した名前のファイルに CSR が格納されます。

  3. CSR、連絡情報、および他の必須ドキュメントを JCE コード署名証明書発行局に送ります。

    CSR および連絡情報 (以下を参照) を、電子メールで javasoft-cert-request@sun.com に送ってください。電子メールメッセージの件名行には、以下を入力します。

      Request a Certificate for Signing a JCE Provider
    

    メッセージの本文に連絡情報を入力し、メッセージに CSR ファイルを添付して送信します。添付に使用するエンコーディングを指定するオプションがメールソフトに存在する場合、「MIME」を選択します。注: CSR ファイルは、Base 64 でエンコーディングされたプレーンテキストです。人間が読むことができるのは、最初と最後の行だけです。

    メッセージの本文に次の連絡情報を含めます。

    Company Name
    Street Address (Not a post office box)
    City
    State/Province
    Country
    Company Telephone Number
    Company Fax Number
    Requester Name
    Requester Telephone Number
    Requester Email Address
    Brief description of your company (size, 
        line of business, etc.)
    

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

    電子メールメッセージの受信後に、JCE コード署名証明書発行局は、要求番号を電子メールで返信します。要求番号を受信したなら、適切な認証フォームを出力および記入し、以下の指定されたアドレスに送付します。送付するフォームは、地域 (米国内または米国外) によって異なります。

    いずれの場合にも、フォームに要求番号を記載して以下の住所に郵送することにより、CSR および連絡情報を含む電子メールメッセージと郵送するハードコピーとを一致させる必要があります。 フォームの郵送先を次に示します。

    Corporate Export
    Attn:Encryption export
    901 San Antonio Road, UPAL01-541
    Palo Alto, CA 94303
    

    注: この住所は変更される可能性があります。フォームを送る前に、「Sun Microsystems International Trade Services Contacts」ページで最新の住所を確認してください。
    JCE コード署名証明書は、電子メールメッセージと必要なフォームの両方を受信後に、要求者の認証を行います。その後、5 年間有効なコード署名証明書を作成および署名します。そして、電子メールメッセージに 2 つのプレーンテキストファイルを添付して要求者に送信します。1 つはこのコード署名証明書を含むファイルで、もう 1 つは独自の CA 証明書を含むファイルで公開鍵の認証に使用します。

  4. keytool を使用して CA から受信した証明書をインポートします。

    JCE コード署名証明書発行局から 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> で指定されたキーストアエントリ内の自己署名証明書が、JCE コード署名証明書発行局が署名した証明書で置き換えられます。

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

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

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

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

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

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

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

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

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

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

jarsigner -verify <JAR file name>

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

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

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

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

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

最初に行う事柄は、作成したクラスを利用可能にして、要求時に検出できるようにすることです。プロバイダクラスは Jar (Java ARchive) ファイルの形式で提供します。 プロバイダクラスのインストール方法は 2 種類あります。
  • プロバイダクラスを含む JAR ファイルを、「インストール型」または「バンドル型」の拡張機能としてインストールする方法
  • プロバイダクラスを含む JAR ファイルを CLASSPATH に含める方法

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

<java-home>/lib/ext         [Solaris]
<java-home>¥lib¥ext         [Win32]

ここで、<java-home> は、ランタイムソフトウェアのインストール先ディレクトリ (JavaTM 2 Runtime Environment のトップレベルディレクトリまたは JavaTM 2 SDK ソフトウェアの jre ディレクトリ) を指します。 たとえば、Java 2 SDK, v 1.4 を /home/user1/J2SDK1.4.0 ディレクトリ (Solaris)、または C:¥J2SDK1.4.0 ディレクトリ (Win32) にインストールした場合、JAR ファイルを次のディレクトリにインストールする必要があります。

/home/user1/J2SDK1.4.0/jre/lib/ext    [Solaris]
C:¥J2SDK1.4.0¥jre¥lib¥ext             [Win32]

同様に、JRE, v 1.4 を /home/user1/j2re1.4.0 ディレクトリ (Solaris)、または C:¥j2re1.4.0 ディレクトリ (Win32) にインストールした場合、JAR ファイルを次のディレクトリにインストールする必要があります。

/home/user1/j2re1.4.0/lib/ext         [Solaris]
C:¥j2re1.4.0¥lib¥ext                  [Win32]

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

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

プロバイダの構成

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

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

ここで、<java-home> は JRE がインストールされているディレクトリを指します。 たとえば、Java 2 SDK バージョン 1.4 を /home/user1/J2SDK1.4.0 (Solaris) または C:¥J2SDK1.4.0 (Win32) にインストールしている場合は、次のファイルを編集する必要があります。

/home/user1/J2SDK1.4.0/jre/lib/security/java.security  [Solaris]
C:¥J2SDK1.4.0¥jre¥lib¥security¥java.security           [Win32]

同様に、Java 2 Runtime Environment バージョン 1.4 を Solaris の /home/user1/j2re1.4.0 ディレクトリにインストールしている場合、または Win32 の C:¥j2re1.4.0 ディレクトリにインストールしている場合は、次のファイルを編集する必要があります。

/home/user1/j2re1.4.0/lib/security/java.security       [Solaris]
C:¥j2re1.4.0¥lib¥security¥java.security                [Win32]

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

    security.provider.n=masterClassName

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

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

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

security.provider.1=sun.security.provider.Sun

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

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

別の JCE プロバイダを利用する場合、代替プロバイダを登録する行を追加し、優先順位を適切に設定します。必要に応じて他のプロバイダの順序も調整します。

例として、マスタークラスが com.cryptox.provider パッケージの CryptoX クラスで、プロバイダを 2 番目の優先順位とする場合を考えてみましょう。その場合、java.security ファイルにある「SUN」プロバイダの行の下に次の行を追加して、さらに他のプロバイダの優先順位を 2 より大きくします。

    security.provider.2=com.cryptox.provider.CryptoX
注: プロバイダは動的に登録することもできます。その場合、プログラム (ステップ 6 で記述したテストプログラムなど) は、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";
};

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

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

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

  • java.lang.RuntimePermission (クラス保護ドメインを取得するため)。プロバイダは、自己完全性チェックの実行過程で、独自の保護ドメインの取得が必要になる場合があります。
  • java.security.SecurityPermission (プロバイダプロパティの設定用)

セキュリティマネージャがインストールされていて、プロバイダがインストール型拡張機能でない場合は、プロバイダが正しく機能するかどうかを確認するため、インストールおよび実行環境をテストする必要があります。 なお、テストを実施する前に、プロバイダとこのプロバイダが使用するすべてのプロバイダに適切なアクセス権を付与しておく必要があります。たとえば、名前が「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";
};

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

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 暗号化拡張機能 (JCE) リファレンスガイド」の「アプリケーションの暗号化制限の「免責」を取得する方法」を参照してください。

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

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

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

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

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

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

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

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

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

次のステップは、クライアント用のドキュメントを記述することです。 少なくとも、次の指定が必要です。 さらに、ドキュメント内で、デフォルトのアルゴリズムパラメータなどの、クライアントに関係する他の指定も行う必要があります。

MAC

MAC アルゴリズムごとに、実装が複製可能かどうかを指定します。これは、技術的には必須ではありませんが、複製による中間「「メッセージ認証コード」 (MAC) が可能かどうかを指定することになるため、クライアントの費やす時間およびコードの記述にかかる手間が軽減されます。 MAC の実装が複製可能かどうかがわからない場合、クライアントは 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
}
この例では、

鍵ペアジェネレータ

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

鍵ファクトリ

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

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

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

ステップ 10:プロバイダソフトウェアおよびドキュメントをクライアントから利用可能にする

最後のステップとして、プロバイダソフトウェアおよびドキュメントをカスタマから利用可能にします。

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

各プロバイダは自己完全性チェックを実行して、プロバイダメソッドを JCE を介さずに直接呼び出すなどの操作により、コードを含む JAR ファイルが改変されていないことを保証する必要があります。 JCE サービスの実装を提供するプロバイダには、デジタル署名を行う必要があります。特定の証明書発行局は「信頼できる」と判断され、信頼される証明書発行局のいずれかの証明書まで証明書チェーンを追跡可能な証明書を使って署名されたコードはすべて、信頼できると判断されます。 プロバイダパッケージには、関連した信頼できる証明書発行局の証明書用のバイトが埋め込まれていなければなりません。後述の「証明書チェーンが信頼できるかどうかの判定」 で解説する trustedCaCerts を参照してください。実行時には、埋め込まれた証明書を使用して、プロバイダコードが認証されたものかどうかが判断されます。

現在のところ、信頼できる証明書発行局には、Sun Microsystems の JCE コード署名 CA、および IBM JCE コード署名 CA の 2 つがあります。Sun Microsystems の JCE コード署名 CA からコード署名証明書を取得する方法については、ステップ 5b を参照してください。

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

  1. プロバイダコードを含む JAR ファイルの URL を特定します。

  2. JAR ファイルのデジタル署名を検証して、JAR ファイルの各エントリの少なくとも 1 つの署名者が信頼できることを確認します。

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

プロバイダ JAR ファイルの検索:基本
プロバイダの JAR ファイル URL の確認
JAR ファイルを参照する JarFile の作成
プロバイダ JAR ファイルの検証:基本
検証の設定
JAR ファイル署名のチェック
署名の検証
署名者の信頼性の確認
署名者証明書リストの取得
個々の証明書チェーンの特定と信頼できる証明書チェーンの特定
サンプルコードについて

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

重要:

JCE 1.2.1 では、プラグインする JCE の完全性および信頼性を保証するため、JCE フレームワークの認証用コードをプロバイダに含める必要がありました。 JCE が Java 2 SDK, v 1.4 に統合されることにより、この操作は不要になりました。

JCE フレームワークコードがプロバイダの期待する場所に存在しなくなるため、プロバイダの JCE フレームワーク認証チェックが機能しなくなります。このため、JCE 1.2.1 専用に記述されたプロバイダは、Java 2 SDK, v 1.4 では動作しなくなります。 プロバイダを Java 2 SDK, v 1.4 でのみ動作させたい場合は、そのプロバイダから、JCE フレームワークを認証するコードを除外してください。 プロバイダを JCE 1.2.1 と Java 2 SDK, v 1.4 の JCE の両方で動作させたい場合は、条件文を追加します。 こうしておけば、プロバイダを JCE 1.2.1 で実行する場合にのみ JCE フレームワークを認証するプロバイダコードが実行されるようになります。以下は、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
jf = (JarFile) AccessController.doPrivileged(
	=new PrivilegedExceptionAction() {
    public Object run() throws Exception { 
        JarURLConnection conn = 
              (JarURLConnection) jarURL.openConnection();

        // 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);
        ...   
JarURLConnection を取得できたら、getJarFile メソッドを呼び出して JAR ファイルを取得します。
JarFile jf = (JarFile)jc.getJarFile();

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

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

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

  1. JAR ファイルが署名された JAR ファイルであることを確認します。

  2. JAR ファイルのすべてのエントリを確認して、各エントリの署名が適切であることを検証します。

  3. 各エントリの署名者の証明書の少なくとも 1 つから、信頼できる証明書発行局までたどれることを確認します。

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

検証の設定
JAR ファイル署名のチェック
署名の検証
署名者の信頼性の確認
署名者証明書リストの取得
個々の証明書チェーンの特定と信頼できる証明書チェーンの特定

検証の設定

前のステップで作成した JarFile をパラメータとしてとる verifySingleJarFile メソッドを定義します。

verifySingleJarFile は、基本的に JAR ファイルエントリを 2 回使用します。このメソッドは、効率を上げるため、ベクトル entriesVec を割り当て、最初にループを通過する際に JAR ファイルのエントリを処理し、各エントリを entriesVec に追加して 2 回目のループで使用できるようにします。以下に、メソッドの最初の部分を示します。

private static void verifySingleJarFile(JarFile jf)
    throws IOException, CertificateException {
    Vector entriesVec = new Vector();

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 ファイルの認証を確認するだけでは十分ではありません。検証すべき最終要件は、署名が JCE の信頼するエンティティにより生成されたことです。 署名が信頼できることをテストするために、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'.
            int startIndex = 0;
            X509Certificate[] certChain;
            boolean signedAsExpected = false;
        }
    ...

個々の証明書チェーンの特定と信頼できる証明書チェーンの特定

JarEntrygetCertificates メソッドが返す証明書配列には、1 つ以上の証明書チェーンが含まれます。エントリの署名者ごとに 1 つのチェーンが存在します。各チェーンには、1 つ以上の証明書が含まれます。チェーン内の各証明書は、前の証明書の公開鍵を認証します。チェーン内の最初の証明書には、エントリの署名に実際に使用される非公開鍵に対応する公開鍵が含まれます。その後に続く証明書は、それぞれ前の証明書に署名を行ったエンティティの証明書になります。チェーン内の最後の証明書は、次のいずれかです。

  • 証明書発行局の証明書、または
  • 証明書発行局により発行された証明書
証明書チェーンの配列内で、「信頼できる」エンティティが見つかるまで各チェーンと関連証明書をチェックします。 JAR ファイルエントリごとに、信頼できる証明書チェーンが少なくとも 1 つ以上必要です。
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;
}
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.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 によってセキュリティ例外がスローされます。

サンプルコードは、エラー処理を行うという点、必要に応じて AccessController.doPrivileged を使用するという点で、上記の抜粋コードとは異なっています。doPrivileged の使用方法の詳細は、「特権ブロックのための API」を参照してください。

実装の詳細および要件

アルゴリズムの別名

多くの暗号化アルゴリズムでは、公式の「標準名」が 1 つ存在します。 Java 2 SDK, v 1.4 の JCE で定義されている標準名のリストは、「Java 暗号化拡張機能 (JCE) リファレンスガイド」の「付録 A」に記載されています。

たとえば、DiffieHellman は、PKCS #3 で定義された Diffie-Hellman 鍵協定アルゴリズムの標準名です。

JCE は、Java 2 SDK, v 1.4 の他のセキュリティ製品と同じ方式で、アルゴリズム名の別名を使用します。この方式では、クライアントは、標準名ではなく別名を使用して、アルゴリズムを参照できます。 たとえば、「SunJCE」プロバイダのマスタークラス (SunJCE.java) は、標準名DiffieHellman の鍵協定に対して別名「DH」を定義します。このため、次の文は同じ意味になります。

    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman", "SunJCE");

    KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");
別名は、「マスタークラス」内で定義できます (ステップ 3 を参照)。別名を定義するには、次の名前のプロパティを作成します。
    Alg.Alias.engineClassName.aliasName

ここで、engineClassNameCipherKeyAgreementKeyGeneratorMacSecretKeyFactoryExemptionMechanism のいずれかを指します。また、aliasName は使用する別名を指します。 ExemptionMechanism を除き、プロパティの「値」には、別名の設定されているアルゴリズムの標準アルゴリズム名を指定する必要があります。 ExemptionMechanism の場合、値は免責機構名 (KeyRecoveryKeyEscrowKeyWeakening のいずれか) になります。

たとえば、「SunJCE」プロバイダは、標準名「DiffieHellman」の鍵協定アルゴリズムに対し、別名「DH」を定義します。これは、次に示すように、Alg.Alias.KeyAgreement.DH という名前のプロパティに値 DiffieHellman を設定することにより行います。

    put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");

現在のところ、「SunJCE」プロバイダにより定義された別名は、クライアントがどのプロバイダを要求するとしても、すべてのクライアントから利用可能です。たとえば、Diffie-Hellman アルゴリズムを実装する「MyPro」という名前のプロバイダを作成すると、その別名を定義しなくても、「SunJCE」により定義された別名「DH」を使用してプロバイダの Diffie-Hellman 実装を参照できます。次にその方法を示します。

    KeyAgreement ka = KeyAgreement.getInstance("DH", "MyPro");

サービスの相互依存性

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

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

  1. どちらのアルゴリズムにも対応した独自の実装の提供。

  2. Java 2 プラットフォームの各インストールに含まれるデフォルトの「SUN」プロバイダにより提供される場合のように、一方のアルゴリズムの実装が他方のアルゴリズムのインスタンスを使用するようにします。たとえば、実装している PBE アルゴリズムがメッセージダイジェストアルゴリズムを要求する場合、次の呼び出しを行うことにより、MD5 メッセージダイジェストアルゴリズムを実装するクラスのインスタンスを取得できます。
        MessageDigest.getInstance("MD5", "SUN")
    

  3. 別の特定のプロバイダにより提供される場合のように、一方のアルゴリズムの実装が他方のアルゴリズムのインスタンスを使用するようにします。これは、プロバイダを使用するすべてのクライアントが、インストールされた他方のプロバイダも保持する場合にだけ有効な方法です。

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

デフォルトの初期化

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

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

Diffie-Hellman サービスを実装するプログラマのために、JCE には次のインタフェースが (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 を拡張するため)

アルゴリズムパラメータ仕様クラス

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

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

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

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

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

JCE は、javax.crypto.spec パッケージ内で次のアルゴリズムパラメータ仕様クラスを定義します。

IvParameterSpec クラス

このクラス (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 クラスのインスタンスを返します。

鍵ファクトリにより要求される鍵仕様クラス

鍵仕様は、鍵を構成する鍵データの透明な表現です。JCE は、javax.crypto.spec パッケージ内で、鍵仕様クラス 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 を参照) を次のいずれかの方法で返すことができます。

エクスポート機能の保証

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

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

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

Java 2 SDK, v 1.4 を JCE にプラグインできるようにするため、プロバイダは、以下の条件を満たしていなければなりません。


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

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

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

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

/*
 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.sun.crypto.provider;

import java.security.AccessController;
import java.security.Provider;
. . .

/**
 * The "SunJCE" Cryptographic Service Provider.
 *
 * @author Jan Luehe
 * @author Sharon Liu
 *
 * @version 1.42, 01/08/01
 */

/**
 * Defines the "SunJCE" provider.
 *
 * Supported algorithms and their names:
 *
 * - DES (ECB, CBC, CFB, OFB, PCBC)
 *
 * - DES-EDE (ECB, CBC, CFB, OFB, PCBC)
 *
 * - Password-based Encryption (PBE)
 *
 * - Blowfish
 *
 * - Diffie-Hellman Key Agreement
 *
 * - HMAC-MD5, HMAC-SHA1
 *
 * - PKCS5Padding
 */

public final class SunJCE extends Provider {

    private static String info = "SunJCE Provider " + 
    "(implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman, HMAC-MD5, "
    + "HMAC-SHA1)";

    public SunJCE() {
	/* We are the "SunJCE" provider */
	super("SunJCE", 1.4, info);

        AccessController.doPrivileged(new java.security.PrivilegedAction() {
            public Object run() {

		/*
		 * Cipher engines 
		 */
		put("Cipher.DES", "com.sun.crypto.provider.DESCipher");

		put("Cipher.DESede", "com.sun.crypto.provider.DESedeCipher");
		put("Alg.Alias.Cipher.TripleDES", "DESede");

		put("Cipher.PBEWithMD5AndDES",
		    "com.sun.crypto.provider.PBEWithMD5AndDESCipher");
		put("Cipher.PBEWithMD5AndTripleDES",
		    "com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher");

		put("Cipher.Blowfish",
		    "com.sun.crypto.provider.BlowfishCipher");

		/*
		 *  Key(pair) Generator engines 
		 */
		put("KeyGenerator.DES", 
		    "com.sun.crypto.provider.DESKeyGenerator");

		put("KeyGenerator.DESede", 
		    "com.sun.crypto.provider.DESedeKeyGenerator");
		put("Alg.Alias.KeyGenerator.TripleDES", "DESede");

		put("KeyGenerator.Blowfish", 
		    "com.sun.crypto.provider.BlowfishKeyGenerator");

		put("KeyGenerator.HmacMD5", 
		    "com.sun.crypto.provider.HmacMD5KeyGenerator");

		put("KeyGenerator.HmacSHA1", 
		    "com.sun.crypto.provider.HmacSHA1KeyGenerator");

		put("KeyPairGenerator.DiffieHellman", 
		    "com.sun.crypto.provider.DHKeyPairGenerator");
		put("Alg.Alias.KeyPairGenerator.DH", "DiffieHellman");

		/*
		 * Algorithm parameter generation engines
		 */
		put("AlgorithmParameterGenerator.DiffieHellman",
		    "com.sun.crypto.provider.DHParameterGenerator");
		put("Alg.Alias.AlgorithmParameterGenerator.DH",
		    "DiffieHellman");

		/* 
		 * Key Agreement engines 
		 */
		put("KeyAgreement.DiffieHellman",
		    "com.sun.crypto.provider.DHKeyAgreement");
		put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");

		/* 
		 * Algorithm Parameter engines 
		 */
		put("AlgorithmParameters.DiffieHellman",
		    "com.sun.crypto.provider.DHParameters");
		put("Alg.Alias.AlgorithmParameters.DH", "DiffieHellman");

		put("AlgorithmParameters.DES",
		    "com.sun.crypto.provider.DESParameters");

		put("AlgorithmParameters.DESede",
		    "com.sun.crypto.provider.DESedeParameters");
		put("Alg.Alias.AlgorithmParameters.TripleDES", "DESede");

		put("AlgorithmParameters.PBE",
		    "com.sun.crypto.provider.PBEParameters");
		put("Alg.Alias.AlgorithmParameters.PBEWithMD5AndDES", "PBE");

		put("AlgorithmParameters.Blowfish",
		    "com.sun.crypto.provider.BlowfishParameters");

		/*
		 * Key factories
		 */
		put("KeyFactory.DiffieHellman",
		    "com.sun.crypto.provider.DHKeyFactory");
		put("Alg.Alias.KeyFactory.DH", "DiffieHellman");

		/*
		 * Secret-key factories
		 */
		put("SecretKeyFactory.DES", 
		    "com.sun.crypto.provider.DESKeyFactory");

		put("SecretKeyFactory.DESede",
		    "com.sun.crypto.provider.DESedeKeyFactory");
		put("Alg.Alias.SecretKeyFactory.TripleDES", "DESede");

		put("SecretKeyFactory.PBEWithMD5AndDES",
		    "com.sun.crypto.provider.PBEKeyFactory");

		/*
		 * MAC
		 */
		put("Mac.HmacMD5", "com.sun.crypto.provider.HmacMD5");
		put("Mac.HmacSHA1", "com.sun.crypto.provider.HmacSHA1");

		/*
		 * KeyStore
		 */
		put("KeyStore.JCEKS", "com.sun.crypto.provider.JceKeyStore");

		return null;
	    }
	});
    }

}


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

次に、EMProvider.java ファイルの例を示します。このファイルには、「EMProvider」という名前のプロバイダのマスタークラスである、EMProvider という名前のクラスが含まれます。

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

このコードは、免責機構を実装するプロバイダのマスタークラスの例として提供されています。「SunJCE」プロバイダには免責機構が実装されていないため、このコードは、「SunJCE」プロバイダのマスタークラスを示す「付録 A」 を補うものです。注: プロバイダは、暗号化サービスと免責機構サービスの両方を実装できます。

package com.abc.crypto.provider;

import java.security.AccessController;
import java.security.Provider;

/**
 * The "EMProvider" Cryptographic Service Provider.
 *
 * @version 1.00, 03/15/2000
 */

/**
 * Defines the "EMProvider" provider.
 *
 * Supported algorithm(s) and their name(s):
 *
 * - Key Recovery
 */

public final class EMProvider extends Provider {

    private static String info = "EMProvider Exemption Mechanism Provider " + 
    "(implements KeyRecovery)";

    public EMProvider() {
        /* We are the "EMProvider" provider */
        super("EMProvider", 1.2, info);

        AccessController.doPrivileged(new java.security.PrivilegedAction() {
            public Object run() {

                /* 
                 * Algorithm Parameter engines 
                 */
                put("AlgorithmParameters.KeyRecovery",
                    "com.abc.crypto.provider.KeyRecoveryParameters");
                put("Alg.Alias.AlgorithmParameters.KR", "KeyRecovery");

                /*
                 * ExemptionMechanism
                 */
                put("ExemptionMechanism.KeyRecovery", 
                    "com.abc.crypto.provider.KeyRecovery");
                put("Alg.Alias.ExemptionMechanism.KR", "KeyRecovery");

                return null;
            }
        });
    }
}

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

次に示すのは、java.security ファイルのコピーで、JRE の各インストールに含まれます。このファイルは次の場所にあります。
<java-home>/lib/security/java.security         [Solaris]
<java-home>¥lib¥security¥java.security         [Win32]
ここで、<java-home> は JRE がインストールされているディレクトリを指します。 したがって、Solaris の /home/user1/J2SDK1.4.0 ディレクトリまたは Win32 の C:¥J2SDK1.4.0 ディレクトリに Java 2 SDK v 1.4 をインストールしている場合、ファイルは次の場所にあることになります。
/home/user1/J2SDK1.4.0/jre/lib/security/java.security  [Solaris]
C:¥J2SDK1.4.0¥jre¥lib¥security¥java.security           [Win32]
同様に、Java 2 Runtime Environment バージョン 1.4 を Solaris の /home/user1/j2re1.4.0 ディレクトリにインストールしている場合、または Win32 の C:¥j2re1.4.0 ディレクトリにインストールしている場合は、ファイルは次の場所にあることになります。
/home/user1/j2re1.4.0/lib/security/java.security       [Solaris]
C:¥j2re1.4.0¥lib¥security¥java.security                [Win32]
このファイルにプロバイダに関する情報を追加する例については、ステップ 5d を参照してください。
#
# 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.<n>=<className>
#
# 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: Statically registered Provider subclasses are instantiated
# when the system is initialized. 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.provider.Sun
security.provider.2=com.sun.net.ssl.internal.ssl.Provider
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider

#
# Select the source of seed data for SecureRandom. By default an
# attempt is made to use the entropy gathering device specified by 
# the securerandom.source property. If an exception occurs when
# accessing the URL then the traditional system/thread activity 
# algorithm is used.
#
securerandom.source=file:/dev/random
#
# The entropy gathering device is described as a URL and can 
# also be specified with the property "java.security.egd". For example,
#   -Djava.security.egd=file:/dev/urandom
# Specifying this property will override the securerandom.source setting.

#
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
login.configuration.provider=com.sun.security.auth.login.ConfigFile

#
# Default login configuration file
#
#login.config.url.1=file:${user.home}/.java.login.config

#
# Class to instantiate as the system Policy. This is the name of the class
# that will be used as the Policy object.
#
policy.provider=sun.security.provider.PolicyFile

# The default is to have a single system-wide policy file,
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

# whether or not we expand properties in the policy file
# if this is set to false, properties (${...}) will not be expanded in policy
# files.
policy.expandProperties=true

# whether or not we allow an extra policy to be passed on the command line
# with -Djava.security.policy=somefile. Comment out this line to disable
# this feature.
policy.allowSystemProperty=true

# whether or not we look into the IdentityScope for trusted Identities
# when encountering a 1.1 signed JAR file. If the identity is found
# and is trusted, we grant it AllPermission.
policy.ignoreIdentityScope=false

#
# Default keystore type.
#
keystore.type=jks

#
# Class to instantiate as the system scope:
#
system.scope=sun.security.provider.IdentityDatabase

#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.

#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, no packages are restricted for definition, and none of
# the class loaders supplied with the JDK call checkPackageDefinition.
#
#package.definition=

#
# Determines whether this properties file can be appended to
# or overridden on the command line via -Djava.security.properties
#
security.overridePropertiesFile=true

#
# Determines the default key and trust manager factory algorithms for 
# the javax.net.ssl package.
#
ssl.KeyManagerFactory.algorithm=SunX509
ssl.TrustManagerFactory.algorithm=SunX509

#
# Determines the default SSLSocketFactory and SSLServerSocketFactory
# provider implementations for the javax.net.ssl package.  If, due to
# export and/or import regulations, the providers are not allowed to be
# replaced, changing these values will produce non-functional
# SocketFactory or ServerSocketFactory implementations.
#
#ssl.SocketFactory.provider=
#ssl.ServerSocketFactory.provider=

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set.
#
# NOTE: Setting this value to anything other than the default value 
#       can have serious security implications. Do not set it unless 
#       you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1 

# The Java-level namelookup cache policy for failed lookups:
#
# any negative value: cache forever
# any positive value: the number of seconds to cache negative lookup results
# zero: do not cache
#
# In some Microsoft Windows networking environments that employ
# the WINS name service in addition to DNS, name service lookups
# that fail may take a noticeably long time to return (approx. 5 seconds).
# For this reason the default caching policy is to maintain these
# results for 10 seconds. 
#
#
networkaddress.cache.negative.ttl=10


Copyright ©1996-2002 Sun Microsystems, Inc.All Rights Reserved.

コメントの送付先:java-security@java.sun.com
Sun
Java ソフトウェア
最終更新日: 2002 年 1 月 17 日