I am developing an application, where I am encrypting and decrypting a text entered by the user.
But, I am getting the following error:
javax.crypto.IllegalBlockSizeException: last block incomplete in
decryption
below is my code for encryption and decryption. Encryption works perfectly, while I am getting this error while decrypting. Please refer the code below:
public static String fncEncrypt(String strClearText, String strKey) throws Exception{
String strData = "";
try {
SecretKeySpec sKeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] encrypted = cipher.doFinal(strClearText.getBytes());
strData = new String(encrypted);
}catch (Exception e){
e.printStackTrace();
}
return strData;
}
public static String fncDecrypt(String strEecrypted, String strKey) throws Exception {
String strData = "";
try {
SecretKeySpec skeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(strEecrypted.getBytes());
strData = new String(decrypted);
}catch (Exception e){
e.printStackTrace();
}
return strData;
}
Please respond if you have a solution for this.
You should decode the string instead of encoding the platform specific representation of the string, right at the start of your method.
byte[] base64TextToDecrypt = Base64.decodeBase64(textToDecrypt);
or more precisely:
byte[] bytesToDecrypt = Base64(base64TextToDecrypt);
if you name your variables correctly.
In general, each time you (feel like you have to) use the String.getBytes(): byte[] method or the String(byte[]) constructor you are likely doing something wrong. You should first think about what you are trying to do, and specify a character-encoding if you do need to use it.
In your case, the output in the converted variable is probably character-encoded. So you you could use the following fragment:
String plainText = new String(converted, Charset.forName("UTF8"));
System.out.println(plainText);
instead of what you have now.
Reference : https://stackoverflow.com/a/13274072/8416317
String class method getBytes() or new String(byte bytes[]) encode / decode with Charset.defaultCharset().name(), and some encrypted data would be ignored by encoding with special charset.
you could directly return byte[] by fncEncrypt and input byte[] to fncDecrypt. or encode result with BASE64.
public static byte[] fncEncrypt(String strClearText, String strKey) throws Exception{
byte[] encrypted = null;
try {
SecretKeySpec sKeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
encrypted = cipher.doFinal(strClearText.getBytes());
} catch (Exception e){
e.printStackTrace();
}
return encrypted;
}
public static String fncDecrypt(byte[] ecrypted, String strKey) throws Exception {
String strData = "";
try {
SecretKeySpec skeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(ecrypted);
strData = new String(decrypted);
}catch (Exception e){
e.printStackTrace();
}
return strData;
}
The reason is when you use new String(encrypted) it will not fully encode the bytes to string. Try the code below
public static byte[] fncEncrypt(String strClearText, String strKey) throws Exception{
SecretKeySpec sKeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] encrypted = cipher.doFinal(strClearText.getBytes());
return encrypted;
}
public static String fncDecrypt(byte[] encrypted, String strKey) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted);
}
You can encrypt and decrypt using the code below
String message = "Hello!";
byte[] encrypted = fncEncrypt(message, "key");
String decrypted = fncDecrypt(encrypted, "key");
System.out.println(decrypted);
Related
There are a lot of threads on stack overflow with this topic, and always the same solutions, but these doesn't work for me. I am looking for a way to decrypt the value byte[] encrypted and return byte[] decodedBytes.
With the method AESCrypt. I use compile 'com.scottyab:aescrypt:0.0.1'
private void testAES() {
try {
final byte[] encrypted = Base64.decode("R3JhbmRlIFZpY3RvaXJlICE=", Base64.NO_WRAP);
byte[] keyBytes = Base64.decode("L/91ZYrliXvmhYt9FKEkkDDni+PzcnOuV9cikm188+4=", Base64.NO_WRAP);
final byte[] ivBytes = Base64.decode("gqjFHI+YQiP7XYEfcIEJHw==".getBytes(), Base64.NO_WRAP);
final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
byte[] decodedBytes = AESCrypt.decrypt(keySpec, ivBytes, encrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
With the value Cipher, i use it like that.
private static byte[] testCipher() {
try {
final byte[] encrypted = Base64.decode("R3JhbmRlIFZpY3RvaXJlICE=", Base64.NO_WRAP);
byte[] keyBytes = Base64.decode("L/91ZYrliXvmhYt9FKEkkDDni+PzcnOuV9cikm188+4=", Base64.NO_WRAP);
byte[] ivBytes = Base64.decode("gqjFHI+YQiP7XYEfcIEJHw==".getBytes(), Base64.NO_WRAP);
final IvParameterSpec ivSpecForData = new IvParameterSpec(ivBytes);
SecretKeySpec decodedKeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, decodedKeySpec, ivSpecForData);
byte[] decodedBytes = cipher.doFinal(encrypted); // I have the error here //
return decodedBytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Whatever i do, i allways have the same error :
error:1e06b07b:Cipher functions:EVP_DecryptFinal_ex:WRONG_FINAL_BLOCK_LENGTH
I try to put in Cipher.getInstance (AES/CBC/NoPadding, AES/CBC/PKCS5Padding, AES/CBC/PKCS7Padding) but nothing change.
Do you have any idea to help me ?
"R3JhbmRlIFZpY3RvaXJlICE=" decoded to 17 hex bytes 4772616E646520566963746F6972652021 which is the ASCII text: "Grande Victoire !".
17 bytes is not a valid size for AES which is a block cipher that requires encrypted data to be a multiple of the block size of 16-bytes.
There is no encryption just Base64 encoding.
I'm new to cryptography and I'm attempting to create a simple AES encryption program and base64 enconding. The program seems to encrypt and decrypt my message string as it should but for some reason it shows me the exception java.lang.IllegalArgumentException: Illegal base64 character 20 in the decrypt method but maybe it has something to do with the encryption..
After searching for a while I couldn't find the reason for this. I would appreciate if someone could point out any mistakes in my code that could lead to this error!
public class AES_encryption {
private static SecretKey skey;
public static Cipher cipher;
public static void main(String[] args) throws Exception{
String init_vector = "RndInitVecforCBC";
String message = "Encrypt this?!()";
String ciphertext = null;
//Generate Key
skey = generateKey();
//Create IV necessary for CBC
IvParameterSpec iv = new IvParameterSpec(init_vector.getBytes());
//Set cipher to AES/CBC/
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try{
ciphertext = encrypt(skey, iv, message);
}
catch(Exception ex){
System.err.println("Exception caught at encrypt method!" + ex);
}
System.out.println("Original Message: " + message + "\nCipher Text: " + ciphertext);
try{
message = decrypt(skey, iv, message);
}
catch(Exception ex){
System.err.println("Exception caught at decrypt method! " + ex);
}
System.out.println("Original Decrypted Message: " + message);
}
private static SecretKey generateKey(){
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
skey = keygen.generateKey();
}
catch(NoSuchAlgorithmException ex){
System.err.println(ex);
}
return skey;
}
private static String encrypt(SecretKey skey, IvParameterSpec iv, String plaintext) throws Exception{
//Encodes plaintext into a sequence of bytes using the given charset
byte[] ptbytes = plaintext.getBytes(StandardCharsets.UTF_8);
//Init cipher for AES/CBC encryption
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
//Encryption of plaintext and enconding to Base64 String so it can be printed out
byte[] ctbytes = cipher.doFinal(ptbytes);
Base64.Encoder encoder64 = Base64.getEncoder();
String ciphertext = new String(encoder64.encode(ctbytes), "UTF-8");
return ciphertext;
}
private static String decrypt(SecretKey skey, IvParameterSpec iv, String ciphertext) throws Exception{
//Decoding ciphertext from Base64 to bytes[]
Base64.Decoder decoder64 = Base64.getDecoder();
byte[] ctbytes = decoder64.decode(ciphertext);
//Init cipher for AES/CBC decryption
cipher.init(Cipher.DECRYPT_MODE, skey, iv);
//Decryption of ciphertext
byte[] ptbytes = cipher.doFinal(ctbytes);
String plaintext = new String(ptbytes);
return plaintext;
}
}
The issue is because you decrypt the message not the encrypted message!
decrypt(skey, iv, message) should probably be decrypt(skey, iv, ciphertext)
I am using the below code to create a 128 bit AES cipher,
String initializer = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
byte[] initializer2 = new BigInteger(initializer, 2).toByteArray();
String encrypt = encrypt(binary_string_firsthalf, initializer2);
public static String encrypt(String plainText, byte[] key) {
try {
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF8"));
String encryptedString = new String(Base64.encode(cipherText));
return encryptedString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
But the code is returning a exception saying invalid AES key length.
How to create a cipher using 128 0's.
byte[] initializer2 = new byte[16];
is all you need to initialize a byte array with the default value of 0x00.
Don't use a static predictable key such as all 0x00 bytes for actual encryption.
In my application I am encrypting and decrypting data using secretKey. For that I am using AES algorithm. But I am getting exception in decrypt, one value out of three already encrypted values using secret key.
Exception is:
Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher.
Below is my code:
Function to encyrpt value
public static String symmetricEncrypt(String text, String secretKey) {
BASE64Decoder decoder = new BASE64Decoder();
byte[] raw;
String encryptedString;
SecretKeySpec skeySpec;
BASE64Encoder bASE64Encoder = new BASE64Encoder();
byte[] encryptText = text.getBytes();
Cipher cipher;
try {
raw = decoder.decodeBuffer(secretKey);
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encryptedString = bASE64Encoder.encode(cipher.doFinal(encryptText));
}
catch (Exception e) {
e.printStackTrace();
return "Error";
}
return encryptedString;
}
Function to decrypt value
public static String symmetricDecrypt(String text, String secretKey) {
BASE64Decoder decoder = new BASE64Decoder();
BASE64Decoder base64Decoder = new BASE64Decoder();
Cipher cipher;
String encryptedString;
byte[] encryptText = null;
byte[] raw;
SecretKeySpec skeySpec;
try {
raw = decoder.decodeBuffer(secretKey);
skeySpec = new SecretKeySpec(raw, "AES");
encryptText = base64Decoder.decodeBuffer(text);
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
encryptedString = new String(cipher.doFinal(encryptText));
} catch (Exception e) {
e.printStackTrace();
return "Error";
}
return encryptedString;
}
Following are the values that I am encrypting and decrypting
String secretKey = "XMzDdG4D03CKm2IxIWQw7g==";
String value1= "ABCD";
String enctypedValue1= "3uweh4pzoVyH1uODQmVNJA==";
String enctypedValue2= "37PTC20w4DMZYjG3f+GWepSvAbEJUccMXwS/lXilLav1qM/PrCTdontw5/82OdC1zzyhDEsFVRGo rV6gXAQcm+Zai15hliiUQ8l8KRMtUl4=";
String value4= "20000";
/** Ecnryption and decryption of value1 **/
String encryptedValue1= symmetricEncrypt(value1, secretKey);
String decryptedValue1 = symmetricDecrypt(encryptedValue1, secretKey);
/** Decryption of enctypedValue1 **/
String decryptedValue2 = symmetricDecrypt(enctypedValue1, secretKey);
System.out.println(decryptedValue2);
/** Decryption of enctypedValue2 (Not decrypted)**/
String decryptedValue3 = symmetricDecrypt(enctypedValue2, secretKey);
System.out.println(decryptedValue3);
/** Ecnryption and decryption of value4 **/
String encryptedValue4= symmetricEncrypt(value4, secretKey);
String decryptedValue4 = symmetricDecrypt(encryptedValue4, secretKey);
In the test function, I have written the following three test cases.
A new value (value1) being encrypted and decrypted using a secret key.
Two example encrypted values (enctypedValue1, enctypedValue2) which are being decrypted using same secret key. encryptedValue2 which got a problem while decrypting using same secret key.
A new value (value4) being encrypted and decrypted using a secret key.
On decrypting encryptedValue2 I am getting the following exception:
Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher
Following is what I have derived till now.
The problematic value seems to have a problem while decoding it, it returns 81 length array which is unable to get decrypted?
If this problem was to happen it should have happened to all the values.
Is this a value specific problem or it is something related to padding or it can have a different behavior on different browser, different os?
I was able to run the code without any problem. However, I used Apache's Base64 for encoding/decoding...maybe your Base64 has bugs. If you wrote it yourself, there is a big chance that you missed some cases. For real production code, use heavily tested libraries such as Apache's.
You can find the library that I used for Base64 here: http://commons.apache.org/proper/commons-codec/download_codec.cgi
Here is the full working code:
package security.symmatric;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AES {
public static String symmetricEncrypt(String text, String secretKey) {
byte[] raw;
String encryptedString;
SecretKeySpec skeySpec;
byte[] encryptText = text.getBytes();
Cipher cipher;
try {
raw = Base64.decodeBase64(secretKey);
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encryptedString = Base64.encodeBase64String(cipher.doFinal(encryptText));
}
catch (Exception e) {
e.printStackTrace();
return "Error";
}
return encryptedString;
}
public static String symmetricDecrypt(String text, String secretKey) {
Cipher cipher;
String encryptedString;
byte[] encryptText = null;
byte[] raw;
SecretKeySpec skeySpec;
try {
raw = Base64.decodeBase64(secretKey);
skeySpec = new SecretKeySpec(raw, "AES");
encryptText = Base64.decodeBase64(text);
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
encryptedString = new String(cipher.doFinal(encryptText));
} catch (Exception e) {
e.printStackTrace();
return "Error";
}
return encryptedString;
}
public static void main(String[] args) {
String secretKey = "XMzDdG4D03CKm2IxIWQw7g==";
String value1= "ABCD";
String enctypedValue1= "3uweh4pzoVyH1uODQmVNJA==";
String enctypedValue2= "37PTC20w4DMZYjG3f+GWepSvAbEJUccMXwS/lXilLav1qM/PrCTdontw5/82OdC1zzyhDEsFVRGo rV6gXAQcm+Zai15hliiUQ8l8KRMtUl4=";
String value4= "20000";
/** Ecnryption and decryption of value1 **/
String encryptedValue1= symmetricEncrypt(value1, secretKey);
String decryptedValue1 = symmetricDecrypt(encryptedValue1, secretKey);
System.out.println(decryptedValue1);
/** Decryption of enctypedValue1 **/
String decryptedValue2 = symmetricDecrypt(enctypedValue1, secretKey);
System.out.println(decryptedValue2);
/** Decryption of enctypedValue2 **/
String decryptedValue3 = symmetricDecrypt(enctypedValue2, secretKey);
System.out.println(decryptedValue3);
/** Ecnryption and decryption of value4 **/
String encryptedValue4= symmetricEncrypt(value4, secretKey);
String decryptedValue4 = symmetricDecrypt(encryptedValue4, secretKey);
System.out.println(decryptedValue4);
}
}
I am encrypting a string and storing it in a cookie at client side.. but when I send that exact encrypted string from js to java code it gives me the aforementioned exception.
The code I am using for encryption and decryption is:
public static final String UNICODE_FORMAT = "UTF8";
public static String encrypt(String Data, SecretKeySpec skeySpec,IvParameterSpec ivspec) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
byte[] plainBytes = Data.getBytes(UNICODE_FORMAT);
byte[] encrypted = cipher.doFinal(plainBytes);
String encryption = bytesToString(encrypted);
return encryption;
}
public static String decrypt(String encryptedData,SecretKeySpec skeySpec,IvParameterSpec ivspec) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
byte[] decryptval = hexToBytes(encryptedData);
byte[] decrypted = cipher.doFinal(decryptval);
return new String(decrypted);
}
public static String bytesToString(byte[] bytes) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
String s = adapter.marshal(bytes);
return s;
}
public static byte[] hexToBytes(String hexString) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
byte[] bytes = adapter.unmarshal(hexString);
return bytes;
}
can you tell me what the issue could be?? I have tried the solutions mentioned at stackoverflow.com and also a few other solutions but none worked.. am I getting this error because I am sending the encrypted string to JS and it is changing the padding of the string?
As # JoopEggen mentioned - creating sting from byte[] can break it.
Can you just serialize, instead of creating string from it?