2012-11-27 3 views
1

AES를 사용하여 암호화/암호 해독을 수행하고 있습니다. 텍스트를 암호화하고 나중에 별도로 해독하려고합니다.BadPaddingException Java에서 AES를 사용하여 별도로 암호 해독 할 때

내 AESEncrypt.java은 다음과 같습니다

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import java.security.spec.KeySpec; 
import org.apache.commons.codec.binary.Base64; 

public class AESEncrypt { 
    private static final byte[] SALT = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03}; 
    private static final int ITERATION_COUNT = 65536; 
    private static final int KEY_LENGTH = 256; 
    private Cipher eCipher; 
    private Cipher dCipher; 

    AESEncrypt(String passPhrase) throws Exception { 
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH); 
     SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec); 
     SecretKey secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES"); 

     eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     eCipher.init(Cipher.ENCRYPT_MODE, secretKey); 

     dCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     byte[] iv = eCipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); 
     dCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); 
    } 

    public String encrypt(String encrypt) throws Exception { 
     byte[] bytes = encrypt.getBytes("UTF8"); 
     byte[] encrypted = encrypt(bytes); 
     return new String(Base64.encodeBase64(encrypted)); 
    } 

    public byte[] encrypt(byte[] plain) throws Exception { 
     return eCipher.doFinal(plain); 
    } 

    public static void main(String[] args) throws Exception { 
     String passphrase = "PASSWORDPASSPHRASE"; 
     String password = "password123";  
     AESEncrypt aesEncrypt = new AESEncrypt(passphrase); 
     String encryptedPassword = aesEncrypt.encrypt(password); 
     System.out.println("encryptedPassword = " + encryptedPassword); 
    } 
} 

위의 AESEncrypt 코드를 실행 한 후, 그 결과는 다음과 같습니다 내 AESDecrypt.java 지금 그래서

encryptedPassword = aUkbhjFebZ9VjJ44yptlBA== 

, 내가 것을 사용하고 encryptedPassword 암호 해독 할 문자열 :

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import java.security.spec.KeySpec; 
import org.apache.commons.codec.binary.Base64; 

public class AESDecrypt { 
    private static final byte[] SALT = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03}; 
    private static final int ITERATION_COUNT = 65536; 
    private static final int KEY_LENGTH = 256; 
    private Cipher eCipher; 
    private Cipher dCipher; 

    AESDecrypt(String passPhrase) throws Exception { 
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH); 
     SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec); 
     SecretKey secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES"); 

     eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     eCipher.init(Cipher.ENCRYPT_MODE, secretKey); 

     dCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     byte[] iv = eCipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); 
     dCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); 
    } 

    public String decrypt(String encrypt) throws Exception { 
     byte[] bytes = Base64.decodeBase64(encrypt); 
     byte[] decrypted = decrypt(bytes); 
     return new String(decrypted, "UTF8"); 
    } 

    public byte[] decrypt(byte[] encrypt) throws Exception { 
     return dCipher.doFinal(encrypt); 
    } 

    public static void main(String[] args) throws Exception { 
     String passphrase = "PASSWORDPASSPHRASE"; 
     String encryptedPassword = "aUkbhjFebZ9VjJ44yptlBA==";   
     AESDecrypt aesDecrypt = new AESDecrypt(passphrase); 
     String decryptedPassword = aesDecrypt.decrypt(encryptedPassword); 
     System.out.println("decryptedPasswpord = " + decryptedPassword); 
    } 
} 

AESDecrypt 코드를 실행할 때 오류가 반환됩니다.

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 
    at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..) 
    at javax.crypto.Cipher.doFinal(DashoA13*..) 
    at AESDecrypt.decrypt(AESDecrypt.java:41) 
    at AESDecrypt.decrypt(AESDecrypt.java:35) 
    at AESDecrypt.main(AESDecrypt.java:50) 

왜 오류가 발생합니까? 누구든지 도와 줄 수 있습니까? 고마워요!

답변

3

CBC (Cipher Block Chaining) 모드를 사용하는 경우 InitializationVector를 추출하여 암호화 된 메시지에 추가하거나 동일한 IV를 암호 해독 코드에 전달하는 다른 방법을 찾아야합니다.

CBC 모드는 IV를 사용하지 않는 ECB보다 안전한 모드입니다. CBC는 두 번 암호화 된 동일한 데이터가 동일한 암호문을 생성하지 않도록 보장하는 무작위 IV를 사용합니다.

import java.security.spec.KeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

import org.apache.commons.codec.binary.Base64; 


