Java - Decryption : javax.crypto.BadPaddingException - java

I get this warning:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Any ideas what causes this? Here are my encryption and decryption code. I have looked at a variety of different answers on StackOverflow but I was unable to find one that actually works.
private static Cipher ecipher;
private static Cipher dcipher;
private static SecretKey key;
public static void Menu() {
try {
// generate secret key using DES algorithm
key = KeyGenerator.getInstance("DES").generateKey();
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
// initialize the ciphers with the given key
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (NoSuchAlgorithmException e) {
System.out.println("No Such Algorithm:" + e.getMessage());
return;
} catch (NoSuchPaddingException e) {
System.out.println("No Such Padding:" + e.getMessage());
return;
} catch (InvalidKeyException e) {
System.out.println("Invalid Key:" + e.getMessage());
return;
}
}
public static String encrypt(String WordToEncrypt) {
Menu();
try {
// encode the string into a sequence of bytes using the named charset
// storing the result into a new byte array.
byte[] utf8 = WordToEncrypt.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
// encode to base64
enc = BASE64EncoderStream.encode(enc);
System.out.println(new String(enc));
return new String(enc);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decrypt(String WordToDecrypt) {
Menu();
try {
// decode with base64 to get bytes
byte[] dec = BASE64DecoderStream.decode(WordToDecrypt.getBytes());
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

You call Menu once in the encryption code and once in the decryption code. Since you generate the key randomly for both encryption and decryption, the key will differ and your code will fail.
Don't keep Cipher instances around, preferably not even in fields, but certainly not in class fields. DES is old; too old. Use AES - using DES isn't any easier than AES.

Related

How can we do Triple Decryption in java?

I am using a MOL API for VOUCHER recharges. Which returns a PIN number in response is successful. That PIN number will be an encrypted text and I need to triple decrypt it!
I contacted the API support, They provided with the code below:
byte[] PinBytes = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
byte[] VectorBytes = Base64.decodeBase64(vectorKey.getBytes("utf-8"));
byte[] SecretKeyBytes = Base64.decodeBase64(secretKey.getBytes("utf-8"));
TripleDESProvider = CreateTripleDESCryptographicProvider(VectorBytes, SecretKeyBytes)
DecryptedBytes = TripleDESProvider.Decrypt(PinBytes)
Here VectorBytes and SecretKeyBytes are security keys provided by them and PinBytes are the response PIN number which is encrypted.
I googled while I was not able to get a correct solution with these three parameters. Any help, please?
I tried this:
try
{
String encryptedText = "FN0hbSrVzkqhe+w2rQefAQ==";
String vectorKey = "7EsBtzAJjMg=";
//32 bit key
String secretKey = "08061052989102040806105298910204";
byte[] PinBytes = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
byte[] VectorBytes = Base64.decodeBase64(vectorKey.getBytes("utf-8"));
byte[] SecretKeyBytes = Base64.decodeBase64(secretKey.getBytes("utf-8"));
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(SecretKeyBytes);
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;)
{
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(VectorBytes);
final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
//final byte[] encData = new sun.misc.BASE64Decoder().decodeBuffer(message);
final byte[] plainText = decipher.doFinal(PinBytes);
System.out.println(plainText.toString());
}
catch (java.security.InvalidAlgorithmParameterException e) { System.out.println("Invalid Algorithm"); }
catch (javax.crypto.NoSuchPaddingException e) { System.out.println("No Such Padding"); }
catch (java.security.NoSuchAlgorithmException e) { System.out.println("No Such Algorithm"); }
catch (java.security.InvalidKeyException e) { System.out.println("Invalid Key"); }
catch (BadPaddingException e) { System.out.println("Invalid Key");}
catch (IllegalBlockSizeException e) { System.out.println("Invalid Key");}
catch (UnsupportedEncodingException e) { System.out.println("Invalid Key");}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Error is Invalid KEY
The document they provide is;
Convert Encrypted Pin into Byte Array from Base64 format
PinBytes = ConvertFromBase64String ("FN0hbSrVzkqhe+w2rQefAQ==")
As Vector Key and Secret Key are provided in Base64 format, thus we need to convert both data into Byte Array as well
VectorBytes = ConvertFromBase64String ("xxxxxxxxx")
SecretKeyBytes = ConvertFromBase64String ("xxxxxxxxxxxx")
Please create your Triple DES Cryptographic Provider and set your IV byte array and Secret Key byte array into your Provider.
TripleDESProvider = CreateTripleDESCryptographicProvider(VectorBytes, SecretKeyBytes)
Please invokes Triple DES Provider decrypt method.
DecryptedBytes = TripleDESProvider.Decrypt(PinBytes)
Finally convert back decrypted bytes back to string.
ConvertToString(DecryptedBytes)
The result should be 8157151550.
I am not sure if this is the right approach but with AES encryption it works. They provided you the vector, use it to initialize the IVParameterSpec, then create Key object and Cipher instance:
// this is the encripted text
byte[] PinBytes = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
byte[] VectorBytes = Base64.decodeBase64(vectorKey.getBytes("utf-8"));
byte[] SecretKeyBytes = Base64.decodeBase64(secretKey.getBytes("utf-8"));
// initialize the vector with the one you receive
IvParameterSpec spec = new IvParameterSpec(VectorBytes);
// create the key. DESede should be correct, but if it doesn't work try also with DES
Key key = new SecretKeySpec(SecretKeyBytes, "DESede");
// Initialize the cipher
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
// decrypt the string
c.init(Cipher.DECRYPT_MODE, key, spec);
byte[] decodedDecryptedBytes = c.doFinal(PinBytes);
Base64 object i use is from apache common codec library, but you can use the library you want.
Finally, I Got this answer with same provided secretKey!!
try
{
byte[] PinBytes = Base64.decodeBase64(encryptedText);
byte[] VectorBytes = Base64.decodeBase64(vectorKey);
byte[] SecretKeyBytes = Base64.decodeBase64(secretKey);
// initialize the vector with the one you receive
IvParameterSpec spec = new IvParameterSpec(VectorBytes);
// create the key. DESede should be correct, but if it doesn't work try also with DES
Key key = new SecretKeySpec(SecretKeyBytes, "DESede");
// Initialize the cipher
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
// decrypt the string
c.init(Cipher.DECRYPT_MODE, key, spec);
byte[] decodedDecryptedBytes = c.doFinal(PinBytes);
return new String(decodedDecryptedBytes, "UTF-8");
}
catch (java.security.InvalidAlgorithmParameterException e) { System.out.println("Invalid Algorithm"); }
catch (javax.crypto.NoSuchPaddingException e) { System.out.println("No Such Padding"); }
catch (java.security.NoSuchAlgorithmException e) { System.out.println("No Such Algorithm"); }
catch (java.security.InvalidKeyException e) { System.out.println("InvalidKeyException : Invalid Key"); }
catch (BadPaddingException e) { System.out.println("BadPaddingException : Invalid Key");}
catch (IllegalBlockSizeException e) { System.out.println("IllegalBlockSizeException : Invalid Key");}
catch (UnsupportedEncodingException e) { System.out.println("UnsupportedEncodingException : Invalid Key");}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
The Mistake was doing this:
byte[] SecretKeyBytes = Base64.decodeBase64(secretKey.getBytes("utf-8"));
I don't know why this happens! But by removing that I got the answer!!

Android AES Encryption from C# to Java

I am converting my C# encryption code to Android.
I am facing issue like I am not able to encrypt the text as same as C#.
Below I copy paste both code.
Both are working code regarding using it you can use any password & any plain text .You will find both have different output.
C# CODE
System.security.Cryptography.RijndaelManaged AES = new System.Security.Cryptography.RijndaelManaged();
System.Security.Cryptography.MD5CryptoServiceProvider Hash_AES = new System.Security.Cryptography.MD5CryptoServiceProvider();
final MessageDigest Hash_AES = MessageDigest.getInstance("MD5");
String encrypted = "";
try {
byte[] hash = new byte[32];
byte[] temp = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass));
final byte[] temp = Hash_AES.digest(pass.getBytes("US-ASCII"));
Array.Copy(temp, 0, hash, 0, 16);
Array.Copy(temp, 0, hash, 15, 16);
AES.Key = hash;
AES.Mode = System.Security.Cryptography.CipherMode.ECB;
System.Security.Cryptography.ICryptoTransform DESEncrypter = AES.CreateEncryptor();
byte[] Buffer = System.Text.ASCIIEncoding.ASCII.GetBytes(input);
encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length));
} catch (Exception ex) {
}
return encrypted;
Here is my Android java code.
ANDROID JAVA CODE
private static String TRANSFORMATION = "AES/ECB/NoPadding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
byte[] encryptedData;
public RijndaelCrypt(String password,String plainText) {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
_password = new SecretKeySpec(digest.digest(password.getBytes()), ALGORITHM);
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_cipher.init(Cipher.ENCRYPT_MODE, _password);
encryptedData = _cipher.doFinal(text);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
return Base64.encodeToString(encryptedData,Base64.DEFAULT);
}
Should I need to use "US-ASCII" in pass or does it take it?
Use the same mode of operation: either ECB or CBC
Use the same character set: it's best to stick to "UTF-8"
Use the same key: in the C# code you're doubling the 128-bit key to 256 bits
When using CBC with a random IV, it is expected that the ciphertext differs for the same plaintext. The decryption is the operation that determines whether you succeeded.
Note that ECB is not semantically secure. Use CBC with a random IV. The IV doesn't have to be secret, so you can just prepend it to the ciphertext and slice it off before decryption.
It's better to use an authenticated mode like GCM or EAX or if it's not provided an encrypt-then-MAC scheme. It's hard to implement it correctly yourself so stick to some library that does this for you like RNCryptor.

Decrypt a string with DES in PHP that's been encrypted by Java

I've been banging my head against the wall trying to figure out exactly how to format everything to decrypt this string in PHP that's been encrypted in a custom Java class.
Here's the relevent functions from the Java class. The "salt" variable is a class variable byte array set earlier:
public DesEncrypter(String passPhrase) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt,
iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
.generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt,
iterationCount);
// Create the ciphers
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (java.security.InvalidAlgorithmParameterException e) {
} catch (java.security.spec.InvalidKeySpecException e) {
} catch (javax.crypto.NoSuchPaddingException e) {
} catch (java.security.NoSuchAlgorithmException e) {
} catch (java.security.InvalidKeyException e) {
}
}
public String encrypt(String str) {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
} catch (javax.crypto.BadPaddingException e) {
} catch (IllegalBlockSizeException e) {
} catch (UnsupportedEncodingException e) {
}
return null;
}
public String decrypt(String str) {
try {
// Decode base64 to get bytes
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch( Exception ex) {
ex.printStackTrace(System.err);
}
return null;
}
And here's what I have so far in PHP (FYI, I'm using this encryption library in PHP https://github.com/phpseclib/phpseclib):
$app->get('/decrypt', function () use ($app) {
$data = '3aCRLRd3srA/QF4MQb0D+P==';
$salt = pack('nvc*', 0xB7, 0x9A, 0xC1, 0x34, 0x26, 0x89, 0xW3, 0x30);
$secret = "secret";
$keyLength = 16;
$cipher = new Crypt_DES(CRYPT_DES_MODE_CBC);
$cipher->setPassword($secret, 'pbkdf2', 'md5', $salt, $keyLength);
var_dump($cipher->decrypt($data));
});
Right now it's dumping out a bunch of binary, which I've tried base64_decoding, but that doesn't do anything either.
If key.getAlgorithm() is "DES" then you need to provide a fully specified Cipher name like "DES/CBC/PKCS5Padding".
You will also need to provide the IV if it is non-null. Usually the IV is prepended to the ciphertext.
You can get the IV with cipher.getIV() and set with $cipher->setIV('...');.

InvalidKeyException java.security.InvalidKeyException: No installed provider supports this key: (null)

I have two classes, one is main class and another is the implementation of AES.
However, in my AES class i have a method to decrypt a string, but whenever i run it, it gives an exception
My encryption method works just fine but my decryption method doesn't work as expected.
The code
private Cipher aesCipherForDecryption;
String strDecryptedText = new String();
public String decryptAES(final String ciphertext) {
try {
aesCipherForDecryption = Cipher.getInstance("AES/CBC/PKCS5PADDING");
aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iV));
byte[] byteDecryptedText = aesCipherForDecryption.doFinal(byteCipherText);
strDecryptedText = new String(byteDecryptedText);
} catch (IllegalBlockSizeException e) {
System.out.print("IllegalBlockSizeException " +e);
} catch (BadPaddingException e) {
System.out.print("BadPaddingException "+e);
} catch (NoSuchAlgorithmException e) {
System.out.print("NoSuchAlgorithmException "+ e);
} catch (NoSuchPaddingException e) {
System.out.print("NoSuchPaddingException "+e);
} catch (InvalidKeyException e) {
System.out.print("InvalidKeyException "+e);
} catch (InvalidAlgorithmParameterException e) {
System.out.print("InvalidAlgorithmParameterException "+e);
}
System.out.println("\nDecrypted Text message is " + strDecryptedText);
return strDecryptedText;
}
The error this method outputs is
InvalidKeyException java.security.InvalidKeyException: No installed provider supports this key: (null)
UPDATE #1:
So i have updated the code as the following
public String decryptAES(byte[] ciphertext) {
String strDecryptedText = new String();
try {
byte[] byteDecryptedText = aesCipherForDecryption.doFinal(ciphertext);
strDecryptedText = new String(byteDecryptedText);
} catch (IllegalBlockSizeException e) {
System.out.print("IllegalBlockSizeException "+e);
e.printStackTrace();
} catch (BadPaddingException e) {
System.out.print("BadPaddingException "+e);
e.printStackTrace();
}
System.out.println("\nDecrypted Text message is " + strDecryptedText);
return strDecryptedText;
}
and in the main class i have this line
byte [] byteciphertext = ciphertext.getBytes();
just to convert the string to bytes
is it correct? i'm still having
IllegalBlockSizeException javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipherjavax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
Could someone help me fix this issue?
Thank you.
secretKey is clearly null.
Other problems:
You aren't using the input parameter cipherText.
The input parameter cipherText should be a byte[], not a String: cipher text is binary, and String is not a container for binary data.
The result string strDecryptedText should be a local variable, not a member variable.

