AES

2012-04-07 7 views
0

I가 거의 작동 다음 코드를AES

AES.java

import java.io.UnsupportedEncodingException; 
import java.security.AlgorithmParameters; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.security.spec.AlgorithmParameterSpec; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.InvalidParameterSpecException; 
import java.security.spec.KeySpec; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.KeyGenerator; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

public class AES { 

    private static final int KEY_LENGTH    = 128; 
    private static final int ITERATIONS    = 100; 

    private static final String ALGORITHM    = "AES"; 
    private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA1"; 
    private static final String TRANSFORMATION   = "AES/CBC/PKCS5Padding"; 

    private final Cipher  m_enc_cipher; 
    private final Cipher  m_dec_cipher; 

    private final byte[]  m_iv; 

    public AES(final char[] password, final byte[] salt) 
      throws NoSuchAlgorithmException, InvalidKeySpecException, 
      NoSuchPaddingException, InvalidKeyException, 
      InvalidParameterSpecException, IllegalBlockSizeException, 
      BadPaddingException, UnsupportedEncodingException, 
      InvalidAlgorithmParameterException { 

     // Derive the key, given password and salt 
     final SecretKeyFactory factory = SecretKeyFactory 
       .getInstance(SECRET_KEY_ALGORITHM); 
     final KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, 
       KEY_LENGTH); 
     final SecretKey tmp = factory.generateSecret(spec); 
     final SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM); 

     // Build encryptor and get IV 
     final Cipher enc_cipher = Cipher.getInstance(TRANSFORMATION); 
     enc_cipher.init(Cipher.ENCRYPT_MODE, secret); 
     final AlgorithmParameters params = enc_cipher.getParameters(); 
     final byte[] iv = params.getParameterSpec(IvParameterSpec.class) 
       .getIV(); 

     // Build decryptor 
     final Cipher dec_cipher = Cipher.getInstance(TRANSFORMATION); 
     dec_cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); 

     this.m_enc_cipher = enc_cipher; 
     this.m_dec_cipher = dec_cipher; 

     this.m_iv = iv; 
    } 

    public AES(final byte[] iv) throws NoSuchAlgorithmException, 
      InvalidKeySpecException, NoSuchPaddingException, 
      InvalidKeyException, InvalidParameterSpecException, 
      IllegalBlockSizeException, BadPaddingException, 
      UnsupportedEncodingException, InvalidAlgorithmParameterException { 

     final AlgorithmParameterSpec aps = new IvParameterSpec(iv); 

     final KeyGenerator keygen = KeyGenerator.getInstance(ALGORITHM); 
     keygen.init(KEY_LENGTH); 
     final SecretKey secret = keygen.generateKey(); 

     // Build encryptor 
     final Cipher enc_cipher = Cipher.getInstance(TRANSFORMATION); 
     enc_cipher.init(Cipher.ENCRYPT_MODE, secret, aps); 

     // Build decryptor 
     final Cipher dec_cipher = Cipher.getInstance(TRANSFORMATION); 
     dec_cipher.init(Cipher.DECRYPT_MODE, secret, aps); 

     this.m_enc_cipher = enc_cipher; 
     this.m_dec_cipher = dec_cipher; 

     this.m_iv = iv; 
    } 

    public byte[] get_iv() { 
     return this.m_iv; 
    } 

    public byte[] encrypt(final byte[] data) throws NoSuchAlgorithmException, 
      InvalidKeySpecException, NoSuchPaddingException, 
      InvalidKeyException, InvalidParameterSpecException, 
      IllegalBlockSizeException, BadPaddingException, 
      UnsupportedEncodingException { 
     return this.m_enc_cipher.doFinal(data); 
    } 

    public byte[] decrypt(final byte[] data) throws IllegalBlockSizeException, 
      BadPaddingException { 
     return this.m_dec_cipher.doFinal(data); 
    } 
} 

AESTest.java

import java.io.UnsupportedEncodingException; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.InvalidParameterSpecException; 
import java.util.Arrays; 

import javax.crypto.BadPaddingException; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 

import org.junit.Test; 
import static org.junit.Assert.*; 

