javax.crypto.IllegalBlockSizeException upon decryption - java

the current decryption algorithm I wrote goes as follows,
public String decrypt(String enc) throws Exception
{
Key key = k;
Cipher crypt = Cipher.getInstance("AES");
crypt.init(Cipher.DECRYPT_MODE,key);
byte[] decrypt = crypt.doFinal(enc.getBytes());
return new String(decrypt);
}
The error that I get is at the line
byte[] decrypt = crypt.doFinal(enc.getBytes());
I have seen similar questions as this posted, but I am using a 128 bit key, so I am pretty certain there is no padding.
This is how I generate the key
public static SecretKey getKey() throws Exception
{
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
return keyGen.generateKey();
}
Additionally, decoding using base64 gives the same exact error
public String decrypt(String enc) throws Exception
{
Key key = k;
Cipher crypt = Cipher.getInstance("AES");
crypt.init(Cipher.DECRYPT_MODE,key);
byte[] decrypt = crypt.doFinal(Base64.getMimeDecoder().decode(enc));
return new String(decrypt);
}

public String decrypt(String enc)
The problem has already happened by the time you get here. The problem is that you are passing around ciphertext in a String. String isn't a container for binary data. Use a byte[].

Related

How to do AES Decryption in java

I tried AES encryption in javaScript and trying to decrypt in java with same algorithm and secretKey please anyone suggest
javaScript encryption
const cipher = crypto.createCipher('aes192','67f969129e2f78f2ee286d16efec0dad');
var encrypted = cipher.update('Hello JavaTpoint', 'utf8', 'base64');
encrypted += cipher.final('base64');
console.log(encrypted); // VABI2hVl2Ydqednr3K5tJv0VFKKiiFK3Jn3kinGxL7U=
encrypted base64 key : VABI2hVl2Ydqednr3K5tJv0VFKKiiFK3Jn3kinGxL7U=
java decryption
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException, Exception {
byte[] array = Base64.getDecoder().decode("VABI2hVl2Ydqednr3K5tJv0VFKKiiFK3Jn3kinGxL7U=");
byte[] dec = decrypt(array, "67f969129e2f78f2ee286d16efec0dad");
System.out.println("content is :: dec " + new String(dec));
}
public static byte[] decrypt(byte[] input, String key) {
byte[] decrypted = null;
try {
System.out.println(new String(decodeHexString(key)));
SecretKeySpec skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey);
decrypted = cipher.doFinal(input);
} catch (Exception e) {
e.printStackTrace();
}
return decrypted;
}
getting error in java :
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at com.sd.lambda.Decryption.decrypt(Decryption.java:84)
at com.sd.lambda.Decryption.main(Decryption.java:47)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:566)
at com.sd.lambda.Decryption.main(Decryption.java:50)
it should be decrypt and print "Hello JavaTpoint" in java console like this:
content is :: dec Hello JavaTpoint
When you are calling cipher.init() in the decrypt method, the IV is a necessary third parameter. Depending on how the original string is being encrypted will determine how you go about obtaining this value.
Here's a link to the init() method you'll want to use when setting up your decryption cipher:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/crypto/Cipher.html#init(int,java.security.Key,java.security.SecureRandom)

BadPaddingException during decryption in java