Missing argument while converting RijndaelManaged in java

while converting a .net code of decryption to java I got an exception
Exception in thread "main" java.lang.IllegalArgumentException: Missing argument
at javax.crypto.spec.SecretKeySpec.<init>(DashoA13*..)
at com.motorola.gst.DecryptTest3.Decrypt(DecryptTest3.java:90)
at com.motorola.gst.DecryptTest3.main(DecryptTest3.java:36)
well I'm trying it for the first time both decryption and converting a .net code to java
here is the .net code that I'm trying to convert
private static string Decrypt(string encryptedText, string completeEncodedKey, int keySize)
{
RijndaelManaged aesEncryption = new RijndaelManaged();
aesEncryption.KeySize = keySize;
aesEncryption.BlockSize = 128;
aesEncryption.Mode = CipherMode.CBC;
aesEncryption.Padding = PaddingMode.PKCS7;
aesEncryption.IV = Convert.FromBase64String(ASCIIEncoding.UTF8.GetString(Convert.FromBase64String(completeEncodedKey)).Split(',')[0]);
aesEncryption.Key = Convert.FromBase64String(ASCIIEncoding.UTF8.GetString(Convert.FromBase64String(completeEncodedKey)).Split(',')[1]);
ICryptoTransform decrypto = aesEncryption.CreateDecryptor();
byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);
return ASCIIEncoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length));
}
I went through many posts and found Decrypting bytes encrypted by .NET's RijndaelManaged using Java is more related to my case.
I followed these and wrote my decrypt function as ::
private static String Decrypt(String encryptedText, String completeEncodedKey,int keySize) {
//get completeEncodedKey in bytes and then to string
String decodedcompleteEncodedKey = StringUtils.newStringUtf8(Base64.decodeBase64(completeEncodedKey));
System.out.println("Decoded completeEncodedKey Key :: "+decodedcompleteEncodedKey);
int indexComma = decodedcompleteEncodedKey.indexOf(',');
System.out.println("COmma Index :: "+indexComma);
String IV = decodedcompleteEncodedKey.substring(0, indexComma);
String Key = decodedcompleteEncodedKey.substring(indexComma+1,decodedcompleteEncodedKey.length());
System.out.println("IV::: "+IV);
System.out.println("Key::: "+Key);
byte[] sessionKey = null;
byte[] iv = null ;
byte[] plaintext = encryptedText.getBytes();
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
byte[] ciphertext = cipher.doFinal(plaintext);
} catch (IllegalBlockSizeException e) {
System.out.println("IllegalBlockSizeException");
e.printStackTrace();
} catch (BadPaddingException e) {
System.out.println("BadPaddingException");
e.printStackTrace();
} catch (InvalidKeyException e) {
System.out.println("InvalidKeyException");
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
System.out.println("InvalidAlgorithmParameterException");
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
System.out.println("NoSuchPaddingException");
e.printStackTrace();
}
return null;
}
but now I'm getting Exception in thread "main" java.lang.IllegalArgumentException: Missing argument.
can anyone help me getting these errors fixed.
any help would be appreciated.
thanks!!
For me the problem was calling new SecretKeySpec(sessionKey, "AES") with sessionKey = null.

Categories

Resources