2011-01-04 25 views
10

私のプログラムのどこかで使用するために暗号化を試みる簡単なクラスがあります。"最後のブロックが不完全な暗号化"を扱う方法

import java.security.SecureRandom; 
import javax.crypto.Cipher; 
import javax.crypto.KeyGenerator; 
import javax.crypto.spec.SecretKeySpec; 

public final class StupidSimpleEncrypter 
{ 
    public static String encrypt(String key, String plaintext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] plaintextBytes = plaintext.getBytes(); 
     byte[] ciphertextBytes = encrypt(keyBytes, plaintextBytes); 
     return new String(ciphertextBytes); 
    } 

    public static byte[] encrypt(byte[] key, byte[] plaintext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, spec); 
      return cipher.doFinal(plaintext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    public static String decrypt(String key, String ciphertext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] ciphertextBytes = ciphertext.getBytes(); 
     byte[] plaintextBytes = decrypt(keyBytes, ciphertextBytes); 
     return new String(plaintextBytes); 
    } 

    public static byte[] decrypt(byte[] key, byte[] ciphertext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.DECRYPT_MODE, spec); 
      return cipher.doFinal(ciphertext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    private static byte[] getRawKey(byte[] key) 
    { 
     try 
     { 
      KeyGenerator gen = KeyGenerator.getInstance("AES"); 
      SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); 
      rand.setSeed(key); 
      gen.init(256, rand); 
      return gen.generateKey().getEncoded(); 
     } 
     catch(Exception e) 
     { 
      return null; 
     } 
    } 
} 

強調表示された行でjavax.crypto.IllegalBlockSizeException「復号化で不完全な最後のブロックを」スローされ、正しく暗号化を処理するようだが、それほど復号化するとき。ここでは、スタックトレースです:私は試してみて、これを理解するために私の机のに対して私の頭を叩いての良い量を行っている

 
Location:com.xxxxxx.android.StupidSimpleEncrypter.decrypt ln:49 
last block incomplete in decryption 
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption 
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1090) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:44) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:34) 

が、私は全然どこに行くならば、それは別の例外なってしまいます。私は検索することで多くを見つけることもできないようです。

私には何が欠けていますか?助けていただければ幸いです。

答えて

19

これがIllegalBlockSizeExceptionの問題であるかどうかわかりませんが、特に文字エンコーディングを指定しないで、Stringとしてキーをエンコードしないでください。これを行うには、特定のバイトのみを文字にマッピングする文字エンコーディングではなく、「バイナリ」データをエンコードするように設計されたBase-64のようなものを使用します。

キーには、通常、デフォルトのプラットフォームエンコーディングの文字に対応しないバイト値が含まれます。その場合、Stringを作成すると、バイトが "置換文字"、U + FFFD(�)に変換され、正しい値が失われて失われます。

この破損したキーを後で使用すると、平文の復元が妨げられます。 IllegalBlockSizeExceptionが発生する可能性がありますが、無効なパディング例外が発生する可能性が高いと思われます。

もう1つの可能性は、ソースプラットフォームとターゲットプラットフォームの文字エンコーディングが異なり、暗号テキストの「デコード」が少なすぎるということです。たとえば、ソースエンコーディングはUTF-8で、入力の2バイトを1文字として解釈し、ターゲットエンコーディングはISO-Latin-1(文字を1バイトとして表す)です。

+0

これは私の問題の根本的な原因だったが、それはペイロードとしませんキーとありました私の場合、常に標準的な文字列になります。私はそれを文字列暗号化メソッドで変更しました。返される暗号文は、バイト配列からBase64にエンコードされ、復号化メソッドでは、暗号化文字列はBase64でバイト配列にデコードされます。つまり、データが失われなくなり、コードが正常に機能します。 –

+0

暗号化されたString自体と同じことです。これはbyte []として格納する必要があります。 – user1666456

6

getKeySpec()方法が間違っています。暗号化と復号化の両方の方向で新しいランダムキーを生成します。両方に同じキーを使用する必要があります。あなたはそのメソッドに引数keyを使わないことに気付かれたはずです。

+1

これは問題の一部でした。ありがとう。 –

1

バイト配列で作業している場合、同じバッファサイズを使用する必要があります。たとえば、サイズが1000の場合は、バイトサイズがあります。暗号化後、このサイズは2000になります(これらは実際の値ではありません)。 bufferを使用して暗号化されたファイルをすべて読み取る場合、buffersize to 2000を選択する必要があります。この方法で同じ問題を解決しました。

0

私にとっては、復号化するデータが破損している(1文字が欠けている)ときに、この問題が発生します。 WiFi経由でデータを送信したことが原因である可能性があります。

4

"悪いベース64"と "最後のブロック不完全"の間で私は髪を引き裂いていました...それはもちろん、非対称です。ここで私はうまくいけば、私が説明しようとした場合よりも、議論に多くを追加したことをやってしまったかの本質だ:

public String crypto(SecretKey key, String inString, boolean decrypt){ 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    byte[] inputByte = inString.getBytes("UTF-8"); 
    if (decrypt){ 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     return new String (cipher.doFinal(Base64.decode(inputByte, Base64.DEFAULT))); 
    } else { 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     return new String (Base64.encode(cipher.doFinal(inputByte), Base64.DEFAULT)); 
    } 
} 
関連する問題