尝试使用AESencryption和解密string时发生IllegalBlockSizeException

我有一个硬编码的密钥,我想先encryption一个string,然后将其存储在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东西。

使用AESencryptionstring时,会返回一个字节数组。 试图将这些字节直接转换为一个string( new String(cipher.doFinal(plaintextBytes)) )将导致各种问题。 如果您要求encryption方法的输出为string,则使用Base64而不是尝试直接转换。 在解密方法中,在解密字节数组之前,将Base64string转换回字节数组。

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

为了防止任何人感兴趣(或者懒得做他们的研究),下面是AES-256encryption和解密的结果代码,在我接受的答案和评论的帮助下,

 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; } } 

这是Artjom B为我工作的延伸。

 public String encryptMsg(String message, SecretKey secret) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { Cipher cipher = null; cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secret); byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8")); return Base64.encodeToString(cipherText, Base64.NO_WRAP); } public String decryptMsg(String cipherText, SecretKey secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException { Cipher cipher = null; cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secret); byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP); String decryptString = new String(cipher.doFinal(decode), "UTF-8"); return decryptString; }