javax.crypto.IllegalBlockSizeException : Input length must be multiple of 16 when decrypting with padded cipher [duplicate]

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

问题:

I'm getting a decrypting error in java class:

javax.crypto.IllegalBlockSizeException :      Input length must be multiple of 16 when decrypting with padded cipher.

What can I do to solve this problem?

UPDATE:

I forgot to mention it is working once and when the second time im trying to execute it again its throwing the above mentioned error.

package com.tb.module.service; import java.security.Key; import java.security.spec.InvalidKeySpecException;  import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec;  import sun.misc.*;  /**  * This class is used for encrypt and decrypt the  password field.  *  */ public class PswdEnc {      private static final String ALGO = "AES";     private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };      public static String encrypt(String Data) throws Exception {         Key key = generateKey();         Cipher c = Cipher.getInstance(ALGO);         c.init(Cipher.ENCRYPT_MODE, key);         byte[] encVal = c.doFinal(Data.getBytes());         String encryptedValue = new BASE64Encoder().encode(encVal);         return encryptedValue;     }      public static String decrypt(String encryptedData) throws Exception {         Key key = generateKey();          Cipher c = Cipher.getInstance(ALGO);         c.init(Cipher.DECRYPT_MODE, key);         byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);         byte[] decValue = c.doFinal(decordedValue);         String decryptedValue = new String(decValue);         return decryptedValue;     }       private static Key generateKey() throws Exception {         Key key = new SecretKeySpec(keyValue, ALGO);         return key;     }  }

回答1:

The algorithm you are using, "AES", is a shorthand for "AES/ECB/NoPadding". What this means is that you are using the AES algorithm with 128-bit key size and block size, with the ECB mode of operation and no padding.

In other words: you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception.

If you want to encrypt data in sizes that are not multiple of 16 bytes, you are either going to have to use some kind of padding, or a cipher-stream. For instance, you could use CBC mode (a mode of operation that effectively transforms a block cipher into a stream cipher) by specifying "AES/CBC/NoPadding" as the algorithm, or PKCS5 padding by specifying "AES/ECB/PKCS5", which will automatically add some bytes at the end of your data in a very specific format to make the size of the ciphertext multiple of 16 bytes, and in a way that the decryption algorithm will understand that it has to ignore some data.

In any case, I strongly suggest that you stop right now what you are doing and go study some very introductory material on cryptography. For instance, check Crypto I on Coursera. You should understand very well the implications of choosing one mode or another, what are their strengths and, most importantly, their weaknesses. Without this knowledge, it is very easy to build systems which are very easy to break.


Update: based on your comments on the question, don't ever encrypt passwords when storing them at a database!!!!! You should never, ever do this. You must HASH the passwords, properly salted, which is completely different from encrypting. Really, please, don't do what you are trying to do... By encrypting the passwords, they can be decrypted. What this means is that you, as the database manager and who knows the secret key, you will be able to read every password stored in your database. Either you knew this and are doing something very, very bad, or you didn't know this, and should get shocked and stop it.



回答2:

A few comments:

import sun.misc.*; Don't do this. It is non-standard and not guaranteed to be the same between implementations. There are other libraries with Base64 conversion available.

byte[] encVal = c.doFinal(Data.getBytes()); You are relying on the default character encoding here. Always specify what character encoding you are using: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Defaults might be different in different places.

As @thegrinner pointed out, you need to explicitly check the length of your byte arrays. If there is a discrepancy, then compare them byte by byte to see where the difference is creeping in.



回答3:

To solve problem few changes you have to do in your code just make return type of encrypt() API of your class is byte[] array and in decrypt() API of your class pass byte[] array so by doing this you can solve input length multiple of 16 exception.

Please refer below working code :

public static byte[] encrypt(String value) {         byte[] encrypted = null;         try {              byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};             Key skeySpec = new SecretKeySpec(raw, "AES");             Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");             byte[] iv = new byte[cipher.getBlockSize()];              IvParameterSpec ivParams = new IvParameterSpec(iv);             cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);             encrypted  = cipher.doFinal(value.getBytes());             System.out.println("encrypted string:" + encrypted.length);          } catch (Exception ex) {             ex.printStackTrace();         }         return encrypted;     }      public static  byte[]  decrypt(byte[] encrypted) {          byte[] original = null;          Cipher cipher = null;         try {             byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};             Key key = new SecretKeySpec(raw, "AES");             cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");             //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher             byte[] ivByte = new byte[cipher.getBlockSize()];             //This class specifies an initialization vector (IV). Examples which use             //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.             IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);             cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);             original= cipher.doFinal(encrypted);         } catch (Exception ex) {             ex.printStackTrace();         }         return original;     }  


回答4:

Well that is Because of

you are only able to encrypt data in blocks of 128 bits or 16 bytes. That's why you are getting that IllegalBlockSizeException exception. and the one way is to encrypt that data Directly into the String.

look this. Try and u will be able to resolve this

public static String decrypt(String encryptedData) throws Exception {      Key key = generateKey();     Cipher c = Cipher.getInstance(ALGO);     c.init(Cipher.DECRYPT_MODE, key);     String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();     System.out.println("This is Data to be Decrypted" + decordedValue);     return decordedValue; }

hope that will help.



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