基于AES-256密码的Java加密/解密

我找到了一个用Java实现AES加密/解密的指南,并尝试理解每一行,因为我把它放到我自己的解决方案中。 但是,我并不完全理解它并因此而遇到问题。 最终目标是使用基于密码的加密/解密。 我已经阅读了关于此的其他文章/ stackoverflowpost,但大多数都没有提供足够的解释(我在Java中加密非常新)

我现在的主要问题是,即使我设置了byte[] saltBytes = "Hello".getBytes(); 我到底仍然得到一个不同的Base64结果( char[] password每次都是随机的,但我读到以char[]forms保留密码更安全。我的另一个问题是当程序进入decrypt() ,我在byte[] saltBytes = salt.getBytes("UTF-8");得到一个NullPointerException byte[] saltBytes = salt.getBytes("UTF-8");

提前感谢您提供给我的任何帮助/建议。

有问题的代码:

 import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class EncryptionDecryption { private static String salt; private static int iterations = 65536 ; private static int keySize = 256; private static byte[] ivBytes; public static void main(String []args) throws Exception { char[] message = "PasswordToEncrypt".toCharArray(); System.out.println("Message: " + message.toString()); System.out.println("Encrypted: " + encrypt(message)); System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); } public static String encrypt(char[] plaintext) throws Exception { salt = getSalt(); byte[] saltBytes = salt.getBytes(); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); PBEKeySpec spec = new PBEKeySpec(plaintext, 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(); ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); byte[] encryptedTextBytes = cipher.doFinal(plaintext.toString().getBytes("UTF-8")); return DatatypeConverter.printBase64Binary(encryptedTextBytes); } public static String decrypt(char[] encryptedText) throws Exception { byte[] saltBytes = salt.getBytes("UTF-8"); byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(encryptedText.toString()); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); PBEKeySpec spec = new PBEKeySpec(encryptedText, 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.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 decryptedTextBytes.toString(); } public static String getSalt() throws Exception { SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); byte[] salt = new byte[20]; sr.nextBytes(salt); return salt.toString(); } } 

我认为你犯了两个错误:)

我已经更正了您的示例代码以使其正常工作:

 import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class EncryptionDecryption { private static String salt; private static int iterations = 65536 ; private static int keySize = 256; private static byte[] ivBytes; private static SecretKey secretKey; public static void main(String []args) throws Exception { salt = getSalt(); char[] message = "PasswordToEncrypt".toCharArray(); System.out.println("Message: " + String.valueOf(message)); System.out.println("Encrypted: " + encrypt(message)); System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); } public static String encrypt(char[] plaintext) throws Exception { byte[] saltBytes = salt.getBytes(); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize); 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(); ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8")); return DatatypeConverter.printBase64Binary(encryptedTextBytes); } public static String decrypt(char[] encryptedText) throws Exception { System.out.println(encryptedText); byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText)); 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种不同的盐(当使用加密方法时),因此加密/解密的日志是不同的(逻辑,但解密仍然有效,因为你在加密后直接调用解密)。

第二个错误是秘密密钥。 您需要在加密时生成密钥,但不能解密。 更简单地说,就好像我用密码“encrypt”加密,并且你试图用密码“decrypt”解密它。

我会建议你生成每个随机的东西(如启动时的私钥,盐等)。 但要注意,当你停止你的应用程序时,除非得到完全相同的随机内容,否则你将无法解密旧的东西。

希望我帮助:)

问候,