IllegalBlockSizeException when trying to encrypt and decrypt a string with AES

匿名 (未验证) 提交于 2019-12-03 01:33:01

问题:

I have a hardcoded key with which I want to encrypt a string before storing it in SharedPreferences. This is the code I have so far:

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

It seems to be catching an exception at the end of decrypt method:

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

Can someone point me in the right direction? I have a feeling I'm doing something wrong instantiating IvParameterSpec.

回答1:

When you encrypt a string with AES, you get an array of bytes back. Trying to convert those bytes directly to a string (new String(cipher.doFinal(plaintextBytes))) will cause all sorts of problems. If you require the output from your encryption method to be a string, then use Base64 rather than attempting a direct conversion. In your decryption method, convert the Base64 string back into a byte array before decrypting the byte array.

Also, do not use getBytes() since the output depends on the system defaults. Use getBytes("utf-8") or whatever. That eliminates ambiguity.



回答2:

Just in case anyone is interested (or feels too lazy to do their research), here is the the result code for AES-256 encryption and decryption that I put together, with help from the accepted answer and comments:

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 


回答3:

It's an extension of Artjom B answer and working for me.

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!