- PR -

復号化時のdoFinalについて

投稿者投稿内容
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2003-10-05 01:52
パスワードベースで暗号化した文を復号化しようとしているのですが、最後のdoFinalのところでエラーが出てしまいます。
具体的には以下のページの「パスワードベース暗号化の使用」を箇所を参考にして試しています。

http://java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jce/JCERefGuide.html#PBEEx

これを元に暗号化は正常に出来ているようなのですが、この後以下のように復号化を試みたところプログラムを走らせた時点で「Input length (with padding) not multiple of 8 bytes」というエラーが出てしまいます。

------------------------------------------------------
// Decript
pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
byte[] decriptedText = pbeCipher.doFinal(ciphertext);
------------------------------------------------------

これは恐らく、doFinal(byte[] input) ではなく、doFinal(byte[] input, int inputOffset, int inputLen)を使うべきなのだと考えたのですが、ここで最後の引数のinputLenに何の長さを入れるべきなのかが分かりません。Java APIによると「入力長」と書いてあるので、ciphertext.lengthで長さを求めてこれを引数に与えてみたのですが、うまくいきませんでした。(ちなみに、ciphertextは上記のページにある変数名でbyte[]型です)ここがうまくいけば復号化できると思うのですが・・・
どなたか分かる方いらっしゃいますでしょうか?
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2003-10-05 02:23
fuzukiさんこんにちは。

「これを元に暗号化は正常に出来ているようなのですが、…」と
ありますが、どの様にして正常なことを確認されたでしょうか?

エラーメッセージによれば、パディングが8の倍数でないと
言われているようなので、パディングの指定をされたのだと
思いますが、パディング処理に間違いがあったのではない
でしょうか?

参考(既にご覧になったとは思いますが。)
http://java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jce/JCERefGuide.html#AppA
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2003-10-05 13:38
Kissingerさんこんにちは。いつもありがとうございます。

引用:

「これを元に暗号化は正常に出来ているようなのですが、…」と
ありますが、どの様にして正常なことを確認されたでしょうか?



これはENCRYPTモードでdoFinalをした後に生成されるbyte[]の中身を単に標準出力に出力してみて、何かしらの暗号化された文字が入っているので、それをもって「暗号化はされているようだ」と思い込んでいたのですが、これでは「正常に」行われているのかは分かりませんね。いい加減ですみませんでした。

引用:

エラーメッセージによれば、パディングが8の倍数でないと
言われているようなので、パディングの指定をされたのだと
思いますが、パディング処理に間違いがあったのではない
でしょうか?



アルゴリズムを指定している箇所ではSunの例のページの通り

Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

というようにしていますので、パディングは指定していません。試しにPBEWithMD5AndDES/NONE/NoPaddingとしたら、そんなプロバイダはありませんといわれてしまいました。例のページを参考にするとalgorithm/mode/paddingという指定でいいと思うのですが。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2003-10-06 00:41
fuzukiさんお待たせしました。(今日も出勤で…。)

サンプルコードの後ろに、fuzukiさんのコード2行入れて、
結果を printlnしてみましたが、エラーにならず、
ちゃんと平文が出力できましたよ。
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2003-10-06 13:34
Kissingerさんこんにちは。

実は実際には標準入力から入力したテキストを暗号化するように書き換えていて、その中でwhile文を使っていたのですが、Sunのページに載っている暗号化の部分をここに組み込む時に単純なミスをしていました。
Kissingerさんのご返事を読んだ後に普通にやってみたところうまくいきました。

お忙しいところどうもありがとうございました。
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2003-10-06 15:05
すみません。解決したと思ったら解決していませんでした・・・

本当の原因は、byte[]に変換された暗号化された文を一度Stringに直して、それをまたbyte[]に変換して復号化するところにありました。
Stringに一度変換する理由は、クライアントとサーバでこの文を送受信する必要があるからです。

----------------------------------------------------------------------
byte[] ciphertext = pbeCipher.doFinal(cleartext); // ここはSunのページにある暗号化の最後の部分

ByteArrayOutputStream baos = new ByteArrayOutputStream(); //ここからbyte[]をStringに変換する処理
baos1.write(ciphertext,0,ciphertext.length);
String sendData = baos.toString();
baos.close(); // String変換終了

byte[] receiveText = sendData.getBytes(); // ここでStringをbyte[]に変換

// 復号化
pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
byte[] decriptedText = pbeCipher.doFinal(receiveText); // ここでエラー
----------------------------------------------------------------------

エラーの内容は最初の投稿と同じ「Input length (with padding) not multiple of 8 bytes」です。
最後の、エラーが出る箇所で

byte[] decriptedText = pbeCipher.doFinal(baos.toByteArray());

などとしてStringに変換される前のbyte[]を与えてやると正常に変換されます。
ただ、このエラーが出る方法でも、なぜか特定の文字の場合はエラーにならずに正常に復号化されて元の文字が出力されます。例えば"aa"などです。また、ある文字の場合は何も出力されなかったりします。

[ メッセージ編集済み 編集者: fuzuki 編集日時 2003-10-06 15:05 ]
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2003-10-06 21:47
byte[] → String の処理を間違っているのではありませんか?

細かく見てはいませんが ByteArrayOutputStream を使用せずに
new String(byte[] bytes) などを使って
byte[] → String と変換した方がわかりやすい気が・・・。
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-10-06 23:14
byte[] → String の処理が間違っています。
ByteArrayOutputStream#toString()やnew String(byte[])は,
プラットホームのデフォルトエンコーディングを使ってバイト配列から
Stringオブジェクトを作成します。

しかし、doFinal()で得られたバイト配列は、文字コードの配列ではありません。
結果、該当する文字がないバイトは'?'になってしまい、複合に失敗します。

バイト配列をStringにダンプする簡単なメソッドは以下のようになります。
コード:
public static String dump(byte[] bytes, int radix) {
    return new java.math.BigInteger(1, bytes).toString(radix);
}


スキルアップ/キャリアアップ(JOB@IT)