使用基于密码的加密审查此AES-128 CBC示例

时间:2017-05-10 09:50:04

标签: java cryptography aes salt initialization-vector

我需要一些帮助来验证下面的代码片段,以便使用CBC,PKCS5Padding和IV进行Java AES加密。

我测试了代码并且能够加密和解密。我有几个问题,如下所述。

  1. 密码应存放在哪里作为一个好的约定?
  2. 将密码和IV字节附加/检索到ciphetext的方法是否合适?
  3. 高度赞赏任何其他评论,谢谢!
  4. 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);
        }
    
    }
    

1 个答案:

答案 0 :(得分:1)

查询

  

密码应该存储在哪里作为一个好的约定?

对称密钥应该最好到达保险库。否则他们应该去密钥库,但是你有保护密钥库密码的问题。

  

是向密码附加/检索Salt和IV字节的方法   文字很好吗?

盐应该生成:

SecureRandom random = SecureRandom.getInstanceStrong();

否则你使用较弱的熵池(即linux中的/ dev / urandom)来生成你的安全号码,这会导致弱键更容易被破解。

  

高度赞赏任何其他评论,谢谢!

在处理字符串转换时,您应始终使用相同的编码,即.getBytes("UTF-8")以避免出现问题。例如,在转换盐时你不能使用它。