I am new java to encryption. Trying to implement something light weight to encrypt a string and store it somewhere and de-crypt it back before using.
With some web search I came up with this for encryption and decryption.
public static String base64Encode(byte[] bytes)
{
return new BASE64Encoder().encode(bytes);
}
public static byte[] base64Decode(String property) throws IOException
{
return new BASE64Decoder().decodeBuffer(property);
}
public static String encrypt(String mystring) throws GeneralSecurityException, UnsupportedEncodingException
{
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(mystring.toCharArray()));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return base64Encode(pbeCipher.doFinal(mystring.getBytes("UTF-8")));
}
public static String decrypt(String estring) throws GeneralSecurityException, IOException
{
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(estring.toCharArray()));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(base64Decode(estring)), "UTF-8");
}
I see that encryption worked but I saw a padding related exception in the decryption part, from the doFinal block. Here it is...
encrypted string:zdrtgOKfkZMgpCOflr1ILQ== -> Encrypted String
exceptionjavax.crypto.BadPaddingException: Given
final block not properly padded -> Exception from the doFinal block.
Seems like when I encrypted it, I need to do some kind of padding.
Can any one tell me what went wrong and how can it be fixed?
Thanks
Tas
You are using password based encryption here. This means that the encryption key itself is based upon a password. You must use the same password for both encryption and decryption.
private static char[] ENCRYPTION_PASSWORD
= "some password populated by configuration".toCharArray();
public static String encrypt(String mystring)
throws GeneralSecurityException, UnsupportedEncodingException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(ENCRYPTION_PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return DatatypeConverter
.printBase64Binary(pbeCipher.doFinal(mystring.getBytes("UTF-8")));
}
public static String decrypt(String string)
throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(ENCRYPTION_PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(DatatypeConverter
.parseBase64Binary(estring)), "UTF-8");
}
Note also the use of javax.xml.bind.DatatypeConverter for base64 operations. No need to write your own or use third parties these days.
You will need to first decode your input to the decrypt method.
Call the base64Decode method and the estring parameter in your decrypt method.
That should do it.
Change your code ,
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(mystring.toCharArray()));
to
SecretKey key = keyFactory.generateSecret(new PBEKeySpec("PASSWORD".toCharArray(), SALT, 20));

javax.crypto.BadPaddingException AES

I am using AESCrypt (gradle :compile 'com.scottyab:aescrypt:0.0.1')
to encrypt and decrypt the data.
TextView tv=(TextView)findViewById(R.id.demotext);
String encrypted="",decrypted="";
try {
encrypted = AESCrypt.encrypt("password","This is the best thing to go by");
decrypted = AESCrypt.decrypt("password",encrypted);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
System.out.println("EncryptedData:"+encrypted);
System.out.println("DecryptedData:"+decrypted);
tv.setText("Encrypted:"+encrypted +"\n"+"Decrypted:"+decrypted);
The code works perfectly fine in this case, I get the same input as decrypted text.
But, when I try to use already encrypted string using the same method (AES) from the site http://aesencryption.net/ as shown in the screenshot:
And copy paste that encrypted text like:
decrypted = AESCrypt.decrypt("password","sttA+FbNm3RkTovjHI8CcAdStXiMl45s29Jqle+y+pA=");
And then run the code then I get error saying :
javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT
But when I use the decrypted text into the same site it works fine as shown in the screenshot below.
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
Probably due to the algorithm to convert the passphrase 'password' to SecretKeySpec
This is the algorithm in AESCrypt
private static SecretKeySpec GenerateKey (final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {    
final MessageDigest digest = MessageDigest.getInstance (HASH_ALGORITHM);
byte [] bytes = password.getBytes ("UTF-8");
digest.update (bytes, 0, bytes.length);
byte [] key = digest.digest ();
log ("SHA-256 key" key);
SecretKeySpec secretKeySpec = new SecretKeySpec (key, "AES");
secretKeySpec return;
}
And this is the (Java) example aesencryption.net
sha = MessageDigest.getInstance ("SHA-1");
key = sha.digest (key);
key = Arrays.copyOf (key, 16); // Use only first 128 bit
SecretKey = new SecretKeySpec (key, "AES");
The first one applies SHA256 hashing, and the second SHA-1 after completing up to 16 bytes, so the key is different.
I think you are encrypting and decrypting AES in the right way. You do not need to change anything.
But if you want to be compatible with aesencryption.net, you need to implement the same key generation algorithm. The code is not too good. I try to summarize
//Code from aesencryption.net
// Generate key
MessageDigest sha = null;
key = myKey.getBytes ("UTF-8");
sha = MessageDigest.getInstance ("SHA-1");
key = sha.digest (key);
key = Arrays.copyOf (key, 16); // Use only first 128 bit
SecretKey = new SecretKeySpec (key, "AES");
public static String encrypt (String strToEncrypt) {
Cipher cipher = Cipher.getInstance ("AES / ECB / PKCS5Padding");
     cipher.init (Cipher.ENCRYPT_MODE, SecretKey);
Base64.encodeBase64String return (cipher.doFinal (strToEncrypt.getBytes ("UTF-8"))));
}
public static String decrypt (String strToDecrypt) {
Cipher cipher = Cipher.getInstance ("AES / ECB / PKCS5PADDING");
cipher.init (Cipher.DECRYPT_MODE, SecretKey);
return new String (cipher.doFinal (Base64.decodeBase64 (strToDecrypt))));
}
I can also provide my own code extracted from an Android app witch requires to store private user data. Data is ciphered with an AES key protected with an user passphrase
public static String SIMMETRICAL_ALGORITHM = "AES";
//Generate cipher key with user provided password
private static String getPassphraseSize16(String key) {
if (TextUtils.isEmpty(key)) {
return null;
}
char controlChar = '\u0014';
String key16 = key + controlChar;
if (key16.length() < 16) {
while (key16.length() < 16) {
key16 += key + controlChar;
}
}
if (key16.length() > 16) {
key16 = key16.substring(key16.length() - 16, key16.length());
}
return key16;
}
//AES cipher with passphrase
public static byte[] encrypt(byte[] message, String passphrase)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
String passphrase16 = getPassphraseSize16(passphrase);
SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encoded = cipher.doFinal(message);
return encoded;
}
//AES decipher with passphrase
public static byte[] decrypt(byte[] encodedMessage, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
String passphrase16 = getPassphraseSize16(key);
SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte decoded[] = cipher.doFinal(encodedMessage);
return decoded;
}

