I come with an issue related to JCE
.
Context
- SDK: JDK 1.8
- OS: Ubuntu 14
I have been asked to implement a component for decrypt java.lang.String
. The encrypted string is part of webservice response which we integrate with.
Webservice provider has provided to us with a binary file to be used to decrypt.
- ProviderDESedeWebservice.key.
They also informed the alogirthm:
- DESede/CBC/PKCS5Padding
String comes encoded in 64Base. So we have to decode it before to decrypt.
Once decrypted, I should get a xml message
My class
Based on this info, I have researched how to implement my component and here is what I have:
package org.mycompany.commons;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
//Apache commons IO
import org.apache.commons.io.IOUtils;
/**
* Componente de soporte para codificar y descodificar mensajes
*
* @author opentrends
*
*/
public final class EncryptHelper {
public static final String decrypt(final String encrypted, final String encoding)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
BadPaddingException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException {
//Mainly UTF-8
Charset charset = Charset.forName(encoding);
//Decoding binary.
byte[] base64CryptedMessageByteArr = Base64.getDecoder().decode(encrypted);
//Init of descipher
Cipher desCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[8]);
desCipher.init(Cipher.DECRYPT_MODE, generateSecretKey(charset),ivSpec);
//Decrypting binary
byte[] byteDecryptedTextByteArr = desCipher.doFinal(base64CryptedMessageByteArr);
String clearText = new String(byteDecryptedTextByteArr, encoding);
return clearText;
}
private final static Key generateSecretKey(Charset charset) throws IOException{
InputStream secretKeyFile = RACEEncrypter.class.getResourceAsStream("/DESedeRACE.key");
InputStreamReader secretKeyReader = new InputStreamReader(secretKeyFile);
byte[] scretKeyByteArr = IOUtils.toByteArray(secretKeyReader);
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(scretKeyByteArr));
return key;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- Key file (ProviderDESedeWebservice.key) is going to be in the classpath. At the moment I placed it at resources folder.
Issue
Executing decrypt() java throws an error:
java.security.InvalidKeyException: Invalid key length: 46 bytes
Ok I have understood that DESede keys can not be longer than 24 bytes. So I have tried this approach at the time of generating the key
...
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(scretKeyByteArr));
return key;
} catch (Exception e) {
e.printStackTrace();
}
return null;
Now Java throws:
javax.crypto.BadPaddingException: Given final block not properly padded
I kept trying different approachs and my next tried has benn to change the algorithm
Cipher desCipher = Cipher.getInstance("DESede/CBC/NoPadding");
Finally I get a binary that looks like this
Decrypted message:�.B ���;����[���u85�I���@M���㦬�����E��+S���^
But I have expected to get an XML.
Question
I think the question is obvious.
- What am I doing wrong?
- Do am I loading properly the key file? -- Answer:Yes. Problem is not here
- Do am I decoding properly the input string? -- Answer:Yes. Problem is not here
- Could secret key file be corrupted? Malformed? -- Answer:No. But it might not be the one I need
EDIT:
I have tested that web services encrypted responses can not be decrypted with the key we have. Key or algorithm might be modified by reasons why dont know and we were not aware of it