Question

I am using the following code for a my sampled 3DES encryption I am using:

package Algorithms;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class MyDES {
    public static String encrypt(String pass,String plainText) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        byte[] key = pass.getBytes("UTF-8"); //get byte arrays of the given password
        MessageDigest sha = MessageDigest.getInstance("SHA-1"); //get SHA-1 hashing instance
        key=sha.digest(key); //has the given password
        key=Arrays.copyOf(key,24);//take the first 16 bytes as the key for DES encryption

        SecretKeySpec sks = new SecretKeySpec(key, "DESede");//key spec for 3-DES
        Cipher c = Cipher.getInstance("DESede");//get an instance of 3DES
        c.init(Cipher.ENCRYPT_MODE,sks); //initialize 3DES to encrypt mode with given parameters
        byte[] cipherTextBytes = c.doFinal(plainText.getBytes()); //encrypt

        System.out.println("key used: "+new String(key)+" cipher generated "+new String(cipherTextBytes));
        StringBuffer cipherText= new StringBuffer();
        for(int i=0;i<cipherTextBytes.length;i++)
        {
            cipherText.append(Integer.toHexString(cipherTextBytes[i]));
        }

        System.out.println("Final Cipher returned: "+cipherText.toString());
        return cipherText.toString();
    }

    public static String decrypt(String pass,String cipherText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        System.out.println("Initially in decryption-> pass:"+pass+" cipher: "+cipherText);
        byte[] byteArray = new byte[cipherText.length() / 2];
        int j=0;
        for(int k=0;k<cipherText.length()-1;k+=2)
        {
            String o= cipherText.substring(k,k+2);
            int dec = Integer.parseInt(o,16);
            byteArray[j++] = (byte)dec;
        }

        String plainText="";
        byte[] key = pass.getBytes("UTF-8");
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        key=sha.digest(key);
        key=Arrays.copyOf(key,24);
        System.out.println("\nkey obtained: "+new String(key)+"\n Later cipher text:-> "+new String(byteArray));

        SecretKeySpec sks = new SecretKeySpec(key, "DESede");
        Cipher c = Cipher.getInstance("DESede");
        c.init(Cipher.DECRYPT_MODE,sks);
        plainText = new String(c.doFinal(byteArray));
        return plainText;
    }

}

Here I am trying to take a password, hash it using SHA-1 and then use the generated has as a key to my 3DES. The generated cipher is being converted to hexadecimal representation as I having trouble saving and retrieving the strange characters in the cipher.

In decryption I am converting the cipher from hexadecimal to normal string again and then decrypting it. But I am getting a javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher Exception. Any idea where I am wrong?

Was it helpful?

Solution

Ah i think i got it. Try to simplify your code a bit, is hard to read. Avoid using strings and work as much as you can with arrays, when you have to work with binary data is better to use byte arrays.

Isolate the problems! Split your program in smaller functions that does simpler task.

You can use a standard Base64 encoder to do that. See http://www.docjar.com/docs/api/sun/misc/BASE64Encoder.html Base64 is of course shorter than hex encoding.

If you want to go on with the HEX conversion try to use these functions i found on google: http://www.developerfeed.com/javacore/blog/how-convert-hex-string-bytes-and-viceversa-java

I tried to simplify the code a little. Instead of new sun.misc.BASE64Encoder().encode() or decode() you can use the new encoding functions you are going to write.

private static byte[] getPassKey(String pass)
{
    byte[] passKey = pass.getBytes("UTF-8"); //get byte arrays of the given password
    byte[] shaKey = MessageDigest.getInstance("SHA-1").digest(passKey); 
    return Arrays.copyOf(shaKey,24);
}

public static String encrypt(String pass, String plainText) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{

    Cipher desCipher = Cipher.getInstance("DESede");
    desCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getPassKey(pass), "DESede")); 

    byte[] cipherTextBytes = desCipher.doFinal(plainText.getBytes());
    String encoded = new sun.misc.BASE64Encoder().encode(cipherTextBytes);

    return encoded;
}

public static String decrypt(String pass,String cipherText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{

    byte[] decoded = new sun.misc.BASE64Encoder().decode(cipherText);

    Cipher desCipher = Cipher.getInstance("DESede");
    desCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getPassKey(pass), "DESede"));
    plainText = new String(desCipher.doFinal(decoded));
    return plainText;
}

Not tested, just written by scratch in notepad.

OTHER TIPS

The problem is hidden under several layers.

    StringBuilder sb = new StringBuilder();
      ...
        sb.append((char)dec);

So you try to assemble the raw binary data by calling StringBuilder.Append(char). Well, what does that do?

The docs for StringBuilder.Append(char) say "The overall effect is exactly as if the argument were converted to a string by the method String.valueOf(char) and the character in that string were then appended to this character sequence."

Okay, so what does the documentation for String.valueOf(char) say? I'm glad you asked. It says it "Returns: a String of length 1 containing as its single character the argument c." (And you can see, the return type is 'String'.)

Ahh, but how does a String value work? Well, let's check the documentation on that. It says, "A String represents a string in the UTF-16 format in which supplementary characters are represented by surrogate pairs (see the section Unicode Character Representations in the Character class for more information). Index values refer to char code units, so a supplementary character uses two positions in a String."

So that's the problem. You are converting the raw binary ciphertext into UTF-16 characters and surrogate pairs, which is certainly not what you want.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top