public class AESTest { 
    @Test 
    public void test() throws InvalidKeyException, NoSuchAlgorithmException, 
      InvalidKeySpecException, NoSuchPaddingException, 
      InvalidParameterSpecException, IllegalBlockSizeException, 
      BadPaddingException, UnsupportedEncodingException, 
      InvalidAlgorithmParameterException { 

     final char[] password = "my_password".toCharArray(); 
     final byte[] salt = new byte[] { 22, 11 }; 

     final byte[] original_data = "Hello, World!".getBytes("UTF-8"); 
     final AES aesA = new AES(password, salt); 
     final byte[] encrypted_data = aesA.encrypt(original_data); 
     System.out.println("Encrypted:"); 
     System.out.println(javax.xml.bind.DatatypeConverter 
       .printBase64Binary(encrypted_data)); 

     final AES aesB = new AES(aesA.get_iv()); 
     final byte[] decrypted_data_B = aesB.decrypt(encrypted_data); 
     System.out.println("Decrypted B:"); 
     System.out.println(javax.xml.bind.DatatypeConverter 
       .printBase64Binary(decrypted_data_B)); 
     assertTrue(Arrays.equals(original_data, decrypted_data_B)); 
    } 
} 

을에 테스트 (AESTest.java),이 날 준다이 오류 :

javax.crypto.BadPaddingException: Given final block not properly padded 

최종 목표는 암호화 된 데이터 블록을 보내고 나중에 다시 가져올 수있게하는 것입니다.
"나중에"라는 용어는 일/주/년을 나타낼 수 있습니다.
그런 다음 동일한 암호를 사용하여 암호를 해독하려고합니다.

"나중에"한 달이 걸릴 수도 있으므로 새 AES 개체를 만들어야합니다.

이제이 새로운 AES 개체는 동일한 고정 암호/salt를 사용하여 데이터를 해독 할 수 있어야합니다.
그게 전부입니다.

동일한 IV를 사용하려고했지만 작동하지 않습니다.

내가 뭘 잘못하고 있니?

편집 # 1 : ITERATIONS에도주의하십시오.

답변

2

이미 언급했듯이 두 번째 생성자는 새 AES 키를 생성하므로 첫 번째 생성자에서 생성 된 AES 키와 일치하지 않습니다. 두 개의 서로 다른 생성자를 가짐으로써 귀하의 의도를 실제로 얻지는 않습니다. 각 생성자에서 암호 해독을위한 AES 인스턴스와 암호 해독을위한 AES 인스턴스를 만들 수 있습니까? 암호화 또는 해독할지 여부에 따라 해당 디자인을 다시 생각하고 단 하나의 인스턴스 만 사용하는 것이 좋습니다.

첫 번째 생성자에서 생성하는 키는 비밀로 유지되지만 생성되는 IV는 공개 정보이며 공개적으로 안전하게 게시 할 수 있습니다. 이는 보안에 해를 끼치 지 않습니다. 그러나 암호화 된 모든 메시지에 대해 고유 한 IV를 만들어야합니다. 그렇지 않으면 사용중인 CBC 모드에 대해 가능한 공격이 있습니다. 그래서 여기

난 당신이 그것을 추천 할 것입니다 방법은 다음과 같습니다

암호화 :

기본적으로 첫 번째 생성자, 암호 해독에 두 번째 인스턴스를 떠나. 생성 된 IV를 검색하십시오.

암호 해독

다시 기본적 추가 IV 파라미터와 제 구성자. 똑같은 매개 변수 (salt, password, iterations)를 사용하여 처음부터 키를 다시 생성하고 암호 해독 모드에서 Cipher을 초기화하고 IV 매개 변수를 추가로 전달하십시오.

그렇게해야합니다!

+0

두 번째 공급자는 http://pastebin.com/741SuBtv와 같아야합니까? 그것은 실제로 작동하지만 궁금하네요. 두 개의 'SecretKey' 객체 ('tmp' 및'secret')는 모두 정적 인 경우 어떻게합니까? 내가 그것을 이해하는지 모르겠다. 어쨌든, 게시 된 코드에 대해 어떻게 말합니까? – Poni

+0

감사합니다! ............. – Poni

3

AES를 iv으로 초기화 할 때 다른 secret을 생성합니다. Isnt는 틀린가?

같은 암호와 소금을 사용하고 있지 않습니다.

+0

나는 잘못인지 아닌지 전혀 모른다. 그래서 나는 구체적인 대답을 얻을 수 있기를 바란다. :) 편집 : 동일한 생성자를 사용하면 같은 오류가 발생합니다. – Poni

+0

'aesB'를 만들고'SecretKeySpec'을 초기화하면'ives '에서와 같이'aesA'의'secret.getEncoded()'를 사용합니다. – dash1e

+0

그렇다면 적절한 디 클리프를 얻기 위해 정확히 무엇을 사용해야합니까? 암호화 된 비밀 키? IV? 양자 모두? – Poni