6. Cipherクラス(2)
2006.08.24 株式会社四次元データ 里見玲爾
- 6.1. テキストの暗号化、復号化
- 6.2. 鍵のラップ、アンラップ
前章に引き続き、Cipherクラスについて解説します。この章では、暗号化や復号化、ラップやアンラップを行うメソッドについて解説します。
6.1. テキストの暗号化、復号化
暗号化や復号化は、単一ステップと複数ステップのどちらかを使って行います。 短いテキストなどは単一ステップ、入力の長さが不明のときデータが長くて複数の配列に渡っている場合などは複数ステップが便利です。 3章の例では単一ステップを用いました。単一ステップの場合は下のdoFinalメソッドを使います。
・単一ステップ byte[] doFinal(byte[] input); byte[] doFinal(byte[] input, int inputOffset, int inputLen); int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output); int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset);
inputは入力データ、inputOffsetは入力を開始するinputのオフセット、inputLenは入力の長さ、
outputは出力を格納するバッファ、outputOffsetは格納を開始するoutputのオフセットで、出力先を指定したときの
返り値は格納したバイト数となっています。
暗号化するときはinputに暗号化するテキストのバイトデータを指定してoutputには暗号化を行った結果を格納するバッファを指定し、
復号化のときはinputに暗号テキストのバイトデータを指定してoutputに復号化を行った結果を
格納するバッファを指定します。
複数ステップの場合は以下のupdateメソッドを実行し、最後のステップでdoFinalメソッドを実行します。
・複数ステップ byte[] update(byte[] input); byte[] update(byte[] input, int inputOffset, int inputLen); int update(byte[] input, int inputOffset, int inputLen, byte[] output); int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset); int update(ByteBuffer input, ByteBuffer output);
引数に関しては上のdoFinalと同じです。5番目のメソッドの引数はjava.nio.ByteBufferです。 また、複数ステップの最後には必ずdoFinalメソッドを実行する必要があります。 この最後のdoFinalには、単一ステップで使用できるdoFinalメソッドを実行する他に、 次のdoFinalメソッドも実行できます。
byte[] doFinal(); int doFinal(byte[] output, int outputOffset);
CipherオブジェクトはdoFinalメソッドを実行すると初期化した状態に戻ります。
特に複数ステップではupdateメソッドを実行する過程でCipherオブジェクトに情報を蓄積しますが、
最後のステップでdoFinalメソッドを実行すると蓄積していた情報はすべてリセットされ、
また新しく暗号化や復号化を行うことができます(どちらを行えるかは初期化の際の暗号化のモードによる)。
またブロック暗号の場合、updateメソッドでは必ずブロック長の倍数で暗号化を区切るため、パディングはdoFinalメソッドでのみ行われます。
3章の例で行った暗号化と復号化を複数ステップで行うコード例を以下に示します。
(略) //暗号化処理 byte[] cleartext = "Techscore-J2SE-JCE".getBytes(); Cipher cipher = Cipher.getInstance("DES"); KeyGenerator keyGen = KeyGenerator.getInstance("DES"); keyGen.init(56); SecretKey key = keyGen.generateKey(); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] output = cipher.update(input); byte[] output2 = cipher.doFinal(); System.out.println("暗号化した文は" + new String(output) + new String(output2)); //復号化処理 cipher.init(Cipher.DECRYPT_MODE, key); byte[] buff = cipher.update(output); byte[] buff2 = cipher.update(output2); byte[] buff3 = cipher.doFinal(); System.out.println("復号化した文は" + new String(output) + new String(output2)); (略)
複数ステップで行う復号化では入力の数より多くバッファを用意する必要があります。
6.2. 鍵のラップ、アンラップ
鍵をラップすることで、鍵の情報が第3者に渡らないようにできます。鍵のラップは以下のwrapメソッドで行います。
byte[] wrap(Key key);
鍵のアンラップは以下のunwrapメソッドで行います。 鍵をラップするには鍵を引数に渡すだけでよいのに対して、鍵のアンラップにはいくつかの引数が必要になります。
Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType);
wrappedKeyはラップされた鍵のデータ、wrappedKeyAlgorithmはラップの際に使用したアルゴリズム、 wrappedKeyTypeは非公開鍵か公開鍵か共有鍵かを指定するものです。指定にはCipherクラスのクラス変数である、 PRIVATE_KEY、PUBLIC_KEY、SECRET_KEYの3つのどれかを使います。
6.1で使用したkeyオブジェクトにラップ、アンラップ処理を行う例を以下に示します。
(略) //ラップ処理 Cipher cipher = Cipher.getInstance("DES"); KeyGenerator keyGen = KeyGenerator.getInstance("DES"); keyGen.init(56); SecretKey wKey = keyGen.generateKey(); cipher.init(Cipher.WRAP_MODE, wKey); byte[] wrapped = cipher.wrap(key); System.out.println("ラップした鍵は" + new String(wrapped)); //アンラップ処理 cipher.init(Cipher.UNWRAP_MODE, wKey); SecretKey unwrapped = (SecretKey)cipher.unwrap(wrapped, "DES", Cipher.SECRET_KEY); System.out.println("アンラップした鍵は" + unwrapped); System.out.println("元の鍵は" + key);
wkeyはラップする際に用いる鍵オブジェクトです。
次の章ではパスワードベース暗号化方式の例を紹介します。