IllegalBlockSize尝试使用AES加密和解密字符串时的异常

2022-09-03 09:11:28

我有一个硬编码的密钥,我想在将字符串存储在 .这是我到目前为止的代码:SharedPreferences

public class TokenEncryptor {

    private final static String TOKEN_KEY = "91a29fa7w46d8x41";

    public static String encrypt(String plain) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]);
            SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES");
            cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
            return new String(cipher.doFinal(plain.getBytes()));
        } catch (Exception e) {
            Ln.e(e);
            return null;
        }
    }

    public static String decrypt(String encoded) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]);
            SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES");
            cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
            return new String(cipher.doFinal(encoded.getBytes()));
        } catch (Exception e) {
            Ln.e(e);
            return null;
        }
    }
}

它似乎在方法末尾捕获了一个异常:decrypt

javax.crypto.IllegalBlockSizeException: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

有人能给我指出正确的方向吗?我有一种感觉,我在实例化时做错了什么。IvParameterSpec


答案 1

使用 AES 加密字符串时,将返回一个字节数组。尝试将这些字节直接转换为字符串()将导致各种问题。如果要求加密方法的输出为字符串,请使用而不是尝试直接转换。在解密方法中,在解密字节数组之前,将字符串转换回字节数组。new String(cipher.doFinal(plaintextBytes))Base64Base64

另外,不要使用,因为输出取决于系统默认值。使用什么的。这消除了歧义。getBytes()getBytes("utf-8")


答案 2

为了以防万一有人感兴趣(或者觉得懒得做他们的研究),这是我放在一起的加密和解密的结果代码,在接受的答案和评论的帮助下:AES-256

public class TokenEncryptor {

    private final static String TOKEN_KEY = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw";

    public static String encrypt(String plain) {
        try {
            byte[] iv = new byte[16];
            new SecureRandom().nextBytes(iv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv));
            byte[] cipherText = cipher.doFinal(plain.getBytes("utf-8"));
            byte[] ivAndCipherText = getCombinedArray(iv, cipherText);
            return Base64.encodeToString(ivAndCipherText, Base64.NO_WRAP);
        } catch (Exception e) {
            Ln.e(e);
            return null;
        }
    }

    public static String decrypt(String encoded) {
        try {
            byte[] ivAndCipherText = Base64.decode(encoded, Base64.NO_WRAP);
            byte[] iv = Arrays.copyOfRange(ivAndCipherText, 0, 16);
            byte[] cipherText = Arrays.copyOfRange(ivAndCipherText, 16, ivAndCipherText.length);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv));
            return new String(cipher.doFinal(cipherText), "utf-8");
        } catch (Exception e) {
            Ln.e(e);
            return null;
        }
    }

    private static byte[] getCombinedArray(byte[] one, byte[] two) {
        byte[] combined = new byte[one.length + two.length];
        for (int i = 0; i < combined.length; ++i) {
            combined[i] = i < one.length ? one[i] : two[i - one.length];
        }
        return combined;
    }

}

推荐