Java AES Decryption: random chars & message at the end

I have a problem with decrypting a message using AES. At the end when I expect a message, e.g.
ala123
Instead of that I receive sth like:
...6�b}\7�k�8�vFP�8~%��_zժF��FW��O_e���ó������������ala123
The message I pass to encryption is built as:
cipher key is SHA-256 from AES_TOKEN
cipher IV is some characters, which are then stored in the message (at the beginnig)
decrypted message is wrapped up into Base64
The question is why at the end I eventually receive my expected message, but with a lot of rubbish chars at the beggining?
My encryption code is:
private static final String AES_TOKEN = "my_very_secret_token";
// encrypted is base64 string
public String decrypt(String encrypted) throws Exception {
byte[] decrypted = Base64.getDecoder().decode(encrypted);
return new String(aesDecrypt(decrypted), "UTF-8");
}
private byte[] aesDecrypt(byte[] message) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] token = MessageDigest.getInstance("SHA-256").digest(AES_TOKEN.getBytes());
SecretKeySpec secretKey = new SecretKeySpec(token, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(message, 16));
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
return cipher.doFinal(message);
}
It looks like you aren't removing the IV from the beginning of message after reading it in to iv. That would explain the garbage being at the start of the decrypted message.

AES Encryption Input Length Error javax.crypto.IllegalBlockSizeException

This is my code:
public class Encryption {
private static final String ALGO = "AES/CBC/PKCS5Padding";
private static final byte[] keyValue = new byte[]{'F','O','R','T','Y','T','W','O','F','O','R','T','Y','T','W','O'};
private static Key key = generateKey();
public static String encrypt(String DATA) throws Exception {
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE,key,new IvParameterSpec(c.getParameters().getParameterSpec(IvParameterSpec.class).getIV()));
byte[] encVal = c.doFinal(DATA.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public static String decrypt(String DATA) throws Exception {
System.out.println(DATA.length());
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(c.getParameters().getParameterSpec(IvParameterSpec.class).getIV()));
byte[] dencVal = c.doFinal(DATA.getBytes());
String decryptedValue = new BASE64Encoder().encode(dencVal);
return decryptedValue;
}
public static Key generateKey() {
Key key = new SecretKeySpec(keyValue,"AES");
return key;
}
}
And I'm getting this error:
Error:Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at Encryption.decrypt(Encryption.java:30)
at EncryptionTest.main(EncryptionTest.java:9)
What am I doing wrong?
AES/CBC/PKCS5Padding is a "block cipher" meaning in works on blocks of fixed size, 16 bytes in this case. Inputs of smaller size must be padded out with extra bytes for encryption to work.
Decryption, because it's working out output of an encryption operation, must already be a multiple of the block size. The exception is telling you that you have not provided correctly encrypted data because the input was not a multiple of the block size.
Decoding should always be the opposite of encoding so if you encode by doing "encrypt then base64-encode" then the decoding must be "base64-decode then decrypt". Your method is "decrypt then base64-encode" which is pretty clearly a mistake.
If you are using the returning value of the encrypt method, its not going to work.
You encrypt and then encode the result of the encryption. After that you try do decrypt the encoded value. You have to decode first and then try to decrypt.

Categories

Resources