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

时间:2015-02-20 05:48:48

标签: java encryption passwords aes password-encryption

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

我现在的主要问题是,即使我设置byte[] saltBytes = "Hello".getBytes(); 我最后仍然获得了不同的Base64结果(char[] password每次都是随机的,但我读到以char[]形式保留密码更安全。我的另一个问题是当程序到达{时{1}},我得到一个NullPointerException  decrypt()

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

有问题的代码:

byte[] saltBytes = salt.getBytes("UTF-8");

1 个答案:

答案 0 :(得分:18)

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

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

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”解密它。

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

希望我帮助过:)

此致