このドキュメントは、「JavaTM 暗号化アーキテクチャ (JCA) 仕様およびリファレンス」と共に使用してください。このドキュメントに存在しない章への言及がなされている場合、「JCA 仕様」の章を参照してください。
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 は、実装非依存および可能な場合にはアルゴリズム非依存など、JCA の他の場所と同じ設計方針に基づいています。使用する「プロバイダ」アーキテクチャは、同一です。信頼できるエンティティにより署名されたプロバイダは、JCE フレームワークへのプラグインが可能です。また、新規アルゴリズムをシームレスに追加できます。
JCE API には、以下が含まれます。
- 対称バルク暗号化 (DES、RC2、および IDEA など)
- 対称ストリーム暗号化 (RC4 など)
- 非対称暗号化 (RSA など)
- パスワードベース暗号化 (PBE)
- 鍵協定
- メッセージ認証コード (MAC)
Java 2 SDK, v 1.4 リリースには、
SunJCE
という名前の標準 JCE プロバイダがあらかじめインストールおよび登録されています。SunJCE は、次の暗号化サービスを提供します。
- Electronic Code Book (ECB)、Cipher Block Chaining (CBC)、Cipher Feedback (CFB)、Output Feedback (OFB)、および Propagating Cipher Block Chaining (PCBC) モードの DES (FIPS PUB 46-1)、トリプル DES、および Blowfish 暗号化アルゴリズムの実装 (注: このドキュメントでは、「トリプル DES」と「DES-EDE」を同じものとする)
- DES、トリプル DES、Blowfish、HMAC-MD5、および HMAC-SHA1 アルゴリズムに適した鍵を生成する鍵ジェネレータ
- PKCS #5 で定義された DES-CBC パスワードベース暗号化 (PBE) アルゴリズムを使用する MD5 の実装
- 不透明な DES、トリプル DES、PBE 鍵オブジェクトと、背後の鍵データの透明な表現との双方向変換を提供する「秘密鍵ファクトリ」
- 複数のパーティ間での Diffie-Hellman 鍵協定アルゴリズムの実装
- Diffie-Hellman アルゴリズムに適した公開値および非公開値のペアの生成に必要な Diffie-Hellman 鍵ペアジェネレータ
- Diffie-Hellman アルゴリズムのパラメータジェネレータ
- 不透明な Diffie-Hellman 鍵オブジェクトと背後の鍵データの透明な表現との間の双方向変換を提供する Diffie-Hellman「鍵ファクトリ」
- Diffie-Hellman、DES、トリプル DES、Blowfish、および PBE パラメータ用のアルゴリズムパラメータマネージャ
- RFC 2104 に定義されている、HMAC-MD5 および HMAC-SHA1 キーハッシュアルゴリズムの実装
- PKCS #5 に記載されているパディング方式の実装
- JCEKS という独自のキーストア型のためのキーストアの実装
用語に関する注記
Java 2 SDK, v 1.4 の JCE には、次の 2 つのソフトウェアコンポーネントが含まれます。
このドキュメントでは、「JCE」という語は、Java 2 SDK, v 1.4 の JCE フレームワークを指して使われています。 Java 2 SDK, v 1.4 とともに提供される JCE プロバイダに言及する場合、常に「SunJCE」プロバイダのことを明示的に指しています。
- プロバイダが実装を提供可能な暗号化サービスを定義および提供するフレームワーク。このフレームワークには、
javax.crypto
パッケージ内のすべてが含まれる
- 「SunJCE」という名前のプロバイダ
以下に、JCE 1.2.1 の JCE と J2SDK, v 1.4 の JCE の相違点を示します。
- Java 2 SDK に含まれる新しい JCE
- 強力な暗号化機能をデフォルトで装備し、無制限に利用可能
- 不要になった JCE フレームワークのプロバイダ認証
- PKCS #1、#5、#8 の追加機能のサポート
- SunJCE Blowfish のデフォルトキーサイズの変更
Java 2 SDK に含まれる新しい JCE
Java JCE は、JavaTM 2 SDK, Standard Edition (Java 2 SDK) バージョン 1.2.x および 1.3.x では、オプションのパッケージでしたが、現在は Java 2 SDK, v 1.4 に統合されています。また SunJCE プロバイダは、Java 2 SDK, v 1.4 に含まれる セキュリティプロパティファイル
java.security
にも含まれ、自動的に登録されます。強力な暗号化機能をデフォルトで装備し、無制限に利用可能
輸入管理制限があるため、Java 2 SDK, v 1.4 に同梱された管轄ポリシーファイルは「強固」ですが、暗号化の使用には制限があります。適格国 (大半の国が該当) の在住者は、暗号化機能に制限のない「強度無制限」のバージョンを利用できます。 このバージョンをダウンロードして、Java 2 SDK, v 1.4 に含まれる暗号化の強力なバージョンと置き換えることができます。無制限のバージョンのダウンロード方法の詳細は、以下を参照してください。
http://java.sun.com/products/jce/index-14.html管轄ポリシーファイルは、次の場所に移されました。
ここで、<java-home> は、ランタイムソフトウェアのインストール先ディレクトリ (JavaTM 2 Runtime Environment<java-home>¥lib¥security [Win32] <java-home>/lib/security [Solaris]のトップレベルディレクトリまたは 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 で使用する場合以外はフレームワーク認証コードが実行されないようにすることもできます。
PKCS #1、#5、#8 の追加機能のサポート
JCE と JCA が拡張され、PKCS #1、#5、#8 の追加機能をサポートするようになりました。追加されたクラスは以下のとおりです。
- java.security.spec.RSAOtherPrimeInfo
- java.security.spec.RSAMultiPrimePrivateCrtKeySpec
- java.security.interfaces.RSAMultiPrimePrivateCrtKey
- java.security.spec.PSSParameterSpec
- javax.crypto.interfaces.PBEKey
- javax.crypto.EncryptedPrivateKeyInfo
javax.crypto.spec.PBEKeySpec クラスに追加されたメソッドは以下のとおりです。
public PBEKeySpec(char[] password, byte[] salt, int iterationCount, int keyLength) public PBEKeySpec(char[] password, byte[] salt, int iterationCount) public final void clearPassword() public final byte[] getSalt() public final int getIterationCount() public final int getKeyLength()SunJCE Blowfish のデフォルトキーサイズの変更
SunJCE プロバイダの Blowfish アルゴリズム用デフォルトキーサイズは、56 バイトから 56 ビットに変更されました。
このセクションでは、API により実装される概念、および API 仕様で使用される技術用語の正確な意味に関する高度な説明を提供します。
暗号化および暗号解読
暗号化とは、データ (「クリアテキスト」と呼ばれる) および短い文字列 (「キー」) を受け取って、鍵を知らないサードパーティにとって無意味なデータ (「暗号テキスト) を生成する処理です。 暗号解読とはその逆で、暗号テキストおよび短い鍵文字列を受け取り、クリアテキストを生成する処理です。
パスワードベース暗号化
パスワードベース暗号化 (PBE) では、パスワードから暗号化鍵を導き出します。パスワードから暗号化鍵を取得しようとする攻撃者のタスクを非常に時間のかかるものにするため、大半の PBE 実装では、キーの作成時に乱数への混入 (salt と呼ばれる) が行われます。
暗号
暗号化および暗号解読は、暗号を使って行われます。暗号とは、暗号化方式に従って暗号化および暗号解読を実行可能なオブジェクトのことです。
鍵協定
鍵協定とは、複数のパーティが秘密情報を交換しなくても同じ暗号化鍵を確立可能なプロトコルを指します。
メッセージ認証コード
メッセージ認証コード (MAC) は、信頼できない媒体に送信または格納された情報の完全性を、秘密鍵に基づいてチェックする方法を提供します。一般に、メッセージ認証コードは、秘密鍵を共有する 2 つのパーティ間で送信される情報の有効性を検証する場合に使用されます。
暗号化ハッシュ機能に基づくMAC 機構は、HMAC と呼ばれます。HMAC は、秘密共有鍵と組み合わせて、MD5 や SHA-1 などの任意の暗号化ハッシュ機能で使用できます。HMAC については、RFC 2104 で規定されています。
Cipher クラス
Cipher クラスは、暗号化および暗号解読で使用される暗号機能を提供します。これは、JCE フレームワークのコア部分を構成します。
Cipher オブジェクトの作成
API 内の他のエンジンクラスと同様、Cipher オブジェクトは Cipher クラスの
getInstance
ファクトリメソッドを使って作成されます。ファクトリメソッドは、クラスのインスタンスを返す static メソッドです。この場合は、要求された transformation を実装するCipher
のインスタンスです。Cipher オブジェクトを作成するには、変換名を指定する必要があります。要求された変換の実装を提供するプロバイダを指定することもできます。
public static Cipher getInstance(String transformation); public static Cipher getInstance(String transformation, String provider);変換名だけを指定すると、要求された変換の実装がその環境で使用可能かどうか、また複数の実装が存在する場合には優先度の高い実装が存在するかどうかをシステムが判別します。
変換名とパッケージプロバイダの両方を指定すると、システムは要求されたパッケージ内に要求された変換の実装が存在するかどうかを確認し、存在しない場合には例外をスローします。
変換は、指定された入力に対して実行し、何らかの出力を生成する操作 (または操作のセット) を説明する文字列です。変換には、暗号化アルゴリズム (
DES
など) の名前が必ず含まれます。それにモードおよびパディング方式が続く場合もあります。変換は、次の書式で記述されます。
- "algorithm/mode/padding" または
- "algorithm"
たとえば、以下は有効な変換です。
"DES/CBC/PKCS5Padding" "DES"モードやパディングを指定しない場合、モードおよびパディング方式のプロバイダ固有のデフォルト値が使用されます。たとえば、SunJCE プロバイダは、
DES
、DES-EDE
、およびBlowfish
暗号のデフォルトモードとしてECB
を、デフォルトパディング方式としてPKCS5Padding
を使用します。このため、SunJCE プロバイダでは、
Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");および
Cipher c1 = Cipher.getInstance("DES");の 2 つの文は、等価になります。
ストリーム暗号モードでブロック暗号を要求する (例、
CFB
またはOFB
モードでDES
を要求する) 場合、「DES/CFB8/NoPadding」および「DES/OFB32/PKCS5Padding」変換に示されるように、この数値をモード名に追加することにより、一度に処理するビット数をオプションで指定できます。数値を指定しない場合、プロバイダ固有のデフォルトが使用されます(たとえば、SunJCE プロバイダではデフォルトの 64 ビットが使用される)。このドキュメントの「付録 A」には、変換のアルゴリズム名、モード、およびパディング方式コンポーネントの指定に使用可能な標準名のリストが掲載されています。
ファクトリメソッドにより返されるオブジェクトは初期化されていないため、使用する前に初期化する必要があります。
Cipher オブジェクトの初期化
getInstance
を介して取得された Cipher オブジェクトは、次の 4 つのモードのいずれかで初期化する必要があります。これらのモードは、Cipher
クラスの final (ファイナル) 整数の定数として定義されます。モードは、シンボル名で参照できます。以下に、各モードのシンボル名および目的を示します。
- ENCRYPT_MODE
データの暗号化- DECRYPT_MODE
データの暗号解読- WRAP_MODE
安全に転送するために鍵をラッピングする- UNWRAP_MODE
ラッピングされた鍵をjava.security.Key
オブジェクトにアンラッピングするCipher 初期化メソッドは、それぞれモードパラメータ (
opmode
) を取り、そのモード用の Cipher オブジェクトを初期化します。他のパラメータには、鍵 (key
) または鍵を含む証明書 (certificate
)、アルゴリズムパラメータ (params
)、および乱数の発生源 (random
) が含まれます。Cipher オブジェクトを初期化する場合、次のいずれかの
init
メソッドを呼び出します。public void init(int opmode, Key key); public void init(int opmode, Certificate certificate) public void init(int opmode, Key key, SecureRandom random); public void init(int opmode, Certificate certificate, SecureRandom random) public void init(int opmode, Key key, AlgorithmParameterSpec params); public void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random); public void init(int opmode, Key key, AlgorithmParameters params) public void init(int opmode, Key key, AlgorithmParameters params, SecureRandom random)初期化ベクトルなどのパラメータを必要とする Cipher オブジェクトを暗号化用に初期化する場合、
init
メソッドにパラメータを何も指定しないと、ランダムパラメータを生成するか、プロバイダ固有のパラメータセット (デフォルト) を使用することにより、基盤となる暗号実装が必須パラメータを提供すると見なされます。ただし、パラメータを必要とする Cipher オブジェクトを暗号解読用に初期化する場合、
init
メソッドにパラメータを何も指定しないと、使用するinit
メソッドに応じてInvalidKeyException
またはInvalidAlgorithmParameterException
例外が発生します。詳細は、「アルゴリズムパラメータの管理」に関するセクションを参照してください。
暗号解読には、暗号化に使用したのと同じパラメータを使用する必要があります。
Cipher オブジェクトを初期化すると、それまでに獲得した状態がすべて失われることに留意してください。つまり、Cipher を初期化することは、その Cipher の新規インスタンスを作成して初期化することと等価です。たとえば、指定された鍵で暗号解読を行うために Cipher を初期化してから、暗号化を行うために初期化すると、暗号解読モードで獲得した状態はすべて失われます。
データの暗号化および暗号解読
データの暗号化または暗号解読は、1 つのステップで実行 (「単一部分操作」) することも 、複数のステップで実行 (「複数部分操作」) することもできます。データの長さが不明な場合、またはデータが長すぎて一度にメモリに格納できない場合に、複数部分操作は有用です。
単独のステップでデータの暗号化または暗号解読を行う場合、次のいずれかの
doFinal
メソッドを呼び出します。public byte[] doFinal(byte[] input); public byte[] doFinal(byte[] input, int inputOffset, int inputLen); public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output); public int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)複数のステップでデータの暗号化または暗号解読を行うには、次のいずれかの
update
メソッドを呼び出します。public byte[] update(byte[] input); public byte[] update(byte[] input, int inputOffset, int inputLen); public int update(byte[] input, int inputOffset, int inputLen, byte[] output); public int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)複数部分操作は、上記の
doFinal
メソッドのいずれか (最後のステップで入力データが残される場合)、または次のdoFinal
メソッドのいずれか (最後のステップで入力データが残らない場合) を使って終了させます。public byte[] doFinal(); public int doFinal(byte[] output, int outputOffset);指定された変換の一部としてパディング (またはアンパディング) が要求された場合、すべての
doFinal
メソッドで、必要なパディング (またはアンパディング) 操作がすべて処理されます。
doFinal
を呼び出すと、Cipher オブジェクトはinit
を呼び出して初期化した時の状態にリセットされます。つまり、Cipher はリセットされて、データをさらに暗号化または暗号解読 (init
の呼び出しで指定された操作モードに基づく) できるようになります。鍵のラッピングとアンラッピング
鍵をラッピングすると、ある場所から別の場所へ安全に転送できます。
wrap/unwrap
API は鍵オブジェクトに対して直接機能するため、この API を使用するとコードの記述が容易になります。次のメソッドを使用すると、ハードウェアベースの鍵の安全な転送も可能になります。Key を wrap する場合、まず WRAP_MODE の Cipher オブジェクトを初期化し、次のメソッドを呼び出します。
public final byte[] wrap(Key key);ラップされた鍵のバイト (
wrap
を呼び出した結果) を、そのラップを解除する他のユーザに提供する場合、受信者がunwrap
を実行するのに必要な、次の追加情報も送信する必要があります。
- 鍵アルゴリズムの名前
- ラップされた鍵の型 (
Cipher.SECRET_KEY
、Cipher.PRIVATE_KEY
、またはCipher.PUBLIC_KEY
のいずれか)鍵アルゴリズム名は、次に示すように Key インタフェースから
getAlgorithm
メソッドを呼び出すことにより確認できます。public String getAlgorithm();
wrap
への呼び出しにより返されたバイトのラップを解除するには、UNWRAP_MODE の Cipher オブジェクトを初期化してから、以下を呼び出します。public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType));ここで、
wrappedKey
はラップへの呼び出しにより返されたバイトを、wrappedKeyAlgorithm
はラップされた鍵に関連付けられたアルゴリズムを、wrappedKeyType
はラップされた鍵の型をそれぞれ指します。これは、Cipher.SECRET_KEY
、Cipher.PRIVATE_KEY
、またはCipher.PUBLIC_KEY
のいずれかでなければなりません。アルゴリズムパラメータの管理
基盤となる Cipher 実装により使用されるパラメータ (アプリケーションにより
init
メソッドに明示的に渡されたか、基盤となる実装自体により生成された) は、getParameters
メソッドを呼び出すことにより Cipher オブジェクトから取得できます。このメソッドは、パラメータをjava.security.AlgorithmParameters
オブジェクト (パラメータが使用されない場合はnull
) として返します。パラメータが初期化ベクトル (IV) の場合、getIV
メソッドを呼び出すことによりパラメータを取得できます。次の例では、パスワードベース暗号化を実装する Cipher オブジェクトを、パラメータを使用せずに鍵のみを使用して初期化します。ただし、選択されたパスワードベース暗号化用に選択されたアルゴリズムは、salt および iteration count という 2 つのパラメータを必要とします。これらは、基盤となるアルゴリズム実装自体により生成されます。アプリケーションは、生成されたパラメータを以下の方法で Cipher オブジェクトから取得できます。
import javax.crypto.*; import java.security.AlgorithmParameters; // get cipher object for password-based encryption Cipher c = Cipher.getInstance("PBEWithMD5AndDES"); // initialize cipher for encryption, without supplying // any parameters. Here, "myKey" is assumed to refer // to an already-generated key. c.init(Cipher.ENCRYPT_MODE, myKey); // encrypt some data and store away ciphertext // for later decryption byte[] cipherText = c.doFinal("This is just an example".getBytes()); // retrieve parameters generated by underlying cipher // implementation AlgorithmParameters algParams = c.getParameters(); // get parameter encoding and store it away byte[] encodedAlgParams = algParams.getEncoded();暗号解読には、暗号化に使用したのと同じパラメータを使用する必要があります。これらは、エンコーディングからインスタンス化することが可能であり、次に示すように、対応する Cipher オブジェクトを暗号解読用に初期化する際に使用できます。
import javax.crypto.*; import java.security.AlgorithmParameters; // get parameter object for password-based encryption AlgorithmParameters algParams; algParams = AlgorithmParameters.getInstance("PBEWithMD5AndDES"); // initialize with parameter encoding from above algParams.init(encodedAlgParams); // get cipher object for password-based encryption Cipher c = Cipher.getInstance("PBEWithMD5AndDES"); // initialize cipher for decryption, using one of the // init() methods that takes an AlgorithmParameters // object, and pass it the algParams object from above c.init(Cipher.DECRYPT_MODE, myKey, algParams);Cipher オブジェクトの初期化時にパラメータを一切指定せず、基盤となる実装がいずれかのパラメータを使用するかどうか不明な場合、Cipher オブジェクトの
getParameters
メソッドを呼び出して、返される値をチェックするだけで確認できます。返される値がnull
の場合、パラメータが使用されなかったことを示します。SunJCE プロバイダにより実装される次の暗号アルゴリズムは、パラメータを使用します。
- DES、DES-EDE、および Blowfish は、フィードバック (つまり CBC、CFB、OFB、または PCBC) モードでの使用時に、初期化ベクトル (IV) を使用します。
javax.crypto.spec.IvParameterSpec
クラスは、指定された IV での Cipher オブジェクトの初期化に使用できます。
- PBEWithMD5AndDES は、salt および iteration count で構成されるパラメータセットを使用します。
javax.crypto.spec.PBEParameterSpec
クラスは、指定された salt および iteration count を使って PBEWithMD5AndDES を実装する Cipher オブジェクトを初期化する場合に使用できます。
SealedObject
クラスを使用する場合、暗号解読操作に使用するアルゴリズムパラメータの格納または転送について心配する必要はありません。このクラスは、シール (暗号化) に使用されるパラメータを暗号化されたオブジェクトコンテンツに添付します。また、アンシール (暗号解読) でも同じパラメータを使用します。暗号出力時の考慮事項
Cipher の
update
およびdoFinal
の中には、呼び出し側による出力バッファの指定が可能なものがあります。暗号化または暗号解読されたデータは、このバッファ内に出力されます。この場合、暗号化または暗号解読操作の結果を保持できるだけの大きさのバッファを渡すことは重要です。Cipher 内の次のメソッドを使用して、設定すべき出力バッファのサイズを確認できます。
public int getOutputSize(int inputLen)Cipher Stream クラス
JCE に、セキュリティ保護されたストリームという概念が導入されました。これは、InputStream または OutputStream を Cipher オブジェクトと結び付けることにより実現されています。セキュリティ保護されたストリームは、
CipherInputStream
およびCipherOutputStream
クラスにより提供されます。
CipherInputStream クラス
このクラスは、通過するデータの暗号化または暗号解読を行う
FilterInputStream
です。これは、InputStream
またはそのサブクラスのいずれか、およびCipher
で構成されます。CipherInputStream は、Cipher オブジェクトの挿入先の、セキュリティ保護された入力ストリームを表します。CipherInputStream のread
メソッドは、基盤となる InputStream から読み取られ、埋め込まれた Cipher オブジェクトによりさらに処理されたデータを返します。Cipher オブジェクトは、CipherInputStream で使用する前に完全に初期化する必要があります。たとえば、埋め込まれた Cipher が暗号解読用に初期化されている場合、CipherInputStream は基盤となる InputStream から読み込んだデータの暗号解読を試みてから、データをアプリケーションに返します。
このクラスは、上位クラス
java.io.FilterInputStream
およびjava.io.InputStream
のセマンティクス (特にエラーに関するセマンティクス) に厳密に準拠します。このクラスは、上位クラスで指定されたメソッドを正確に保持し、それらすべてをオーバーライドします。このため、埋め込まれた暗号によるデータの追加処理が可能になります。さらに、このクラスは、上位クラスがスローしない例外をすべてキャッチします。特に、skip(long)
メソッドは、Cipher により処理されたデータだけを無視します。このクラスを使用するプログラマにとって、このクラスが定義またはオーバーライドされていないメソッド (上位クラスのいずれかに後で追加された新規メソッドまたはコンストラクタ) を使用しないようにすることは重要です。これらのメソッド実装は、CipherInputStream へのセキュリティ面の影響を考慮に入れていないためです。
使用方法の一例として、
cipher1
が暗号化用に初期化されている場合を考えてみましょう。以下のコードは、暗号および FileInputStream を含む CipherInputStream を使用して、入力ストリームデータを暗号化する方法を示します。FileInputStream fis; FileOutputStream fos; CipherInputStream cis; fis = new FileInputStream("/tmp/a.txt"); cis = new CipherInputStream(fis, cipher1); fos = new FileOutputStream("/tmp/b.txt"); byte[] b = new byte[8]; int i = cis.read(b); while (i != -1) { fos.write(b, 0, i); i = cis.read(b); }上記のプログラムは、ファイル
/tmp/a.txt
からコンテンツを読み取って暗号化し、結果 (暗号化されたバイト) を/tmp/b.txt
に格納します。次の例は、CipherInputStream および FileInputStream の複数インスタンスを簡単に接続する方法を示します。この例では、
cipher1
およびcipher2
が、それぞれ暗号化および暗号解読用に (対応する鍵を使用して) 初期化されているものとします。FileInputStream fis; FileOutputStream fos; CipherInputStream cis1, cis2; fis = new FileInputStream("/tmp/a.txt"); cis1 = new CipherInputStream(fis, cipher1); cis2 = new CipherInputStream(cis1, cipher2); fos = new FileOutputStream("/tmp/b.txt"); byte[] b = new byte[8]; int i = cis2.read(b); while (i != -1) { fos.write(b, 0, i); i = cis2.read(b); }上記のプログラムは、ファイル
/tmp/a.txt
の内容を/tmp/b.txt
にコピーします。ただし、/tmp/a.txt
からの読み取り時に、最初に内容の暗号化、次に暗号解読が行われます。実際のところ、このプログラムはテキストを暗号化した後、すぐに暗号解読を行うため、CipherInputStreams のチェーンをわかりやすく示す以外は特に有用なものではありません。CipherOutputStream クラス
このクラスは、通過するデータの暗号化または暗号解読を行う
FilterOutputStream
です。これは、OutputStream
またはそのサブクラスのいずれか、およびCipher
で構成されます。CipherOutputStream は、Cipher オブジェクトの挿入先の、セキュリティ保護された出力ストリームを表します。CipherOutputStream のwrite
メソッドは、埋め込まれた Cipher オブジェクトを使ってデータを処理してから、基盤となる OutputStream にデータを書き出します。Cipher オブジェクトは、CipherOutputStream で使用する前に完全に初期化する必要があります。たとえば、埋め込まれた Cipher が暗号化用に初期化されている場合、CipherOutputStream はデータを暗号化してから、基盤となる出力ストリームに書き出します。
このクラスは、上位クラス
java.io.OutputStream
およびjava.io.FilterOutputStream
のセマンティクス (特にエラーに関するセマンティクス) に厳密に準拠します。このクラスは、上位クラスで指定されたメソッドを正確に保持し、それらすべてをオーバーライドします。このため、埋め込まれた暗号によるすべてのデータの追加処理が可能になります。さらに、このクラスは、上位クラスがスローしない例外をすべてキャッチします。このクラスを使用するプログラマにとって、このクラスが定義またはオーバーライドされていないメソッド (上位クラスのいずれかに後で追加された新規メソッドまたはコンストラクタ) を使用しないようにすることは重要です。これらのメソッド実装は、CipherOutputStream へのセキュリティ面の影響を考慮に入れていないためです。
使用方法の一例として、
cipher1
が暗号化用に初期化されている場合を考えてみましょう。以下のコードは、暗号および FileOutputStream を含む CipherOutputStream を使用して、暗号化されたデータを出力ストリームに書き出す方法を示します。FileInputStream fis; FileOutputStream fos; CipherOutputStream cos; fis = new FileInputStream("/tmp/a.txt"); fos = new FileOutputStream("/tmp/b.txt"); cos = new CipherOutputStream(fos, cipher1); byte[] b = new byte[8]; int i = fis.read(b); while (i != -1) { cos.write(b, 0, i); i = fis.read(b); } cos.flush();上記のプログラムは、ファイル
/tmp/a.txt
からコンテンツを読み取って暗号化し、結果 (暗号化されたバイト) を/tmp/b.txt
に格納します。次の例は、CipherOutputStream および FileOutputStream の複数インスタンスを簡単に接続する方法を示します。この例では、
cipher1
およびcipher2
が、それぞれ暗号解読および暗号化用に (対応する鍵を使用して) 初期化されているものとします。FileInputStream fis; FileOutputStream fos; CipherOutputStream cos1, cos2; fis = new FileInputStream("/tmp/a.txt"); fos = new FileOutputStream("/tmp/b.txt"); cos1 = new CipherOutputStream(fos, cipher1); cos2 = new CipherOutputStream(cos1, cipher2); byte[] b = new byte[8]; int i = fis.read(b); while (i != -1) { cos2.write(b, 0, i); i = fis.read(b); } cos2.flush();上記のプログラムは、ファイル
/tmp/a.txt
の内容を/tmp/b.txt
にコピーします。ただし、/tmp/b.txt
に書き込む前に、内容の暗号化および暗号解読が行われます。このクラスの
flush
とclose
メソッドには 1 つの重要な相違点があります。カプセル化された Cipher オブジェクトが、パディングを有効にしてブロック暗号アルゴリズムを実装する場合、この相違点に特に留意する必要があります。
flush
は、カプセル化された Cipher オブジェクトにより処理済みのバッファリングされた出力バイトをすべて強制的に書き出すことにより、基盤となる OutputStream をフラッシュします。カプセル化された Cipher オブジェクトによりバッファリングされ、処理待ち状態にあるバイトは、書き出されません。
close
は、基盤となる OutputStream を閉じて、関連付けられたすべてのシステムリソースを解放します。カプセル化された Cipher オブジェクトのdoFinal
メソッドを呼び出して、このオブジェクトによりバッファリングされたすべてのバイトを処理します。さらにflush
メソッドを呼び出して、処理したバイトを基盤となるストリームに書き出します。KeyGenerator クラス
鍵ジェネレータは、対称アルゴリズム用の秘密鍵を生成します。
鍵ジェネレータの作成
API 内の他のエンジンクラスと同様、KeyGenerator オブジェクトは KeyGenerator クラスの
getInstance
ファクトリメソッドを使って作成されます。ファクトリメソッドは、クラスのインスタンスを返す static メソッドです。この場合は、要求された鍵ジェネレータの実装を提供するKeyGenerator
のインスタンスです。
getInstance
は、秘密鍵を生成する対称アルゴリズムの名前を引数として取ります。オプションで、パッケージプロバイダ名を指定することもできます。public static KeyGenerator getInstance(String algorithm); public static KeyGenerator getInstance(String algorithm, String provider);アルゴリズム名だけを指定すると、要求された鍵ジェネレータの実装がその環境で使用可能かどうか、また複数の実装が存在する場合には優先度の高い実装が存在するかどうかをシステムが判別します。
アルゴリズム名とパッケージプロバイダの両方を指定すると、システムは要求されたパッケージ内に要求された鍵ジェネレータの実装が存在するかどうかを確認し、存在しない場合には例外をスローします。
KeyGenerator オブジェクトの初期化
特定の対称鍵アルゴリズムの鍵ジェレネータは、そのアルゴリズムで使用可能な対称鍵を作成します。また、生成された鍵に、アルゴリズムに特定のパラメータ (存在する場合) を関連付けます。
鍵の生成方法には、アルゴリズム独立型とアルゴリズム特定型の 2 つがあります。この 2 つの唯一の相違点は、オブジェクトの初期化にあります。
- アルゴリズム独立型の初期化
すべての鍵ジェネレータは、「キーサイズ」および「乱数の発生源」の概念を共有します。普遍的に共有されるこれら 2 つの引数の型をとる
init
メソッドが存在します。また、keysize
引数のみをとり、システムにより提供される乱数の発生源を使用するinit
メソッドや、乱数の発生源だけをとるinit
メソッドも存在します。public void init(SecureRandom random); public void init(int keysize); public void init(int keysize, SecureRandom random);上のアルゴリズムに依存しない
init
メソッドを呼び出すときは、その他のパラメータは指定しないため、生成された鍵に関連付けられるアルゴリズムに特定のパラメータが存在する場合、そのパラメータの処理は、プロバイダによって異なります。
- アルゴリズム特定型の初期化
アルゴリズムに特定のパラメータのセットがすでに存在する状況では、
AlgorithmParameterSpec
引数を取るinit
メソッドが 2 つあります。このうちの一方はSecureRandom
引数も取りますが、他方では、乱数の発生源はシステムによって提供されます。public void init(AlgorithmParameterSpec params); public void init(AlgorithmParameterSpec params, SecureRandom random);クライアントが (
init
メソッドの呼び出しを介して) KeyGenerator を明示的に初期化しない場合、各プロバイダはデフォルトの初期化を提供およびドキュメント化する必要があります。鍵の作成
次のメソッドにより、秘密鍵が生成されます。public SecretKey generateKey();SecretKeyFactory クラス
このクラスは、秘密鍵のファクトリを表します。
鍵ファクトリは、「鍵」(
java.security.Key
型の不透明な暗号化鍵) を「鍵仕様」(背後の鍵データの適切な形式の透明表現) に変換したり、その逆の変換を行うために使用します。
javax.crypto.SecretKeyFactory
オブジェクトは、秘密 (対称) 鍵のみを処理するのに対し、java.security.KeyFactory
オブジェクトは鍵ペアの公開鍵および非公開鍵コンポーネントを処理します。
java.security.Key
型のオブジェクト (java.security.PublicKey
、java.security.PrivateKey
、およびjavax.crypto.SecretKey
はそのサブクラス) は、その実装方法が不明であるため、不透明な鍵オブジェクトになります。基盤となる実装はプロバイダ依存であるため、ソフトウェアベースにもハードウェアベースにもできます。鍵ファクトリを使用すると、プロバイダは独自の暗号化鍵実装を提供できるようになります。たとえば、公開値
y
、プライム係数p
、ベースg
で構成される Diffie Hellman 公開鍵の鍵仕様を保持しており、同じ仕様を別のプロバイダの Diffie-Hellman 鍵ファクトリに送る場合、生成されるPublicKey
オブジェクトは大抵、異なる基盤実装を保持するようになります。プロバイダは、秘密鍵ファクトリがサポートする鍵仕様をドキュメント化する必要があります。たとえば、「SunJCE」プロバイダにより提供される DES 鍵の
SecretKeyFactory
は、DESKeySpec
を DES 鍵の透明表現としてサポートします。また、DES-EDE 鍵のSecretKeyFactory
はDESedeKeySpec
を DES-EDE 鍵の透明表現として、PBE のSecretKeyFactory
はPBEKeySpec
を基盤となるパスワードの透明表現として、それぞれサポートします。次の例は、
SecretKeyFactory
を使用して秘密鍵データをSecretKey
オブジェクトに変換する方法を示します。これは、以降のCipher
操作で使用できます。// Note the following bytes are not realistic secret key data // bytes but are simply supplied as an illustration of using data // bytes (key material) you already have to build a DESKeySpec. byte[] desKeyData = { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08 }; DESKeySpec desKeySpec = new DESKeySpec(desKeyData); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec);この場合、
secretKey
の基盤実装は、keyFactory
のプロバイダに基づきます。別の方法として、プロバイダに依存せずに、同じ鍵データから等価な機能を持つ
SecretKey
オブジェクトを作成することも可能です。その場合、javax.crypto.SecretKey
インタフェースを実装するjavax.crypto.spec.SecretKeySpec
クラスを使用します。byte[] desKeyData = { (byte)0x01, (byte)0x02, ...}; SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "DES");SealedObject クラス
プログラマは、このクラスを使用してオブジェクトを作成し、暗号化アルゴリズムを利用してその機密性を保護することができます。
java.io.Serializable
インタフェースを実装するオブジェクトが指定された場合、元のオブジェクトを直列化形式 (「ディープコピー」) でカプセル化するSealedObject
を作成し、DES などの暗号化アルゴリズムを使用して直列化された内容をシール (暗号化) することにより、機密性を保護できます。その後、暗号化された内容の暗号解読 (適正な暗号解読鍵を使用)、および直列化解除を行うことにより、元のオブジェクトを復元できます。一般的な使用法を、次のコード例に示します。オブジェクトをシールする場合、シール対象のオブジェクトから
SealedObject
を作成し、直列化されたオブジェクト内容を暗号化する、完全に初期化されたCipher
オブジェクトを作成します。この例では、文字列「This is a secret」が DES アルゴリズムを使用してシールされます。シール操作に使用されるすべてのアルゴリズムパラメータは、SealedObject
の内部に格納されることに留意してください。
// create Cipher object // Note: sKey is assumed to refer to an already-generated // secret DES key. Cipher c = Cipher.getInstance("DES"); c.init(Cipher.ENCRYPT_MODE, sKey); // do the sealing SealedObject so = new SealedObject("This is a secret", c);シールされた元のオブジェクトは、次の異なる 2 つの方法で復元可能です。
- 厳密に同一のアルゴリズム、鍵、パディング方式などで初期化され、オブジェクトのシールに使用された
Cipher
オブジェクトを使用する方法
c.init(Cipher.DECRYPT_MODE, sKey); try { String s = (String)so.getObject(c); } catch (Exception e) { // do something };この方法には、暗号解読鍵に関する知識がなくても、シールされたオブジェクトのアンシールを実行できるという利点があります。たとえば、あるパーティが暗号オブジェクトを必須の暗号解読鍵を使って初期化した後で、別のパーティに渡すと、そのパーティはシールされたオブジェクトをアンシールできます。
- 適切な暗号解読鍵を使用する方法 (DES は対称暗号化アルゴリズムであるため、シールとアンシールに同じ鍵を使用できる)
try { String s = (String)so.getObject(sKey); } catch (Exception e) { // do something };この方法では、
getObject
メソッドは、適切な暗号解読アルゴリズム用の暗号オブジェクトを作成し、シール済みのオブジェクトに格納された暗号解読鍵およびアルゴリズムパラメータ (存在する場合) を使用して初期化を行います。この方法の利点は、オブジェクトをアンシールするパーティが、オブジェクトのシールに使用したパラメータ (例、IV) を追跡する必要がないことです。KeyAgreement クラス
KeyAgreement クラスは、鍵協定プロトコルの機能を提供します。共有の秘密作成に関係する鍵は、
KeyPairGenerator
またはKeyGenerator
のいずれかの鍵ジェネレータか、KeyFactory
により、または鍵協定プロトコルの中間フェーズの結果として作成されます。KeyAgreement オブジェクトの作成
鍵協定に関係する各パーティは、KeyAgreement オブジェクトを作成する必要があります。API 内の他のエンジンクラスと同様、KeyAgreement オブジェクトは KeyAgreement クラスの
getInstance
ファクトリメソッドを使って作成されます。ファクトリメソッドは、クラスのインスタンスを返す static メソッドです。この場合は、要求された鍵協定アルゴリズムを提供するKeyAgreement
のインスタンスです。
getInstance
は、引数として鍵協定アルゴリズムの名前を取ります。オプションで、パッケージプロバイダ名を指定することもできます。public static KeyAgreement getInstance(String algorithm); public static KeyAgreement getInstance(String algorithm, String provider);アルゴリズム名だけを指定すると、要求された鍵協定の実装がその環境で使用可能かどうか、また複数の実装が存在する場合には優先度の高い実装が存在するかどうかをシステムが判別します。
アルゴリズム名とパッケージプロバイダの両方を指定すると、システムは要求されたパッケージ内に要求された鍵協定の実装が存在するかどうかを確認し、存在しない場合には例外をスローします。
KeyAgreement オブジェクトの初期化
非公開情報を使用して KeyAgreement オブジェクトを初期化できます。Diffie-Hellman の場合、Diffie-Hellman 非公開鍵を使用して初期化します。補足的な初期化情報には、乱数の発生源、アルゴリズムパラメータのセットが含まれます。要求された鍵協定アルゴリズムで、アルゴリズムパラメータを指定する必要があり、また KeyAgreement オブジェクトの初期化にパラメータではなく鍵だけが提供される場合、必須のアルゴリズムパラメータを鍵に含める必要があります。たとえば、Diffie-Hellman アルゴリズムは、プライム係数
p
およびベースジェネレータg
をパラメータとして使用します。KeyAgreement オブジェクトを初期化する場合、次のいずれかの
init
メソッドを呼び出します。public void init(Key key); public void init(Key key, SecureRandom random); public void init(Key key, AlgorithmParameterSpec params); public void init(Key key, AlgorithmParameterSpec params, SecureRandom random);KeyAgreement フェーズの実行
各協定プロトコルは、鍵協定に関係する各パーティが実行する必要のある多数のフェーズで構成されます。
鍵協定の次のフェーズを実行するには、
doPhase
メソッドを呼び出します。public Key doPhase(Key key, boolean lastPhase);
key
パラメータには、そのフェーズで処理する鍵が含まれます。大抵の場合、これは、鍵協定に関係する他のパーティのいずれかの公開鍵、または前のフェーズで生成された中間鍵です。doPhase
は、この鍵協定の他のパーティに送信する必要のある中間鍵を返すため、続くフェーズでその鍵を処理できます。
lastPhase
パラメータには、実行するフェーズが鍵協定の最後のフェーズかどうかを指定します。値FALSE
は、これが鍵協定の最後のフェーズではない (この後にフェーズが続く) ことを示します。値TRUE
は、これが鍵協定の最後のフェーズであり、鍵協定が完了する (次にgenerateSecret
が呼び出される) ことを示します。Diffie-Hellman で 2 つのパーティが存在する場合 (see 「付録 F」を参照)、
lastPhase
をTRUE
に設定してdoPhase
を呼び出します。 Diffie-Hellman で 3 つのパーティが存在する場合、doPhase
を 2 度呼び出します。最初はlastPhase
をFALSE
に設定し、2 度目にはlastPhase
をTRUE
に設定します。共有される秘密の生成
各パーティがすべての必須鍵協定フェーズを実行した後で、
generateSecret
メソッドのいずれかを呼び出して共有される秘密を計算できます。public byte[] generateSecret(); public int generateSecret(byte[] sharedSecret, int offset); public SecretKey generateSecret(String algorithm);Mac クラス
Mac クラスは、メッセージ認証コード (MAC) の機能を提供します。「付録 F」の「コード例」を参照してください。
Mac オブジェクトの作成
API 内の他のエンジンクラスと同様、Mac オブジェクトは Mac クラスの
getInstance
ファクトリメソッドを使って作成されます。ファクトリメソッドは、クラスのインスタンスを返す static メソッドです。この場合は、要求された MAC アルゴリズムを提供するMac
のインスタンスです。
getInstance
は、引数として Mac アルゴリズムの名前を取ります。オプションで、パッケージプロバイダ名を指定することもできます。public static Mac getInstance(String algorithm); public static Mac getInstance(String algorithm, String provider);アルゴリズム名だけを指定すると、要求された MAC アルゴリズムの実装がその環境で使用可能かどうか、また複数の実装が存在する場合には優先度の高い実装が存在するかどうかをシステムが判別します。
アルゴリズム名とパッケージプロバイダの両方を指定すると、システムは要求されたパッケージ内に要求された MAC アルゴリズムの実装が存在するかどうかを確認し、存在しない場合には例外をスローします。
Mac オブジェクトの初期化
Mac オブジェクトは、常に (秘密) 鍵を使って初期化されます。また、基盤となる MAC アルゴリズムによっては、パラメータセットを使って初期化することもできます。
Mac オブジェクトを初期化する場合、次のいずれかの
init
メソッドを呼び出します。public void init(Key key); public void init(Key key, AlgorithmParameterSpec params);
javax.crypto.SecretKey
インタフェースを実装する任意の (秘密) 鍵オブジェクトを使って、Mac オブジェクトを初期化できます。これは、javax.crypto.KeyGenerator.generateKey()
が返すオブジェクト、javax.crypto.KeyAgreement.generateSecret()
などが返す鍵協定プロトコルの結果生成されるオブジェクト、またはjavax.crypto.spec.SecretKeySpec
のインスタンスです。MAC アルゴリズムの中には、Mac オブジェクトの初期化に使用される (秘密) 鍵オブジェクトに関連付けられた (秘密) 鍵アルゴリズムが重要ではないものがあります (SunJCE プロバイダの HMAC-MD5 および HMAC-SHA1 実装の場合)。ただし、それ以外の場合、(秘密) 鍵アルゴリズムは重要であり、(秘密) 鍵オブジェクトが不適切な (秘密) 鍵アルゴリズムで使用されると、
InvalidKeyException
がスローされます。MAC の計算
MAC は、1 つのステップで計算 (「単一部分操作」) することも 、複数のステップで計算 (「複数部分操作」) することもできます。データの長さが不明な場合、またはデータが長すぎて一度にメモリに格納できない場合に、複数部分操作は有用です。
あるデータの MAC を 1 回のステップで計算するには、次の
doFinal
メソッドを呼び出します。public byte[] doFinal(byte[] input);複数のステップでデータの MAC を計算するには、次のいずれかの
update
メソッドを呼び出します。public void update(byte input); public void update(byte[] input); public void update(byte[] input, int inputOffset, int inputLen);複数部分操作は、上記の
doFinal
メソッド (最後のステップで入力データが残される場合)、または次のdoFinal
メソッドのいずれか (最後のステップで入力データが残らない場合) を使って終了させます。public byte[] doFinal(); public void doFinal(byte[] output, int outOffset);
[注 1:大半のアプリケーション開発者には、このセクションで説明する内容は関係ありません。関係があるのは、作成するアプリケーションが、政府により暗号化制限の課された国に輸出される可能性があり、アプリケーションをその制限に適合させる必要がある場合だけです。この節を省略する場合は、Installing JCE Providers for the Java 2 SDK, v 1.4 へ進んでください。]
[注 2:このセクション全体で、「アプリケーション」という語は、アプリケーションとアプレットの両方を指します。]
Java 2 SDK, v 1.4 の JCE フレームワークには、異なる管轄コンテキスト (位置) のアプレット/アプリケーションから利用可能な暗号化アルゴリズムおよび最大暗号化強度に関する制限を施行する機能が含まれます。これらの制限はすべて、「管轄ポリシーファイル」に指定されます。
輸入管理制限があるため、Java 2 SDK, v 1.4 に同梱された管轄ポリシーファイルは「強固」ですが、暗号化の使用には制限があります。適格国 (大半の国が該当) の在住者は、暗号化機能に制限のない「強度無制限」のバージョンを利用できます。ただし、政府が制限を課しているこれらの国が輸入できるのは「強力な」バージョンだけです。JCE フレームワークでは、インストール済みの管轄ポリシーファイルで指定された制限が施行されます。
これらの国の一部またはすべてで、特定のアプリケーションに対し、暗号化制限の一部またはすべての免責が許可されています。たとえば、特定の種類のアプリケーションは「特別」と見なされ、免責されます。また、鍵復元などの「免責機構」を利用するアプリケーションは、免責可能です。この種の国では、免責されたと見なされるアプリケーションは、免責されていないアプリケーションに許可されるよりも強力な暗号化にアクセスできます。
実行時にアプリケーションが「免責されている」と認識されるようにするには、次の条件を満たす必要があります。
- JAR ファイル内にアクセス権ポリシーファイルを保持する必要があります。アクセス権ポリシーファイルには、アプリケーションが保持する暗号化関連のアクセス権、およびそれを保持する条件 (存在する場合) を指定します。
- アプリケーションおよびアクセス権ポリシーファイルを含む JAR ファイルには、アプリケーションが免責を受け取った後で発行されたコード署名証明書を使用して署名する必要があります。
以下に、暗号化制限の一部またはすべての免責をアプリケーションに設定するために必要な手順のサンプルを示します。これは、免責されたものとしてアプリケーションを認識および処理するため、JCE により要求される情報を含む、基本情報です。実際には、アプリケーションを実行可能にする (政府が暗号化制限を課している) 特定の国の免責要件を知る必要があります。また、免責されたアプリケーションの処理プロセスを保持する JCE フレームワークベンダーの要件も理解しておく必要があります。詳細は、ベンダーにお尋ねください。なお、SunJCE プロバイダは、ExemptionMechanismSpi クラスの実装を提供しません。
- ステップ 1:アプリケーションコードの記述およびコンパイル
- ステップ 2:適切な暗号化アクセス権を付与するアクセス権ポリシーファイルの作成
- ステップ 3:テストの準備
- ステップ 3a:政府の課す制限に関する政府承認の申請
- ステップ 3b:コード署名証明書の取得
- ステップ 3c:アプリケーションおよびアクセス権ポリシーファイルの JAR ファイルへのバンドル
- ステップ 3d:JAR ファイルへの署名
- ステップ 3e:制限国のユーザと同じ環境の設定
- ステップ 3f:アクセス権ポリシーファイルで指定された免責機構を実装するプロバイダのインストール (免責機構を使用するアプリケーションのみ)
- ステップ 4:アプリケーションのテスト
- ステップ 5:米国政府による輸出承認の申請 (必要な場合)
- ステップ 6:アプリケーションの配備
免責機構を使用するアプリケーションに対する特殊コード要件
アプリケーションが関連付けられたアクセス権ポリシーファイルを (同じ JAR ファイル内に) 保持し、アクセス権ポリシーファイルで免責機構が指定されている場合、Cipher
getInstance
メソッドが呼び出されて Cipher がインスタンス化されると、JCE コードはインストール済みのプロバイダ内で指定された免責機構を実装するものを検索します。目的のプロバイダが見つかると、JCE は、プロバイダの実装に関連付けられた ExemptionMechanism API オブジェクトをインスタンス化してから、ExemptionMechanism オブジェクトをgetInstance
が返す Cipher と関連付けます。Cipher をインスタンス化した後、かつ初期化する前に (Cipher
init
メソッドを呼び出して)、コードから次の Cipher メソッドを呼び出す必要があります。public ExemptionMechanism getExemptionMechanism()この呼び出しにより、Cipher に関連付けられた ExemptionMechanism オブジェクトが返されます。次に、返された ExemptionMechanism に対して次のメソッドを実行して、免責機構の実装を初期化する必要があります。
public final void init(Key key)ここで指定する引数の型は、この後で Cipher
init
メソッドに指定する引数の型と同じにする必要があります。ExemptionMechanism の初期化が完了したら、通常と同じ方法で Cipher を初期化して使用できます。
アクセス権ポリシーファイル
実行時にアプリケーションが暗号化制限の一部またはすべてを「免責」されていると認識されるには、JAR ファイル内にアクセス権ポリシーファイルをバンドルする必要があります。アクセス権ポリシーファイルには、アプリケーションが保持する暗号化関連のアクセス権、およびそれを保持する条件 (存在する場合) を指定します。
注:アプリケーションにバンドルするアクセス権ポリシーファイルの名前は、
cryptoPerms
にする必要があります。免責されるアプリケーションにバンドルされるアクセス権ポリシーファイル内のアクセス権エントリの書式は、Java 2 SDK, v 1.4 とともにダウンロードされる管轄ポリシーファイルの書式と同じです。以下にその書式を示します。
permission <crypto permission class name>[ <alg_name> [[, <exemption mechanism name>][, <maxKeySize> [, <AlgorithmParameterSpec class name>, <parameters for constructing an AlgorithmParameterSpec object>]]]];管轄ポリシーファイルの書式の詳細は、「付録 D」を参照してください。
免責されるアプリケーションのアクセス権ポリシーファイル
アプリケーションの中には、制限を完全に解除可能なものもあります。通常、その種のアプリケーションにバンドルするアクセス権ポリシーファイルには、以下を含めるだけで十分です。
grant { // There are no restrictions to any algorithms. permission javax.crypto.CryptoAllPermission; };アプリケーションが 1 つ (またはいくつかの特定の) アルゴリズムだけを使用する場合、アクセス権ポリシーファイルには、CryptoAllPermission を付与するのではなく、そのアルゴリズムを明示的に記述します。たとえば、アプリケーションが Blowfish アルゴリズムだけを使用する場合、アクセス権ポリシーファイルですべてのアルゴリズムに CryptoAllPermission を付与する必要はありません。Blowfish アルゴリズムが使用される場合、暗号化制限が存在しないことを指定するだけで十分です。この場合、アクセス権ポリシーファイルは、次のようになります。
grant { permission javax.crypto.CryptoPermission "Blowfish"; };免責機構により免責されるアプリケーションのアクセス権ポリシーファイル
免責機構が導入されるためにアプリケーションが「免責される」と見なされる場合、アプリケーションにバンドルされるアクセス権ポリシーファイルに 1 つ以上の免責機構を指定する必要があります。実行時に、これらの免責機構のいずれかが機能していると、アプリケーションは免責されたものと見なされます。次のようなアクセス権エントリ内に、各免責機構を指定する必要があります。
// No algorithm restrictions if specified // exemption mechanism is enforced. permission javax.crypto.CryptoPermission *, "<ExemptionMechanismName>";ここで、
<ExemptionMechanismName>
には免責機構の名前を指定します。指定可能な免責機構の名前には、以下が含まれます。例として、鍵復元または鍵エスクローのいずれかが機能すると、アプリケーションが免責される場合を考えましょう。その場合、アクセス権ポリシーファイルには、以下が含まれます。
- KeyRecovery
- KeyEscrow
- KeyWeakening
grant { // No algorithm restrictions if KeyRecovery is enforced. permission javax.crypto.CryptoPermission *, "KeyRecovery"; // No algorithm restrictions if KeyEscrow is enforced. permission javax.crypto.CryptoPermission *, "KeyEscrow"; };注:免責機構を指定するアクセス権エントリには、最大キーサイズを指定してはなりません。許可される鍵のサイズは、実際にはインストールされた免責管轄ポリシーファイルにより決定されます。詳細は、次のセクションを参照してください。
バンドルされたアクセス権ポリシーファイルによる暗号化アクセス権への影響
実行時にアプリケーションが Cipher をインスタンス化し (
getInstance
メソッドを呼び出して)、かつそのアプリケーションが関連するアクセス権ポリシーファイルを保持する場合、JCE はアクセス権ポリシーファイルにgetInstance
の呼び出しで指定されたアルゴリズムに適用されるエントリが含まれるかどうかをチェックします。該当するエントリが含まれ、エントリが CryptoAllPermission を付与するか免責機構の実施を指定しない場合、このアルゴリズムには暗号化制限が存在しないことを意味します。アクセス権ポリシーファイルに
getInstance
の呼び出しで指定されたアルゴリズムに適用されるエントリが含まれ、かつエントリで免責機構の実施が指定されている場合、免責管轄ポリシーファイルがチェックされます。免責されるアクセス権が関連するアルゴリズムおよび免責機構のエントリを含み、そのエントリがアプリケーションに添付のアクセス権ポリシーファイル内のアクセス権により暗黙的に設定されている場合、および指定された免責機構の実装がいずれかの登録済みプロバイダから利用可能な場合、Cipher の最大キーサイズおよびアルゴリズムパラメータ値は、免責アクセス権エントリにより決定されます。アプリケーションにバンドルされるアクセス権ポリシーファイル内の関連するエントリに、暗黙的に設定された免責アクセス権が存在しない場合、またはいずれかの登録済みプロバイダから利用可能な、指定された免責機構の実装が存在しない場合、デフォルトの標準暗号化アクセス権のみがアプリケーションに付与されます。
暗号化プロバイダを使用するには、静的または動的にインストールおよび登録する必要があります。 Java 2 SDK, v 1.4 の JCE 用暗号化プロバイダのインストールおよび構成方法は、Java TM 2 プラットフォームの他のプロバイダと同様です。プロバイダのインストールおよび構成方法の詳細は、「JavaTM 暗号化アーキテクチャ API 仕様 & リファレンス」の「プロバイダのインストール」を参照してください。
「SunJCE」はあらかじめインストールされているため、インストールする必要はありません。他のプロバイダを使用する場合は、後述のセクションでプロバイダの登録方法を確認してください。
プロバイダのインストールには、プロバイダパッケージクラスのインストール、およびプロバイダの構成という 2 つのステップが含まれます。状況によっては、使用する前に、プロバイダのアクセス権の設定が必要な場合があります。
プロバイダクラスのインストール
最初に行う事柄は、プロバイダクラスを利用可能にして、要求時に検出できるようにすることです。プロバイダクラスは、署名付き JAR (Java ARchive) ファイル形式で提供されます。プロバイダクラスのインストール方法は 2 種類あります。
- プロバイダクラスを含む JAR ファイルを、「インストール型」または「バンドル型」の拡張機能としてインストールする方法
- プロバイダクラスを含む JAR ファイルをクラスパスに含める方法
プロバイダ 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/Java 2 SDK1.4.0
ディレクトリ (Solaris)、またはC:¥Java 2 SDK1.4.0
ディレクトリ (Win32) にインストールした場合、JAR ファイルを次のディレクトリにインストールする必要があります。/home/user1/Java 2 SDK1.4.0/jre/lib/ext [Solaris] C:¥Java 2 SDK1.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/Java 2 SDK1.4.0
(Solaris) またはC:¥Java 2 SDK1.4.0
(Win32) にインストールしている場合は、次のファイルを編集する必要があります。/home/user1/Java 2 SDK1.4.0/jre/lib/security/java.security [Solaris] C:¥Java 2 SDK1.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 には、プロバイダの「マスタークラス」を完全修飾名で指定します。この名前は、プロバイダベンダーから入手する必要があります。
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注:プロバイダは、動的に登録することもできます。このためには、Security
クラスのaddProvider
またはinsertProviderAt
のどちらかのメソッドを呼び出します。こうした登録は持続的なものではありません。また、実行できるのは次の権限を付与されたコードだけです。ここで、java.security.SecurityPermission "insertProvider.{name}"{name}
には実際のプロバイダ名を指定します。たとえば、プロバイダ名が「MyJCE」であり、このプロバイダを動的に登録するコードが/localWork
ディレクトリのMyApp.jar
ファイル内に存在する場合、アクセス権を付与するサンプルポリシーファイルのgrant
文は次のようになります。grant codeBase "file:/localWork/MyApp.jar" { permission java.security.SecurityPermission "insertProvider.MyJCE"; };プロバイダアクセス権の設定
JCE プロバイダがインストール型拡張機能ではない場合、セキュリティマネージャがインストール済みの状態で、JCE を使用するアプレットまたはアプリケーションを実行する際、常に JCE プロバイダに アクセス権を付与する必要があります。通常、アプレットの実行時にはセキュリティマネージャが常にインストールされます。アプリケーションの場合でも、アプリケーション自体のコード内またはコマンド行引数で指定することにより、セキュリティマネージャをインストールできます。デフォルトシステムのポリシー構成ファイルは、インストール型拡張機能にすべてのアクセス権を付与するため、インストール型拡張機能にアクセス権を設定する必要はありません。
ベンダーの提供する各プロバイダ用ドキュメントには、必須のアクセス権やそれを付与する方法が記載されています。たとえば、拡張機能がインストール型ではなく、セキュリティマネージャがインストールされている場合、プロバイダに次のアクセス権を付与する必要があります。
java.lang.RuntimePermission
(クラス保護ドメインを取得するため)。プロバイダは、自己完全性チェックの実行過程で、独自の保護ドメインの取得が必要になる場合があります。
java.security.SecurityPermission "putProviderProperty.{name}"
(プロバイダプロパティを設定するため、{name}
には実際のプロバイダ名を指定)たとえば、名前が「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"; };
「SunJCE」プロバイダは、Java 2 SDK, v 1.4 の
java.security.KeyStore
クラスの実装を独自に提供します。 この実装は、(トリプル DES に対しパスワードベース暗号化を使用して) Java 2 SDK, v 1.4 の「SUN」プロバイダが提供するキーストア実装よりも強力に非公開鍵を保護します。 Java 2 SDK, v 1.4 の配布は、世界規模およびバイナリおよびソース形式で行われるため、これより強力な暗号化機構は使用できません。「SunJCE」プロバイダのキーストア実装のメリットを享受するには、キーストア型に「JCEKS」を指定します。
「JKS」型 (Java 2 SDK の「SUN」プロバイダにより実装されたキーストア型の名前) のキーストアを、JCE キーストア型「JCEKS」にアップグレードできます。これは、キーストア内の非公開鍵エントリのパスワードを変更することにより実行します。
「SunJCE」の提供する (より) 強力な暗号化による鍵保護を、デフォルトキーストア内の「signkey」という名前の非公開鍵に適用する場合は、次のコマンドを入力します。このコマンドにより、旧パスワードおよび新規パスワードの指定が求められます。
keytool -keypasswd -alias signkey -storetype jceks同じコマンドを使用して、パスワードを以前の値に戻すこともできます。
keytool
とキーストア、およびその管理方法の詳細は、「セキュリティツール」を参照してください。
このセクションでは、Java 2 SDK, v 1.4 の JCE API の主な機能の使用方法について説明します。この API を実行する完全なサンプルプログラムは、このドキュメントの「付録 F」に掲載されています。
暗号化の使用
このセクションでは、鍵の生成、Cipher オブジェクトの作成と初期化、およびファイルの暗号化と暗号解読という一連の処理について説明します。この例全体で、データ暗号化規格 (DES) を使用します。
鍵の生成
DES を作成するには、DES 用の KeyGenerator をインスタンス化する必要があります。特定の DES 鍵生成実装について考慮する必要はないため、プロバイダは指定しません。KeyGenerator を初期化しないため、DES 鍵の作成にはシステム提供の乱数発生源が使用されます。
KeyGenerator keygen = KeyGenerator.getInstance("DES"); SecretKey desKey = keygen.generateKey();鍵を生成した後、同じ KeyGenerator を使用して他の鍵を再度作成できます。
Cipher の作成
次のステップは、Cipher インスタンスの作成です。これには、Cipher クラスのいずれかの
getInstance
ファクトリメソッドを使用します。次のコンポーネントを含む必須の変換名を、スラッシュ (/) で区切って指定する必要があります。
- アルゴリズム名
- モード (オプション)
- パディング方式 (オプション)
この例では、Electronic Codebook モードおよび PKCS #5 パディング方式で DES (データ暗号化規格) 暗号を作成します。特定の必須変換の実装について考慮する必要はないため、プロバイダは指定しません。
DES の標準アルゴリズム名は「DES」、Electronic Codebook モードの標準名は「ECB」、PKCS #5 パディング方式の標準名は「PKCS5Padding」です。
Cipher desCipher; // Create the cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");上で生成された
desKey
を使用して、Cipher オブジェクトを暗号化用に初期化します。// Initialize the cipher for encryption desCipher.init(Cipher.ENCRYPT_MODE, desKey); // Our cleartext byte[] cleartext = "This is just an example".getBytes(); // Encrypt the cleartext byte[] ciphertext = desCipher.doFinal(cleartext); // Initialize the same cipher for decryption desCipher.init(Cipher.DECRYPT_MODE, desKey); // Decrypt the ciphertext byte[] cleartext1 = desCipher.doFinal(ciphertext);
cleartext
とcleartext1
は、同一です。パスワードベース暗号化の使用
この例では、ユーザにパスワードを要求し、暗号化鍵をそのパスワードから導き出します。
java.lang.String
型のオブジェクトにパスワードを収集および格納するのは、適切と考えられます。ただし、注意すべき点があります。それは、String
型のオブジェクトは不変であるということです。このため、使用後にString
の内容を変更 (上書き) またはゼロにするようなメソッドは存在しません。この機能のために、String
オブジェクトは、ユーザパスワードなどセキュリティ上重要な情報の格納には適しません。セキュリティ関連の情報は、常に char 型の配列に収集および格納するようにしてください。この理由で、
javax.crypto.spec.PBEKeySpec
クラスは、パスワードを char 型の配列として受け取り、返します。次のメソッド例に、ユーザパスワードを char 型の配列として収集する方法を示します。
/** * Reads user password from given input stream. */ public char[] readPasswd(InputStream in) throws IOException { char[] lineBuffer; char[] buf; int i; buf = lineBuffer = new char[128]; int room = buf.length; int offset = 0; int c; loop: while (true) { switch (c = in.read()) { case -1: case '¥n': break loop; case '¥r': int c2 = in.read(); if ((c2 != '¥n') && (c2 != -1)) { if (!(in instanceof PushbackInputStream)) { in = new PushbackInputStream(in); } ((PushbackInputStream)in).unread(c2); } else break loop; default: if (--room < 0) { buf = new char[offset + 128]; room = buf.length - offset - 1; System.arraycopy(lineBuffer, 0, buf, 0, offset); Arrays.fill(lineBuffer, ' '); lineBuffer = buf; } buf[offset++] = (char) c; break; } } if (offset == 0) { return null; } char[] ret = new char[offset]; System.arraycopy(buf, 0, ret, 0, offset); Arrays.fill(buf, ' '); return ret; }PKCS #5 で定義された パスワードベースの暗号化 (PBE) を使用するには、salt と繰り返し処理の回数を指定する必要があります。 暗号解読時にも、暗号化時と同じ salt および繰り返し処理の回数を使用する必要があります。
PBEKeySpec pbeKeySpec; PBEParameterSpec pbeParamSpec; SecretKeyFactory keyFac; // Salt byte[] salt = { (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 }; // Iteration count int count = 20; // Create PBE parameter set pbeParamSpec = new PBEParameterSpec(salt, count); // Prompt user for encryption password. // Collect user password as char array (using the // "readPasswd" method from above), and convert // it into a SecretKey object, using a PBE key // factory. System.out.print("Enter encryption password: "); System.out.flush(); pbeKeySpec = new PBEKeySpec(readPasswd(System.in)); keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); // Create PBE Cipher Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); // Initialize PBE Cipher with key and parameters pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); // Our cleartext byte[] cleartext = "This is another example".getBytes(); // Encrypt the cleartext byte[] ciphertext = pbeCipher.doFinal(cleartext);鍵協定の使用
2 つおよび 3 つのパーティ間で Diffie-Hellman 鍵交換を実行するサンプルプログラムに関しては、「付録 F」を参照してください。
JCE API では、アルゴリズム、アルゴリズムモード、およびパディング方式の標準名のセットが必要とされ、使用されます。ここに記載の仕様は、標準名として以下の名前を確立するものです。また、「JavaTM 暗号化アーキテクチャ仕様 & リファレンス」の「付録 A」で定義された標準名のリストを補足する内容となっています。 アルゴリズム名の大文字と小文字が区別されることに留意してください。
場合によっては、命名規則を利用して、名前がリストに明示的に表示されないようにすることをお勧めします。こうしておけば、プロバイダ実装が異なっていても名前の整合性を確保しやすくなります。 <digest>、<encryption> のように角括弧で囲まれた項目は、特定のメッセージダイジェスト、暗号化アルゴリズム、その他の名前で置き換えられます。
暗号
アルゴリズム
Cipher
のインスタンスを要求する場合、次の名前を変換内の algorithm コンポーネントとして指定できます。
- AES - Advanced Encryption Standard として、NIST によって FIPS ドラフトに指定されました。 Joan Daemen、Vincent Rijmen 両氏による Rijndael アルゴリズムに基づいた 128 ビットのブロック暗号であり、128 ビット、192 ビット、256 ビットの鍵をサポートします。
- Blowfish - Bruce Schneier 氏の設計によるブロック暗号です。
- DES - データ暗号化規格です (FIPS PUB 46-2 で定義)。
- DESede - トリプル DES 暗号化です (DES-EDE)。
- PBEWith<digest>And<encryption> または PBEWith<prf>And<encryption> - パスワードベースの暗号化アルゴリズム (PKCS #5) です。指定されたメッセージダイジェスト (<digest>) または擬似ランダム関数 (<prf>) と暗号化アルゴリズム (<encryption>) を使用します。次に例を示します。
- PBEWithMD5AndDES - 1993 年 11 月、RSA Laboratories の「PKCS #5: Password-Based Encryption Standard」バージョン 1.5 に定義されたパスワードベースの暗号化アルゴリズムです。 このアルゴリズムでは、CBC は暗号モード、PKCS5Padding はパディング方式とされています。他の暗号モードやパディング方式で使用することはできません。
- PBEWithHmacSHA1AndDESede - 1999 年 3 月、RSA Laboratories の「PKCS #5: Password-Based Encryption Standard」バージョン 2.0 に定義されたパスワードベースの暗号化アルゴリズムです。
- RC2、RC4、および RC5 - RSA Data Security, Inc の Ron Rivest により開発された可変キーサイズ暗号化アルゴリズムです。
- RSA - PKCS #1 に定義されている RSA 暗号化アルゴリズムです。
モード
Cipher
のインスタンスを要求する場合、次の名前を変換内の mode コンポーネントとして指定できます。
- NONE - モードなし
- CBC - FIPS PUB 81 で定義された Cipher Block Chaining Mode
- CFB - FIPS PUB 81 で定義された Cipher Feedback Mode
- ECB - 米国商務省 National Institute of Standards and Technology (NIST) の Federal Information Processing Standard (FIPS) PUB 81「DES Modes of Operation」で定義された Electronic Codebook Mode (1980 年 12 月)
- OFB - FIPS PUB 81 で定義された Output Feedback Mode
- PCBC - Kerberos バージョン 4 で定義された Propagating Cipher Block Chaining
パディング
Cipher
のインスタンスを要求する場合、次の名前を変換内の padding コンポーネントとして指定できます。
- NoPadding - パディングなし
- OAEPWith<digest>And<mgf>Padding - PKCS #1 に定義されている Optimal Asymmetric Encryption Padding スキーマ。<digest> はメッセージダイジェスト、<mgf> はマスク生成関数で置き換える (例: OAEPWithMD5AndMGF1Padding)
- PKCS5Padding - 「PKCS #5: Password-Based Encryption Standard」バージョン 1.5 (RSA Laboratories、1993 年 11 月) で規定されたパディング方式
- SSL3Padding - SSL Protocol バージョン 3.0 のセクション 5.2.3.2 (CBC ブロック暗号) で規定されたパディング方式
block-ciphered struct { opaque content[SSLCompressed.length]; opaque MAC[CipherSpec.hash_size]; uint8 padding[GenericBlockCipher.padding_length]; uint8 padding_length; } GenericBlockCipher;GenericBlockCipher のインスタンスのサイズは、ブロック暗号のブロック長の倍数でなければなりません。
パディングは、パディング長 (常に存在) に影響を受けます。次の式が当てはまる場合を考えましょう。
sizeof(content) + sizeof(MAC) % block_length = 0,この場合、padding_length
が存在するため、パディング長を (block_length - 1) バイトにする必要があります。このため、パディング方式は PKCS5Padding に類似した (全く同一ではない) ものになります。パディング長は、パディング内で符号化され、1 〜 block_length の範囲の値になります。SSL スキーマでは、パディングのサイズは、常に存在する
padding_length
内で符号化されるため、0 〜 block_length-1 の範囲の値になります。「SunJCE」プロバイダは、このパディング機構をサポートしない点に留意してください。
KeyAgreement
KeyAgreement
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- DiffieHellman - 「PKCS #3: Diffie-Hellman Key-Agreement Standard」バージョン 1.4 (RSA Laboratories、1993 年 11 月) で定義された Diffie-Hellman 鍵協定
KeyGenerator
KeyGenerator
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- AES
- Blowfish
- DES
- DESede
- HmacMD5
- HmacSHA1
KeyPairGenerator
KeyPairGenerator
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- DiffieHellman
SecretKeyFactory
SecretKeyFactory
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- AES
- DES
- DESede
- PBEWith<digest>And<encryption> or PBEWith<prf>And<encryption> - パスワードベースの暗号化 PKCS #5 で使用される秘密鍵ファクトリ。<digest> はメッセージダイジェスト、<prf> は擬似ランダム関数、<encryption> は暗号化アルゴリズム。たとえば、 PBEWithMD5AndDES (PKCS #5, v 1.5)、PBEWithHmacSHA1AndDESede (PKCS #5, v 2.0) などがある。注: これらは各パスワード文字の下位 8 ビットのみを使用
KeyFactory
KeyFactory
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- DiffieHellman
AlgorithmParameterGenerator
AlgorithmParameterGenerator
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- DiffieHellman
AlgorithmParameters
AlgorithmParameters
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- Blowfish
- DES
- DESede
- DiffieHellman
- PBE
MAC
Mac
のインスタンスを要求する際、次のアルゴリズム名を指定できます。
- HmacMD5 - RFC 2104「HMAC: Keyed-Hashing for Message Authentication」 (1997 年 2 月) で定義された HMAC-MD5 キーハッシュアルゴリズム
- HmacSHA1 - RFC 2104「HMAC: Keyed-Hashing for Message Authentication」 (1997 年 2 月) で定義された HMAC-SHA1 キーハッシュアルゴリズム
- PBEWith<mac> - パスワードベースのメッセージ認証規格、PKCS #5 バージョン 2.0 で使用される MAC。<mac> はメッセージ認証コードのアルゴリズム名。例: PBEWithHmacSHA1
キーストア型
KeyStore
のインスタンスを要求する際、次の型を指定できます。
- JCEKS:「SunJCE」により実装された独自のキーストア型
免責機構
暗号化制限を「免責された」と見なされるアプリケーションに付属するアクセス権ポリシーファイル内で、次の免責機構名を指定できます。
- KeyEscrow: バックアップ暗号解読機能付き暗号化システム。このシステムを利用すると、特定条件下で、承認された人物 (ユーザ、組織役員、政府職員) が、特別なデータ復元鍵を保持する信頼できる 1 つ以上のパーティの提供する情報を利用して、暗号解読を実行できます。
- KeyRecovery: 暗号化データのロックに使用する秘密鍵を取得するメソッド。これは、災害発生時に、企業独自の暗号化情報への復旧アクセスを実行する手段として使用できます。
- KeyWeakening: 鍵の一部をエスクローまたは復元可能なメソッド
SunJCE プロバイダは、次のデフォルトキーサイズを使用します。
- KeyGenerator
- DES: 56 ビット
- トリプル DES: 112 ビット
- Blowfish: 56 ビット
- HmacMD5: 64 バイト
- HmacSHA1: 64 バイト
- KeyPairGenerator
- Diffie-Hellman: 1024 ビット
- AlgorithmParameterGenerator
- Diffie-Hellman: 1024 ビット
SunJCE プロバイダでは、次のクラスの初期化メソッドに渡すキーサイズに制限が課されます。
- KeyGenerator
制限 (アルゴリズム別):
- DES: キーサイズを
56
にする必要があります。
- トリプル DES: キーサイズを
112
または168
にする必要があります。注: キーサイズが
112
の場合には 2 つの中間鍵を保持するトリプル DES 鍵が、168
の場合には 3 つの中間鍵を保持するトリプル DES 鍵が、それぞれ生成されます。
- Blowfish: キーサイズを、
8
の倍数 (32
以上448
以下) にする必要があります。
- KeyPairGenerator
制限 (アルゴリズム別):
- Diffie-Hellman: キーサイズを、
64
の倍数 (512
以上1024
以下) にする必要があります。
- AlgorithmParameterGenerator
制限 (アルゴリズム別):
- Diffie-Hellman: キーサイズを、
64
の倍数 (512
以上1024
以下) にする必要があります。
JCE の管轄ポリシーファイルは、J2SE 形式のポリシーファイル (対応するアクセス権を指定する文を含む) で表されます。「デフォルトの Policy の実装とポリシーファイルの構文」に説明されているように、J2SE ポリシーファイルでは、指定されたコードソースのコードに付与するアクセス権を指定します。アクセス権は、システムリソースへのアクセスを表します。JCE の場合、「リソース」は暗号化アルゴリズムです。また、暗号化制限はすべてのコードに適用されるため、コードソースを指定する必要はありません。
管轄ポリシーファイルは、1 つ以上の「アクセス権エントリ」を含む、非常に基本的な「付与エントリ」で構成されます。
grant { <permission entries>; };以下に、管轄ポリシーファイルのアクセス権エントリの書式を示します。
permission <crypto permission class name>[ <alg_name> [[, <exemption mechanism name>][, <maxKeySize> [, <AlgorithmParameterSpec class name>, <parameters for constructing an AlgorithmParameterSpec object>]]]];以下に、「Blowfish」アルゴリズムを 64 ビットの最大キーサイズに制限する、管轄ポリシーファイルのサンプルを示します。
grant { permission javax.crypto.CryptoPermission "Blowfish", 64; . . .; };アクセス権エントリは、
permission
で始まります。上記のテンプレート内の<crypto permission class name>
には、javax.crypto.CryptoPermission
などの具体的なアクセス権クラス名を指定します。暗号化アクセス権クラスは、特定の環境下で特定のキーサイズを使用するアプリケーション/アプレットの機能に対応します。 暗号化アクセス権クラスには、CryptoPermission
およびCryptoAllPermission
の 2 つが存在します。特別なCryptoAllPermission
クラスは、暗号化関連のアクセス権すべてを表します。つまり、暗号化関連の制限はないことを示します。<alg_name> を指定する場合、"DES" や "RSA" など暗号化アルゴリズムの標準名を表す文字列 (「付録 A」を参照) を引用符で囲んで指定します。
<免責機構名> を指定する場合、免責機構を指す文字列を引用符で囲んで指定します。免責機構を実施すると、暗号化制限が緩和されます。使用可能な免責機構名には、「KeyRecovery」、「KeyEscrow」、および「KeyWeakening」が含まれます。
<maxKeySize> は、指定されたアルゴリズムで許容される最大キーサイズをビット単位で指定する整数です。
アルゴリズムによっては、キーサイズでアルゴリズムの強度を指定するだけでは不十分な場合があります。たとえば、"RC5" アルゴリズムの場合には、ラウンド数も考慮する必要があります。アルゴリズムの強度をキーサイズだけで表現するのでは不十分な場合、アクセス権エントリで AlgorithmParameterSpec クラス名 (
javax.crypto.spec.RC5ParameterSpec
など)、および指定された AlgorithmParameterSpec オブジェクトの構築用パラメータリストも指定する必要があります。アクセス権エントリの各項目は、指定された順序で記述する必要があります。各エントリはセミコロンで終わります。
識別子 (
grant
、permission
) では大文字と小文字は区別されませんが、<crypto permission class name>
、および値として引き渡される文字列では大文字と小文字が区別されます。注:「*」は、すべてのアクセス権エントリオプションでワイルドカードとして使用できます。たとえば、<alg_name> に「*」を指定すると、「すべてのアルゴリズム」という意味になります。
輸入管理制限により Java 2 SDK, v 1.4 に同梱されている管轄ポリシーファイルでは、制限付きの「強力」な暗号化機能が利用できます。
アルゴリズム
最大キーサイズ
DES
64
DESede
*
RC2
128
RC4
128
RC5
128
RSA
2048
* (その他すべて)
128
/* * Copyright 1997-2001 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. */ import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; import com.sun.crypto.provider.SunJCE; /** * This program executes the Diffie-Hellman key agreement protocol * between 2 parties: Alice and Bob. * * By default, preconfigured parameters (1024-bit prime modulus and base * generator used by SKIP) are used. * If this program is called with the "-gen" option, a new set of * parameters is created. */ public class DHKeyAgreement2 { private DHKeyAgreement2() {} public static void main(String argv[]) { try { String mode = "USE_SKIP_DH_PARAMS"; DHKeyAgreement2 keyAgree = new DHKeyAgreement2(); if (argv.length > 1) { keyAgree.usage(); throw new Exception("Wrong number of command options"); } else if (argv.length == 1) { if (!(argv[0].equals("-gen"))) { keyAgree.usage(); throw new Exception("Unrecognized flag: " + argv[0]); } mode = "GENERATE_DH_PARAMS"; } keyAgree.run(mode); } catch (Exception e) { System.err.println("Error: " + e); System.exit(1); } } private void run(String mode) throws Exception { DHParameterSpec dhSkipParamSpec; if (mode.equals("GENERATE_DH_PARAMS")) { // Some central authority creates new DH parameters System.out.println ("Creating Diffie-Hellman parameters (takes VERY long) ..."); AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH"); paramGen.init(512); AlgorithmParameters params = paramGen.generateParameters(); dhSkipParamSpec = (DHParameterSpec)params.getParameterSpec (DHParameterSpec.class); } else { // use some pre-generated, default DH parameters System.out.println("Using SKIP Diffie-Hellman parameters"); dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, skip1024Base); } /* * Alice creates her own DH key pair, using the DH parameters from * above */ System.out.println("ALICE: Generate DH keypair ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(dhSkipParamSpec); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); // Alice creates and initializes her DH KeyAgreement object System.out.println("ALICE: Initialization ..."); KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); aliceKeyAgree.init(aliceKpair.getPrivate()); // Alice encodes her public key, and sends it over to Bob. byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded(); /* * Let's turn over to Bob. Bob has received Alice's public key * in encoded format. * He instantiates a DH public key from the encoded key material. */ KeyFactory bobKeyFac = KeyFactory.getInstance("DH"); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec (alicePubKeyEnc); PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); /* * Bob gets the DH parameters associated with Alice's public key. * He must use the same parameters when he generates his own key * pair. */ DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); // Bob creates his own DH key pair System.out.println("BOB: Generate DH keypair ..."); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); bobKpairGen.initialize(dhParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair(); // Bob creates and initializes his DH KeyAgreement object System.out.println("BOB: Initialization ..."); KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); bobKeyAgree.init(bobKpair.getPrivate()); // Bob encodes his public key, and sends it over to Alice. byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); /* * Alice uses Bob's public key for the first (and only) phase * of her version of the DH * protocol. * Before she can do so, she has to instanticate a DH public key * from Bob's encoded key material. */ KeyFactory aliceKeyFac = KeyFactory.getInstance("DH"); x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc); PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec); System.out.println("ALICE: Execute PHASE1 ..."); aliceKeyAgree.doPhase(bobPubKey, true); /* * Bob uses Alice's public key for the first (and only) phase * of his version of the DH * protocol. */ System.out.println("BOB: Execute PHASE1 ..."); bobKeyAgree.doPhase(alicePubKey, true); /* * At this stage, both Alice and Bob have completed the DH key * agreement protocol. * Both generate the (same) shared secret. */ byte[] aliceSharedSecret = aliceKeyAgree.generateSecret(); int aliceLen = aliceSharedSecret.length; byte[] bobSharedSecret = new byte[aliceLen]; int bobLen; try { // show example of what happens if you // provide an output buffer that is too short bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 1); } catch (ShortBufferException e) { System.out.println(e.getMessage()); } // provide output buffer of required size bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 0); System.out.println("Alice secret: " + toHexString(aliceSharedSecret)); System.out.println("Bob secret: " + toHexString(bobSharedSecret)); if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret)) throw new Exception("Shared secrets differ"); System.out.println("Shared secrets are the same"); /* * Now let's return the shared secret as a SecretKey object * and use it for encryption. First, we generate SecretKeys for the * "DES" algorithm (based on the raw shared secret data) and * then we use DES in ECB mode * as the encryption algorithm. DES in ECB mode does not require any * parameters. * * Then we use DES in CBC mode, which requires an initialization * vector (IV) parameter. In CBC mode, you need to initialize the * Cipher object with an IV, which can be supplied using the * javax.crypto.spec.IvParameterSpec class. Note that you have to use * the same IV for encryption and decryption: If you use a different * IV for decryption than you used for encryption, decryption will * fail. * * Note: If you do not specify an IV when you initialize the * Cipher object for encryption, the underlying implementation * will generate a random one, which you have to retrieve using the * javax.crypto.Cipher.getParameters() method, which returns an * instance of java.security.AlgorithmParameters. You need to transfer * the contents of that object (e.g., in encoded format, obtained via * the AlgorithmParameters.getEncoded() method) to the party who will * do the decryption. When initializing the Cipher for decryption, * the (reinstantiated) AlgorithmParameters object must be passed to * the Cipher.init() method. */ System.out.println("Return shared secret as SecretKey object ..."); // Bob // Note: The call to bobKeyAgree.generateSecret above reset the key // agreement object, so we call doPhase again prior to another // generateSecret call bobKeyAgree.doPhase(alicePubKey, true); SecretKey bobDesKey = bobKeyAgree.generateSecret("DES"); // Alice // Note: The call to aliceKeyAgree.generateSecret above reset the key // agreement object, so we call doPhase again prior to another // generateSecret call aliceKeyAgree.doPhase(bobPubKey, true); SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES"); /* * Bob encrypts, using DES in ECB mode */ Cipher bobCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey); byte[] cleartext = "This is just an example".getBytes(); byte[] ciphertext = bobCipher.doFinal(cleartext); /* * Alice decrypts, using DES in ECB mode */ Cipher aliceCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey); byte[] recovered = aliceCipher.doFinal(ciphertext); if (!java.util.Arrays.equals(cleartext, recovered)) throw new Exception("DES in CBC mode recovered text is " + "different from cleartext"); System.out.println("DES in ECB mode recovered text is " + "same as cleartext"); /* * Bob encrypts, using DES in CBC mode */ bobCipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey); cleartext = "This is just an example".getBytes(); ciphertext = bobCipher.doFinal(cleartext); // Retrieve the parameter that was used, and transfer it to Alice in // encoded format byte[] encodedParams = bobCipher.getParameters().getEncoded(); /* * Alice decrypts, using DES in CBC mode */ // Instantiate AlgorithmParameters object from parameter encoding // obtained from Bob AlgorithmParameters params = AlgorithmParameters.getInstance("DES"); params.init(encodedParams); aliceCipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey, params); recovered = aliceCipher.doFinal(ciphertext); if (!java.util.Arrays.equals(cleartext, recovered)) throw new Exception("DES in CBC mode recovered text is " + "different from cleartext"); System.out.println("DES in CBC mode recovered text is " + "same as cleartext"); } /* * Converts a byte to hex digit and writes to the supplied buffer */ private void byte2hex(byte b, StringBuffer buf) { char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; int high = ((b & 0xf0) >> 4); int low = (b & 0x0f); buf.append(hexChars[high]); buf.append(hexChars[low]); } /* * Converts a byte array to hex string */ private String toHexString(byte[] block) { StringBuffer buf = new StringBuffer(); int len = block.length; for (int i = 0; i < len; i++) { byte2hex(block[i], buf); if (i < len-1) { buf.append(":"); } } return buf.toString(); } /* * Prints the usage of this test. */ private void usage() { System.err.print("DHKeyAgreement usage: "); System.err.println("[-gen]"); } // The 1024 bit Diffie-Hellman modulus values used by SKIP private static final byte skip1024ModulusBytes[] = { (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 }; // The SKIP 1024 bit modulus private static final BigInteger skip1024Modulus = new BigInteger(1, skip1024ModulusBytes); // The base used with the SKIP 1024 bit modulus private static final BigInteger skip1024Base = BigInteger.valueOf(2); }
/* * Copyright 1997-2001 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. */ import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; import com.sun.crypto.provider.SunJCE; /** * This program executes the Diffie-Hellman key agreement protocol * between 3 parties: Alice, Bob, and Carol. * * We use the same 1024-bit prime modulus and base generator that are * used by SKIP. */ public class DHKeyAgreement3 { private DHKeyAgreement3() {} public static void main(String argv[]) { try { DHKeyAgreement3 keyAgree = new DHKeyAgreement3(); keyAgree.run(); } catch (Exception e) { System.err.println("Error: " + e); System.exit(1); } } private void run() throws Exception { DHParameterSpec dhSkipParamSpec; System.out.println("Using SKIP Diffie-Hellman parameters"); dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, skip1024Base); // Alice creates her own DH key pair System.out.println("ALICE: Generate DH keypair ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(dhSkipParamSpec); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); // Bob creates his own DH key pair System.out.println("BOB: Generate DH keypair ..."); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); bobKpairGen.initialize(dhSkipParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair(); // Carol creates her own DH key pair System.out.println("CAROL: Generate DH keypair ..."); KeyPairGenerator carolKpairGen = KeyPairGenerator.getInstance("DH"); carolKpairGen.initialize(dhSkipParamSpec); KeyPair carolKpair = carolKpairGen.generateKeyPair(); // Alice initialize System.out.println("ALICE: Initialize ..."); KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); aliceKeyAgree.init(aliceKpair.getPrivate()); // Bob initialize System.out.println("BOB: Initialize ..."); KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); bobKeyAgree.init(bobKpair.getPrivate()); // Carol initialize System.out.println("CAROL: Initialize ..."); KeyAgreement carolKeyAgree = KeyAgreement.getInstance("DH"); carolKeyAgree.init(carolKpair.getPrivate()); // Alice uses Carol's public key Key ac = aliceKeyAgree.doPhase(carolKpair.getPublic(), false); // Bob uses Alice's public key Key ba = bobKeyAgree.doPhase(aliceKpair.getPublic(), false); // Carol uses Bob's public key Key cb = carolKeyAgree.doPhase(bobKpair.getPublic(), false); // Alice uses Carol's result from above aliceKeyAgree.doPhase(cb, true); // Bob uses Alice's result from above bobKeyAgree.doPhase(ac, true); // Carol uses Bob's result from above carolKeyAgree.doPhase(ba, true); // Alice, Bob and Carol compute their secrets byte[] aliceSharedSecret = aliceKeyAgree.generateSecret(); System.out.println("Alice secret: " + toHexString(aliceSharedSecret)); byte[] bobSharedSecret = bobKeyAgree.generateSecret(); System.out.println("Bob secret: " + toHexString(bobSharedSecret)); byte[] carolSharedSecret = carolKeyAgree.generateSecret(); System.out.println("Carol secret: " + toHexString(carolSharedSecret)); // Compare Alice and Bob if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret)) throw new Exception("Alice and Bob differ"); System.out.println("Alice and Bob are the same"); // Compare Bob and Carol if (!java.util.Arrays.equals(bobSharedSecret, carolSharedSecret)) throw new Exception("Bob and Carol differ"); System.out.println("Bob and Carol are the same"); } /* * Converts a byte to hex digit and writes to the supplied buffer */ private void byte2hex(byte b, StringBuffer buf) { char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; int high = ((b & 0xf0) >> 4); int low = (b & 0x0f); buf.append(hexChars[high]); buf.append(hexChars[low]); } /* * Converts a byte array to hex string */ private String toHexString(byte[] block) { StringBuffer buf = new StringBuffer(); int len = block.length; for (int i = 0; i < len; i++) { byte2hex(block[i], buf); if (i < len-1) { buf.append(":"); } } return buf.toString(); } /* * Prints the usage of this test. */ private void usage() { System.err.print("DHKeyAgreement usage: "); System.err.println("[-gen]"); } // The 1024 bit Diffie-Hellman modulus values used by SKIP private static final byte skip1024ModulusBytes[] = { (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 }; // The SKIP 1024 bit modulus private static final BigInteger skip1024Modulus = new BigInteger(1, skip1024ModulusBytes); // The base used with the SKIP 1024 bit modulus private static final BigInteger skip1024Base = BigInteger.valueOf(2); }
/* * Copyright 1997-2001 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. */ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; /** * This program generates a Blowfish key, retrieves its raw bytes, and * then reinstantiates a Blowfish key from the key bytes. * The reinstantiated key is used to initialize a Blowfish cipher for * encryption. */ public class BlowfishKey { public static void main(String[] args) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("Blowfish"); SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish"); Cipher cipher = Cipher.getInstance("Blowfish"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal("This is just an example".getBytes()); } }
/* * Copyright 1997-2001 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. */ import java.security.*; import javax.crypto.*; /** * This program demonstrates how to generate a secret-key object for * HMAC-MD5, and initialize an HMAC-MD5 object with it. */ public class initMac { public static void main(String[] args) throws Exception { // Generate secret key for HMAC-MD5 KeyGenerator kg = KeyGenerator.getInstance("HmacMD5"); SecretKey sk = kg.generateKey(); // Get instance of Mac object implementing HMAC-MD5, and // initialize it with the above secret key Mac mac = Mac.getInstance("HmacMD5"); mac.init(sk); byte[] result = mac.doFinal("Hi There".getBytes()); } }
Copyright ©1996-2002 Sun Microsystems, Inc.All Rights Reserved. コメントの送付先:java-security@java.sun.com。 |
Java ソフトウェア |