2017-05-10 33 views
1

我需要一些幫助來驗證以下代碼片段,以便使用CBC,PKCS5Padding和IV進行Java AES加密。使用基於密碼的加密對AES-128 CBC示例的回顧

我測試了代碼並能夠加密和解密。我有幾個查詢如下所述。

  1. 密碼應該存儲在哪裏作爲一個良好的約定?
  2. 將ciphetext附加/檢索salt和IV字節的方式是否正確?
  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

查詢

應該在哪裏密碼被存儲爲一個好習慣?

對稱密鑰應該最好放在保險庫中。否則,他們應該繼續使用密鑰存儲庫,但是存在保護密鑰庫密碼的問題。

添加/檢索Salt和IV字節到密碼 文本的方式是否正常?

鹽應產生:

SecureRandom random = SecureRandom.getInstanceStrong(); 

否則,您使用的弱熵池(即的/ dev/urandom的在Linux)來生成你的安全號碼,並導致弱密鑰,可以是更容易破碎。

其他意見非常感謝,謝謝!

您應該在處理字符串轉換時始終使用相同的編碼,即.getBytes("UTF-8")以避免問題。例如,在轉換鹽時不使用它。

+1

私鑰很難保護。非對稱加密與對稱加密相比非常慢,數據長度被限制爲小於密鑰大小。一般情況下,數據採用AES等對稱方法進行加密,密鑰採用非對稱加密進行加密。請注意,TLS使用對稱加密來加密數據。 – zaph

+1

幾乎所有數據都使用對稱加密進行加密。給定RSA 2048位密鑰,數據限制小於256字節,對於256位EC密鑰,數據限制小於32字節。使用AES基本上沒有數據長度限制。對稱加密是加密工作。對於iOS,所有文件系統數據均使用對稱加密進行加密:AES。 – zaph

+0

注意:最後一段WRT對稱和非對稱密鑰已從相關評論中刪除。 – zaph

相關問題