Java BadPaddingException "Given final block not properly padded" after several hours - java

Like many others over time I'm having issues with encryption in a system I'm maintaining.
Process A generates some encrypted text which later Process B must decode. They share the same code for this purpose which is as below:
public class DesEncryption {
private Cipher mEcipher;
private Cipher mDcipher;
private byte[] salt = {
(byte) 0x08, (byte) 0x90, (byte) 0xA6, (byte) 0x4B,
(byte) 0xBB, (byte) 0x51, (byte) 0x3C, (byte) 0xDE
};
// Iteration count
int iterationCount = 19;
DesEncryption(String passPhrase) throws EncryptionException {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWithMD5AndDES").generateSecret(keySpec);
mEcipher = Cipher.getInstance(key.getAlgorithm());
mDcipher = Cipher.getInstance(key.getAlgorithm());
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
// Create the ciphers
mEcipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
mDcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (java.security.InvalidAlgorithmParameterException e) {
throw new EncryptionException(e);
} catch (java.security.spec.InvalidKeySpecException e) {
throw new EncryptionException(e);
} catch (javax.crypto.NoSuchPaddingException e) {
throw new EncryptionException(e);
} catch (java.security.NoSuchAlgorithmException e) {
throw new EncryptionException(e);
} catch (java.security.InvalidKeyException e) {
throw new EncryptionException(e);
}
}
public String encrypt(String str) throws EncryptionException {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = mEcipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
} catch (javax.crypto.BadPaddingException e) {
throw new EncryptionException(e);
} catch (IllegalBlockSizeException e) {
throw new EncryptionException(e);
} catch (UnsupportedEncodingException e) {
throw new EncryptionException(e);
} catch (java.io.IOException e) {
throw new EncryptionException(e);
}
}
public String decrypt(String str) throws EncryptionException {
try {
// Decode base64 to get bytes
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
// Decrypt
byte[] utf8 = mDcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (javax.crypto.BadPaddingException e) {
throw new EncryptionException(e);
} catch (IllegalBlockSizeException e) {
throw new EncryptionException(e);
} catch (UnsupportedEncodingException e) {
throw new EncryptionException(e);
} catch (java.io.IOException e) {
throw new EncryptionException(e);
}
}
}
The two processes run on separate servers, both Centos (5.3 for process A, 6.4 for Process B)
There are no apparent issues with Process A - The string to be encoded is done so reliably.
When process B starts, everything appears to be fine. It decodes and decrypts the required strings correctly.
At some point over the course of about 24 hours however, this stops working. At this point, I get the 'BadPaddingException "Given final block not properly padded"' Exceptions. This then continues every time the code is executed with any encoded string until such time as the process is restarted, at which point everything works again, including decoding strings that failed moments before.
At the time when this goes wrong, calling decrypt(encrypt("test")) will fail too so this seems to be unrelated to the actual encrypted value and more to do with the encryption and decryption getting out of sync some how.
If anyone could offer any suggestions about where I may be going wrong with this I'd appreciate it.
Many thanks in advance...
Andrew

Related

How can I encrypt a large message with a 512 RSA key?

