2017-05-10 11 views
1

CBC, PKCS5Padding 및 IV를 사용하여 Java AES 암호화를위한 아래 코드 스 니펫의 유효성을 검사하는 데 도움이 필요합니다.비밀번호 기반 암호화를 사용하는이 AES-128 CBC 예제 검토

코드를 테스트하여 암호화하고 해독 할 수있었습니다. 아래에 설명 된대로 몇 가지 쿼리가 있습니다.

  1. 어디에서 암호를 규칙으로 저장해야합니까?
  2. 소금과 IV 바이트를 ciphetext에 잘 추가/검색하는 방법이 있습니까?
  3. 기타 의견은 높이 평가되었습니다. 감사합니다.
public class Encryption { 

    private static int iterations = 65536; 
    private static int keySize = 128; 
    private static char[] password = "password".toCharArray(); 
    private static String algorithm= "PBKDF2WithHmacSHA1"; 


    private static final String SEPARATOR = "~"; 


    public static void main(String []args) throws Exception { 

     String filePath = "test.xml"; 

     String fileContent = new String(Files.readAllBytes(Paths.get(filePath))); 

     String encrMesg = encrypt(fileContent); 

     System.out.println("Encrypted: " + encrypt(encrMesg)); 

     System.out.println("Decrypted: " + decrypt(encrMesg)); 
    } 


    public static String encrypt(String plaintext) throws Exception { 


     byte[] saltBytes = getSalt().getBytes(); 

     SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm); 
     PBEKeySpec spec = new PBEKeySpec(password, saltBytes, iterations, keySize); 
     SecretKey secretKey = skf.generateSecret(spec); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretSpec); 
     AlgorithmParameters params = cipher.getParameters(); 

     byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); 
     byte[] cipherText = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8")); 

     return DatatypeConverter.printBase64Binary(ivBytes)+SEPARATOR+DatatypeConverter.printBase64Binary(saltBytes) 
     +SEPARATOR+DatatypeConverter.printBase64Binary(cipherText); 
    } 

    public static String decrypt(String encryptedText) throws Exception { 

     System.out.println(encryptedText); 

     String[] encryptedArr = encryptedText.split(SEPARATOR); 

     byte[] ivBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[0])); 

     byte[] salt = DatatypeConverter.parseBase64Binary(new String(encryptedArr[1])); 

     byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[2])); 

     SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm); 
     PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keySize); 
     SecretKey secretKey = skf.generateSecret(spec); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes)); 

     byte[] decryptedTextBytes = null; 

     try { 
      decryptedTextBytes = cipher.doFinal(encryptedTextBytes); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } 

     return new String(decryptedTextBytes); 

    } 

    public static String getSalt() throws Exception { 

     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     byte[] salt = new byte[20]; 
     sr.nextBytes(salt); 
     return new String(salt); 
    } 

} 
+2

암호를 저장하는 가장 좋은 장소는 사람의 뇌입니다. 그것은 처음부터 암호를 사용하는 요지입니다. 머신에 저장하는 경우 이진 키를 안전한 방법으로 저장하는 것이 좋습니다. – Henry

+0

이 작업을 잘 수행하는 라이브러리 중 하나를 사용하지 않는 이유는 무엇입니까? [RNCryptor] (https://github.com/RNCryptor/JNCryptor)와 [this one] (https://github.com/tozny/java-aes-crypto)이 떠오른다. –

답변

1

쿼리 암호가 좋은 규칙으로 저장해야합니다

?

대칭 키는 볼트로 이동해야합니다. 그렇지 않으면 키 저장소로 이동해야하지만 키 저장소 비밀번호를 안전하게 유지해야합니다.

소금과 IV 바이트를 암호문에 추가/검색하는 방법은 입니다. 괜찮습니까?

소금 생성해야합니다 그렇지 않으면

SecureRandom random = SecureRandom.getInstanceStrong(); 

당신이 당신의 보안 번호를 생성하기 위해 (예는/dev/urandom을 리눅스에서) 약한 엔트로피 풀을 사용하고 있으며, 그 수 있습니다 약한 키에 이르게 더 쉽게 깨진.

기타 의견은 높이 평가했습니다. 감사합니다.

문제를 방지하려면 문자열 변환을 처리 할 때 항상 동일한 인코딩 (예 : .getBytes("UTF-8"))을 사용해야합니다. 예를 들어 소금을 전환 할 때 사용하지 마십시오.

+1

개인 키는 보안하기가 어렵습니다. 비대칭 암호화는 대칭 암호화에 비해 매우 느리고 데이터 길이는 키 크기보다 작습니다. 일반적으로 데이터는 AES와 같은 대칭 방식으로 암호화되며 키는 비대칭 암호화로 암호화됩니다. TLS는 대칭 암호화로 데이터를 암호화합니다. – zaph

+1

사실 모든 데이터는 대칭 암호화로 암호화됩니다. RSA 2048 비트 키가 주어지면 데이터 제한은 256 바이트 미만이고 256 비트 EC 키의 경우 데이터 제한은 32 바이트 미만입니다. AES에는 기본적으로 데이터 길이 제한이 없습니다. 대칭 암호화는 암호화 작업 말입니다. iOS의 경우 모든 파일 시스템 데이터는 대칭 암호화 인 AES로 암호화됩니다. – zaph

+0

참고 : WRT 대칭 및 비대칭 키의 마지막 단락은 관련 주석이있는 것처럼 대답에서 삭제되었습니다. – zaph