1

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

Laiv
  • 306
  • 3
  • 21
  • 1
    *"secret key pair"* is not something that exists as a concept. We have key pairs for asymmetric crypto (public & private key) and then we have a single secret key for symmetric crypto. – Artjom B. Sep 08 '16 at 18:15
  • 1
    A secret key when stored in binary form may consist of arbitrary bytes which don't have to correspond to *any* valid character encoding. The same is true for the ciphertext and the IV (if you're using CBC mode, you have to keep track of the IV! It isn't a secret value and can be freely sent to the decryptor). – Artjom B. Sep 08 '16 at 18:18
  • @ArtjomB I have checked the link. If I'm right, my .key file would be the TOKEN_KEY and I have to read it to get my token Now I have to validate if I'm do it right. Then I have to set IV to the Cipher. I see that in order to instanciate IV we have to set a byte array with an specific length. Is this length related to the algorithm? Or to the key length (in bytes)? – Laiv Sep 08 '16 at 19:07
  • 3DES supports key sizes of 8, 16 and 24 *bytes* (not all of those bits are actually used). It has a fixed block size of 8 *bytes* which is also the size of the IV in CBC mode. – Artjom B. Sep 08 '16 at 19:16
  • Ok. Then I will test informing IV with these byte length and make sure I do read well the key file. – Laiv Sep 08 '16 at 19:19
  • Use an `FileInputStream` if you want to read binary data. Use `InputStreamReader` if you want to read textual data. Since your key size seems wrong, perhaps you can add your key file here (only if it is a test key). – Artjom B. Sep 08 '16 at 19:23
  • I will test all your hints first. If get stuck I will share it. – Laiv Sep 08 '16 at 19:28
  • Finally we have found what was the problem. Web service messages can not be decrypted with the key they gave to us. Key works, because we can cipher/decipher strings. I have also added IV to Cipher configuration as @ArtjomB. pointed and works as intended. Its byte length with DESede is 8 bytes (Other length raises `java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 8 bytes long` errors). Thank you very much @ArtjomB. – Laiv Sep 09 '16 at 08:21

0 Answers0