public class AESEncrypt { 
    private static final byte[] SALT = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03}; 
    private static final int ITERATION_COUNT = 65536; 
    private static final int KEY_LENGTH = 128; 
    private Cipher eCipher; 
    private Cipher dCipher; 
    private byte[] iv; 

    AESEncrypt(String passPhrase) throws Exception { 
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH); 
     SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec); 
     SecretKey secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES"); 

     eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     eCipher.init(Cipher.ENCRYPT_MODE, secretKey); 

     dCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     iv = eCipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); 
     dCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); 
    } 

    public String encrypt(String encrypt) throws Exception { 
     byte[] bytes = encrypt.getBytes("UTF8"); 
     byte[] encrypted = encrypt(bytes); 
     byte[] cipherText = new byte[encrypted.length + iv.length]; 
     System.arraycopy(iv, 0, cipherText, 0, iv.length); 
     System.arraycopy(encrypted, 0, cipherText, iv.length, encrypted.length); 
     return new String(Base64.encodeBase64(cipherText)); 
    } 

    public byte[] encrypt(byte[] plain) throws Exception { 
     return eCipher.doFinal(plain); 
    } 

    public static void main(String[] args) throws Exception { 
     String passphrase = "PASSWORDPASSPHRASE"; 
     String password = "password123";  
     AESEncrypt aesEncrypt = new AESEncrypt(passphrase); 
     String encryptedPassword = aesEncrypt.encrypt(password); 
     System.out.println("encryptedPassword = " + encryptedPassword); 
    } 
} 

그리고 :

그래서 코드를 같이한다이 경우

import java.security.spec.KeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

import org.apache.commons.codec.binary.Base64; 


public class AESDecrypt { 
    private static final byte[] SALT = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03}; 
    private static final int ITERATION_COUNT = 65536; 
    private static final int KEY_LENGTH = 128; 
    private static final int IV_LENGTH = 16; 
    private Cipher eCipher; 
    private Cipher dCipher; 
    private byte[] encrypt; 

    AESDecrypt(String passPhrase, String encryptedString) throws Exception { 
     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH); 
     SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec); 
     SecretKey secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES"); 

     encrypt = Base64.decodeBase64(encryptedString); 

     eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     eCipher.init(Cipher.ENCRYPT_MODE, secretKey); 

     byte[] iv = extractIV(); 
     dCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     dCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); 
    } 


    private byte[] extractIV() { 
     byte[] iv = new byte[IV_LENGTH]; 
     System.arraycopy(encrypt, 0, iv, 0, iv.length); 
     return iv; 
    } 

    public String decrypt() throws Exception { 
     byte[] bytes = extractCipherText(); 

     byte[] decrypted = decrypt(bytes); 
     return new String(decrypted, "UTF8"); 
    } 

    private byte[] extractCipherText() { 
     byte[] ciphertext = new byte[encrypt.length - IV_LENGTH]; 
     System.arraycopy(encrypt, 16, ciphertext, 0, ciphertext.length); 
     return ciphertext; 
    } 

    public byte[] decrypt(byte[] encrypt) throws Exception { 
     return dCipher.doFinal(encrypt); 
    } 

    public static void main(String[] args) throws Exception { 
     String passphrase = "PASSWORDPASSPHRASE"; 
     String encryptedPassword = "LiN1KmaB2Pl7cooe3qvuImbAKXsVJt5oxt+ajuVZ5n4=";   
     AESDecrypt aesDecrypt = new AESDecrypt(passphrase, encryptedPassword); 
     String decryptedPassword = aesDecrypt.decrypt(); 
     System.out.println("decryptedPasswpord = " + decryptedPassword); 
    } 
} 
+0

, 그것은 패딩을 사용하지하는 것이 가능하지만, 프로그램이 아직 확보하게? 어떻게해야하는지에 대한 조언이 있습니까? 감사! –

+0

당신은 너무 :) 왜 그게 문제입니까? 패딩 크기가 일정하기 때문에 u가 앞에 추가되거나 Base64를 암호 메시지에 추가하면 첨부 파일을 자유롭게 전송하거나 저장할 수 있습니다. 리셉션에서 그것을 떼어 내십시오. 또는 데이터가 부분적으로 암호화되어 대체 할 수 있기 때문에 보안을 손상시킬 수있는 ECB 모드를 사용합니다. – fatfredyy

+0

내 암호화 코드에서 패딩 및 IV를 추출하는 방법에 대한 예제를 제공 할 수 있습니까? 그리고 암호 해독 코드에서 나중에 어떻게 사용합니까? 저는 Java에서 매우 새로 운 것이고, 특히 암호화로 완전히 비어 있습니다. 고마워요! –

관련 문제