I want to encrypt a large message and perform a measurement with different key sizes.
public static void generate(int keylen)
{
KeyPairGenerator keygen = null;
try
{
keygen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
keygen.initialize(keylen);
key = keygen.generateKeyPair();
}
When I select 512 as the key size, my program throws the following error message: javax.crypto.IllegalBlockSizeException: Data must not be longer than 53 bytes
public static byte[] encrypt(String message, PublicKey pk)
{
Cipher cipher = null;
try
{
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pk);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] cipherText = null;
try {
ciphertext = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return cipherText;
}
I know that the RSA algorithm can only encrypt data that has a maximum byte length of the RSA key length in bits divided with eight minus eleven padding bytes, i.e. number of maximum bytes = key length in bits / 8 - 11.
I also know that 512 is not secure. I want to measure different key sizes with their respective time e.g. 512, 1024, 2048, 4096.....
Is there a way to encrypt the message without using a hybrid method because I also need to measure the time.
I read that there is a method to divide the message into blocks. I am not sure how this works exactly.

Java to VB.NET AES Encryption

I have this code here which I'm having difficulty converting to VB.NET and hoping someone who give me a hand with it.
I'm having difficulty with the part on the cipher - I have tried Googling but was unable to find a clear resource explaining it in simple terms. (I don't know how to proceed with it as it seems there's no equivalent for it??)
I have almost no knowledge of java hence am trying to google and find out what each part means and convert it after. Hope someone would be able to point me in the right direction!
public static byte[] decryptPDF(String password, String filePath) {
try {
byte[] headerSaltAndCipherText = Base64.decode(IOUtils.toString(new FileInputStream(new File(filePath)), "UTF-8").toString().getBytes("UTF-8"), 0);
byte[] salt = Arrays.copyOfRange(headerSaltAndCipherText, 8, 16);
byte[] encrypted = Arrays.copyOfRange(headerSaltAndCipherText, 16, headerSaltAndCipherText.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[][] keyAndIV = EVP_BytesToKey(32, aesCBC.getBlockSize(), MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1);
aesCBC.init(2, new SecretKeySpec(keyAndIV[0], "AES"), new IvParameterSpec(keyAndIV[1]));
return aesCBC.doFinal(encrypted);
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (NoSuchPaddingException e2) {
e2.printStackTrace();
return null;
} catch (InvalidAlgorithmParameterException e3) {
e3.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e4) {
e4.printStackTrace();
return null;
} catch (IllegalBlockSizeException e5) {
e5.printStackTrace();
return null;
} catch (BadPaddingException e6) {
e6.printStackTrace();
return null;
} catch (InvalidKeyException e7) {
e7.printStackTrace();
return null;
}
}
What I've tried so far is...
Public Shared Function decryptPDF(ByVal password As String, ByVal fileAsString As String) As Byte()
Try
Dim headerSaltAndCipherText() As Byte = System.Convert.FromBase64String(fileAsString)
Dim salt() As Byte = headerSaltAndCipherText.Skip(7).Take(8)
Dim encrypted() As Byte = headerSaltAndCipherText.Skip(15).Take(headerSaltAndCipherText.Length)
Dim aesCBC As Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
Dim keyAndIV() As Byte = EVP_BytesToKey(32, aesCBC.getBlockSize, MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1)
aesCBC.init(2, New SecretKeySpec(keyAndIV(0), "AES"), New IvParameterSpec(keyAndIV(1)))
Return aesCBC.doFinal(encrypted)
End Try
End Function
Try that
Public Shared Function decryptPDF(ByVal password As String, ByVal filePath As String) As Byte()
Try
Dim headerSaltAndCipherText() As Byte = Base64.decode(IOUtils.toString(New FileInputStream(New File(filePath)), "UTF-8").toString.getBytes("UTF-8"), 0)
Dim salt() As Byte = Arrays.copyOfRange(headerSaltAndCipherText, 8, 16)
Dim encrypted() As Byte = Arrays.copyOfRange(headerSaltAndCipherText, 16, headerSaltAndCipherText.length)
Dim aesCBC As Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
Dim keyAndIV(,) As Byte = EVP_BytesToKey(32, aesCBC.getBlockSize, MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1)
aesCBC.init(2, New SecretKeySpec(keyAndIV(0), "AES"), New IvParameterSpec(keyAndIV(1)))
Return aesCBC.doFinal(encrypted)
Catch e As IOException
e.printStackTrace
Return Nothing
Catch e2 As NoSuchPaddingException
e2.printStackTrace
Return Nothing
Catch e3 As InvalidAlgorithmParameterException
e3.printStackTrace
Return Nothing
Catch e4 As NoSuchAlgorithmException
e4.printStackTrace
Return Nothing
Catch e5 As IllegalBlockSizeException
e5.printStackTrace
Return Nothing
Catch e6 As BadPaddingException
e6.printStackTrace
Return Nothing
Catch e7 As InvalidKeyException
e7.printStackTrace
Return Nothing
End Try
End Function

How can I store hashed password in sqlite android

protected static byte[] getHashedKey(String password,String MODE)throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
saltIV = new byte[48];
salt = new byte[32];
ivBytes =new byte[16];
if(MODE.equals("CREATE_VAULT")){
//generate salt ,iv & save them
salt = generateSalt();
ivBytes = generateIV();
System.arraycopy(salt, 0, saltIV, 0, salt.length);
System.arraycopy(ivBytes, 0, saltIV, salt.length, ivBytes.length);
//save salt & iv
//FileOutputStream saltIvOutFile = new FileOutputStream("C:\\saltIv.ats");
//saltIvOutFile.write(saltIV);
//saltIvOutFile.close();
}
if(MODE.equals("OPEN_VAULT")){
FileInputStream saltIvInFile = new FileInputStream("C:\\saltIv.ats");
saltIvInFile.read(saltIV);
saltIvInFile.close();
System.arraycopy(saltIV, 0, salt, 0, salt.length);
System.arraycopy(saltIV, salt.length, ivBytes, 0, ivBytes.length);
}
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
return secretKey.getEncoded();
}
this is where the hashed password gets generated and
try {
String finalKey = Arrays.toString(androCrypter.getHashedKey(v.password,"CREATE_VAULT"));
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
boolean vaultCreationSuccessful = new TableController(context).addNewVault(finalKey,v.vaultName,v.algorithm);
this is where I save the hash as string and insert it to database
but it never gets saved.The sqlite column is TEXT type.I came to know that sqlite supports directly saving byte array so I tried with byte[] also but same result,no entry in database.There is nothing wrong with addVault() code as I have checked it with other normal string and all,it works just fine.
Here is the code
protected boolean addNewVault(String finalKey,String vaultName,String algorithm) {
ContentValues values = new ContentValues();
values.put("Vault_Name", vaultName);
values.put("KEY", finalKey);
values.put("Algorithm", algorithm);
SQLiteDatabase db = this.getWritableDatabase();
boolean createSuccessful = db.insert(DATABASE_NAME, null, values) > 0;
db.close();
return createSuccessful;
}
But in this case I cant get it to work.Nothing gets saved.I also read about BLOB but I think its not needed as because byte[] is supported in sqlite.
What is wrong ?
Any help/suggestion would be really appreciated.Thank you.
NOTE:Please ignore the FileInputStream and FileOutputtream lines in getHashedKey();
EDIT:
I just figured out that this
try {
finalKey = Arrays.toString(androCrypter.getHashedKey(v.password,"CREATE_VAULT"));
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
code is not getting executed that is the problem. I have created another class just to check if it works there and it does.
Tried another method and calling it like finalKey= getFinalKey(v.password) and this method contains the above code but that does not work.
I am completely out of clue.Please help.
What I would do is to convert the "byte[]" to String:
String hashAsString = new String(hashAsBytes,"UTF-8");
Where "hashAsBytes" is the the resulting of "getHashedKey", and "hashAsString" is your byte array converted to a String.
Then you just save the "hashAsString" in your DB, as you see fit.
Then to compare hashes:
public boolean compareHashes(String hashInDB, String hashNew){
return hashInDB.equals(hashNew);
}
This method will return TRUE if your hashInDB is equal to the new hash you have just calculated. In case the hashes do not match it will return FALSE.
Hope this helps!
Best, Federico.

Android exception java.io.IOException: last block incomplete

I am working on decrypting a binary file encrypted in C# using Rijndael encryption method. The file is copied to an android device. The decryption logic works fine when run in a java based desktop test program. But it throws java.io.IOException: last block incomplete when run in android. I am using the code below.
public static void Decrypt(String fileIn, String fileOut, byte[] key, byte[] IV, long offset)
{
// First we are going to open the file streams
FileInputStream fsIn;
try
{
fsIn = new FileInputStream(fileIn);,,
FileOutputStream fsOut = new FileOutputStream(fileOut);
// create cipher object
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(IV));
// create the encryption stream
CipherInputStream cis = new CipherInputStream(fsIn, cipher);
// set a buffer and keep writing to the stream
int bufferLen = KiloByte;
byte[] buffer = new byte[bufferLen];
int bytesRead = 0;
// read a chunk of data from the input file
while ( (bytesRead = cis.read(buffer, 0, bufferLen)) != -1)
{
// write to file
fsOut.write(buffer, 0, bytesRead);
}
fsOut.flush();
// close streams
fsOut.close();
cis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
The key is generated by using the function
public static byte[] GetKey(String password, byte[] IV, int length)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Length is kept 16 to make it compatible with all platforms
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec ks = new PBEKeySpec(password.toCharArray(), IV, 1000, length*8);
SecretKey s = f.generateSecret(ks);
Key k = new SecretKeySpec(s.getEncoded(),"AES");
return k.getEncoded();
}
I have gone through many posts on internet related to the topic. Based on that, I have made sure that I use byte array rather String. But still getting this issue.

Encrypt and decrypt with AES and Base64 encoding

I have following program for encrypting data.
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Test {
private static final String ALGORITHM = "AES";
private static final byte[] keyValue = "ADBSJHJS12547896".getBytes();
public static void main(String args[]) throws Exception {
String encriptValue = encrypt("dude5");
decrypt(encriptValue);
}
/**
* #param args
* #throws Exception
*/
public static String encrypt(String valueToEnc) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
System.out.println("encValue length" + encValue.length);
byte[] encryptedByteValue = new Base64().encode(encValue);
String encryptedValue = encryptedByteValue.toString();
System.out.println("encryptedValue " + encryptedValue);
return encryptedValue;
}
public static String decrypt(String encryptedValue) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] enctVal = c.doFinal(encryptedValue.getBytes());
System.out.println("enctVal length " + enctVal.length);
byte[] decordedValue = new Base64().decode(enctVal);
return decordedValue.toString();
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
return key;
}
}
Here I am getting the following out put with exception?
valueToEnc.getBytes().length 5
encValue length16
encryptedValue [B#aa9835
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
Can some one explain me the cause? Why its only saying when decrypting that length should be 16. Doesn't it convert to 16 as like encrypting with the doFinal method.
And as the exception says "how to decrypting without padded cipher?"
Your Order for encrypt: getBytes, encrypt, encode, toString
Your Order for decrypt(Wrong*): getBytes, decrypt, decode, toString
Two problems:
As someone already mentioned you should reverse the order of operations for decryption. You are not doing that.
encrypt gives you 16 bytes, encode 24 bytes, but toString gives 106 bytes. Something to do with invalid chars taking up additional space.
Note: Also, you don't need to call generateKey() twice.
Fix problem #1 by using the reverse order for decryption.
Correct order for decrypt: getBytes, decode, decrypt, toString
Fix problem #2 by replacing xxx.toString() with new String(xxx). Do this in both the encrypt and decrypt functions.
Your decrypt should look like this:
c.init(Cipher.DECRYPT_MODE, key)
val decodedValue = new Base64().decode(encryptedValue.getBytes())
val decryptedVal = c.doFinal(decodedValue)
return new String(decryptedVal)
This should give you back "dude5"
The line
String encryptedValue = encryptedByteValue.toString();
is the problem. The type of encryptedByteValue is byte[] and calling toString on it isn't what you want to do there. Instead try
String encryptedValue = Base64.getEncoder().encodeToString(encValue);
Then use Base64.decodeBase64(encryptedValue) in decrypt. You must do that prior to attempting to decrypt though. You must undo the operations in the reverse order of the encrypt method.
Fundamentally, there is an asymmetry between your encrypt function and your decrypt function. When you encrypt you perform an AES encrypt and then a base64 encode, when you decrypt you don't first undo the base64 encoding step.
I think that there's something wrong with your base64 encoding as well as [ shouldn't appear in a base64 encoded string.
Looking at the documentation for org.apache.commons.codec.binary.Base64 you should be able to do this on encode:
String encryptedValue = Base64.encodeBase64String(encValue);
and this on decode:
byte[] encValue = Base64.decodeBase64(encryptedValue);
Where are you getting a version of apache codec that has encodeToString or encodeBase64String?
I downloaded 1.5 from the apache site and while it says in the documentation that these methods exist, they don't show up when you do code completion and they create an unknown method when you provide them.
I was able to do:
byte raw[] = md.digest(); //step 4
byte hashBytes[] = Base64.encodeBase64(raw); //step 5
StringBuffer buffer = new StringBuffer();
for( int i=0; i<hashBytes.length; i++ )
buffer.append(hashBytes[i]);
return buffer.toString(); //step 6
And then the string that I obtained was very long, BUT it decrypted correctly.
I don't think this is the "right" way to do things, but can't find the methods that the documentation says are there.
That was alright, you just needed to
1) Use new String instead of toString() since toString() doesn't return what you need here (in both cases, encryption and decryption)
2) you need to decode first since the value is encode in base64.
I came across this thread but it took sometime to find out the actual point..I am posting my code for rest of the people who come across this issue.
public abstract class EncryptionDecryption {
static byte[] key = "!##$!##$%^&**&^%".getBytes();
final static String algorithm="AES";
public static String encrypt(String data){
byte[] dataToSend = data.getBytes();
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k = new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.ENCRYPT_MODE, k);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedData = "".getBytes();
try {
encryptedData = c.doFinal(dataToSend);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedByteValue = new Base64().encode(encryptedData);
return new String(encryptedByteValue);//.toString();
}
public static String decrypt(String data){
byte[] encryptedData = new Base64().decode(data);
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k =
new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.DECRYPT_MODE, k);
} catch (InvalidKeyException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] decrypted = null;
try {
decrypted = c.doFinal(encryptedData);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(decrypted);
}
public static void main(String[] args){
String password=EncryptionDecryption.encrypt("password123");
System.out.println(password);
System.out.println(EncryptionDecryption.decrypt(password));
}
}
I have replaces line in example:
String encryptedValue = encryptedByteValue.toString();
with next one:
String encryptedValue = new String(encryptedByteValue);
All works fine!

Categories