2011-01-04 4 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 (& # xFFFD;)로 변환되어 올바른 값이 영구적으로 손실됩니다.

나중에 키가 손상된 String 표현을 사용하면 일반 텍스트가 복구되지 않습니다. IllegalBlockSizeException이 발생할 수 있지만 유효하지 않은 패딩 예외가있을 가능성이 큽니다.

또 다른 가능성은 소스 플랫폼과 대상 플랫폼 문자 인코딩이 다르며 암호 텍스트를 "디코딩"하면 너무 적은 바이트가되는 것입니다. 예를 들어 소스 인코딩은 UTF-8이며 입력의 두 바이트를 단일 문자로 해석하지만 대상 인코딩은 문자를 단일 바이트로 나타내는 ISO-Latin-1입니다.

+0

이 내 문제의 근본 원인이었다,하지만 그것은 페이로드이고있는하지 않습니다 키 내 경우에는 항상 표준 문자열이되어야합니다.나는 문자열 암호화 방법에서 그것을 바꿨다. 반환 된 암호문은 바이트 배열에서 Base64로 인코딩되고 해독 방법에서는 암호문 문자열이 Base64로 바뀌어 바이트 배열로 바뀐다. 즉, 데이터가 더 이상 손실되지 않고 코드가 작동합니다. –

+0

암호화 된 String 자체와 동일합니다. byte []로 저장해야합니다. – user1666456

6

getKeySpec() 방법이 잘못되었습니다. 암호화 및 암호 해독 방향에 대해 새로운 무작위 키를 생성합니다. 두 가지 모두에 대해 동일한 키를 사용해야합니다. 해당 메서드에 대해 key 인수를 사용하지 않는 것으로 나타났습니다.

+1

이것은 문제의 일부 였고, 눈치 채는 데 다소 시간이 걸렸습니다. 감사. –

1

바이트 배열에서 작업하는 경우 동일한 버퍼 크기를 사용해야합니다. 예를 들어 크기가 1000 인 크기는 bytearray입니다. 암호화 후이 크기는 2000입니다 (실제 값이 아님). 버퍼를 사용하여 암호화 된 파일을 모두 읽는다면 buffersize를 2000으로 선택해야합니다.이 방법으로 같은 문제가 해결되었습니다.

0

암호 해독 된 데이터가 손상된 경우 (1 문자 누락)이 문제가 발생합니다. Wi-Fi를 통해 데이터를 전송했기 때문일 수 있습니다.

4

나는 "bad base 64"와 "last block incomplete"오류 사이에 내 머리카락을 찢어 내고있었습니다 ... 물론 비대칭입니다. 여기에 내가 잘하면 내가 설명하려고 시도하는 것보다 토론을 더 추가하는 그 일을 결국 어떻게 본질이다 :

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)); 
    } 
} 
관련 문제