2010-12-30 2 views
5

次のコードがあります。復号化エラー:パッドブロックが壊れています

byte[] input = etInput.getText().toString().getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
     0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 

    String strLength = new String(cipherText,"US-ASCII"); 
    byte[] byteCiphterText = strLength.getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(byteCiphterText.length)); 

    etOutput.setText(new String(cipherText,"US-ASCII")); 

    cipherText = etOutput.getText().toString().getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(cipherText.length)); 

    ptLength += cipher.doFinal(plainText, ptLength); 
    Log.e("Decrypt", new String(plainText)); 
    Log.e("Decrypt", Integer.toString(ptLength)); 

これは完全に機能します。 しかし、一度それをクラスに変換します。常にこの行のエラーに当たった。

ptLength += cipher.doFinal(plainText, ptLength); 

Error:Pad block corrupted 

私はチェックしており、両方のコードがまったく同じです。変換文字列でbyteに渡された値でさえ、上記のコードと変わりません。コードの何が悪いと思いますか?

public String Encrypt(String strPlainText) throws Exception, NoSuchProviderException, 
     NoSuchPaddingException { 
    byte[] input = strPlainText.getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    return new String(cipherText, "US-ASCII"); 
} 

public String Decrypt(String strCipherText) throws Exception, 
     NoSuchProviderException, NoSuchPaddingException { 
    byte[] cipherText = strCipherText.getBytes("US-ASCII"); 
    int ctLength = cipherText.length; 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // decryption pass 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 
    ptLength += cipher.doFinal(plainText, ptLength); 

    return new String(plainText); 
} 
+0

を一度に1ブロック、ECBモードを使用しないでください。これまで –

+0

代わりにCBCを使用してください – Codefor

答えて

1

PKCS7パディングを指定しました。 Stringオブジェクトに格納するとパディングが保持されますか?あなたの文字列オブジェクトは、暗号によって出力されたバイトと1:1で一致しますか?一般に、Stringは、暗号出力などのバイナリデータを渡すのには不適切です。

+0

あなたの質問は混乱します。あなたのStringオブジェクトに格納されているときにパディングが保存されていますか? - >どうすれば確認できますか?あなたの文字列オブジェクトは、暗号によって出力されるバイトと1対1で一致しますか? - >暗号化のために入力する文字列は、バイト出力と一致する必要がありますか?一般に、Stringは暗号出力などのバイナリデータを渡すのには不適切です.->なぜそうだと思いますか?暗号文を取得したら、ASCIIで変換しました。私はバイト配列に変換して、 。 – kangalert

+0

文字列のバイトが最初のbyte []配列と一致するかどうかを確認できます。私は彼らが真剣に疑う。 "US-ASCII"!=バイナリデータ。 –

0

あなたのケースでは、暗号はパディングを使用します。つまり、入力データは、事前定義されたサイズ(パディングアルゴリズムに依存します)でブロックにパディング/丸められます。暗号化に500バイトを指定したとしましょう。パディングブロックサイズは16バイトなので、暗号化されたデータのサイズは512バイト(32ブロック)になります.12バイトはパディングされます。

あなたのコードでは、例外が発生する入力配列と同じサイズの暗号化配列が必要です。パディングを念頭に置いて出力配列のサイズを再計算する必要があります。

+0

暗号化された文字列は、パディングブロックと同じサイズでなければならないということですか? – kangalert

+0

いいえ、文字列(実際には文字列ではなくバイト[]配列)をパディングブロックサイズに丸めてください – barmaley

3

ヤン・ラミン(Yann Ramin)が述べたように、文字列の使用は暗号の入出力に失敗します。これは

  • が定義または使用エンコーディングで奇妙な場所にマッピングされていない値を含むことができる0x00で
  • を含むことができるバイナリデータである

使用無地バイト[]あなたの最初の例のように、またはバイト[]を16進符号化またはbase64符号化する。

// this is a quick example - dont use sun.misc inproduction 
// - go for some open source implementation 
String encryptedString = new sun.misc.BASE64Encoder.encodeBuffer(encryptedBytes); 

この文字列は安全に転送し、バイトにマップすることができます。

EDIT

おそらく長さの問題に対処するための最も安全な方法は、常に実装(私見)ストリーミング使用することです:あなたは絶対に確信している、またはだけで作業している場合を除き

static public byte[] decrypt(Cipher cipher, SecretKey key, byte[]... bytes) 
     throws GeneralSecurityException, IOException { 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    for (int i = 0; i < bytes.length; i++) { 
     bos.write(cipher.update(bytes[i])); 
    } 
    bos.write(cipher.doFinal()); 
    return bos.toByteArray(); 
} 
+1

ありがとうございます。しかし、私はbos.write(cipher.update(bytes [i]))にエラーがあります。 cipher.updateはバイト配列のみを受け入れます。 – kangalert

+0

@kangalertメソッドのシグネチャに気付きましたか? bytes [i] **は**バイト配列です。たぶんあなたはあなたのニーズに署名を適応させる、配列またはリストの配列を使用する... – mtraut

関連する問題