2

I wonder if you can help me to understand why my decrypt method gives strange characters. Specifically, in this case, I get characters similar to

�����c~�+�J*zC�iV�-��&�_l��*.

Here is my code:

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import javax.crypto.*;
import java.security.*;
import java.util.Arrays;
import javax.crypto.spec.*;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;

import org.apache.commons.codec.binary.Hex;

public class AESCrypto2 {

private Cipher AEScipher;
private KeyGenerator AESgen;
private SecretKeySpec AESkey;
private SecretKeySpec decodeKey;
private String hexDecodeKey;
private String decodeKey64;
private byte[] cipherData;
private String msg;
private String encMsg;

public static void main(String[] args) {
    try {
        AESCrypto2 a = new AESCrypto2();
        a.encrypt("Hello!");
        try {
            a.decrypt(a.getEncryptedMsg(), a.getDecodeKey());
        } catch (DecoderException ex) {
            ex.printStackTrace();
        }
    } catch (NoSuchAlgorithmException ex) {
        ex.printStackTrace();
    } catch (NoSuchPaddingException ex) {
        ex.printStackTrace();
    } catch (InvalidKeyException ex) {
        ex.printStackTrace();
    } catch (UnsupportedEncodingException ex) {
        ex.printStackTrace();
    } catch (IllegalBlockSizeException ex) {
        ex.printStackTrace();
    } catch (BadPaddingException ex) {
        ex.printStackTrace();
    }

}

public AESCrypto2() throws NoSuchAlgorithmException, NoSuchPaddingException,
        UnsupportedEncodingException {
    AESgen = KeyGenerator.getInstance("AES");
    AESgen.init(128);
    AESkey = (SecretKeySpec) AESgen.generateKey();
    decodeKey = new SecretKeySpec(AESkey.getEncoded(), "AES");
    hexDecodeKey = keyToString(decodeKey);
    AEScipher = Cipher.getInstance("AES/ECB/NoPadding");
}

public AESCrypto2(String msg) throws NoSuchAlgorithmException,
        NoSuchPaddingException, InvalidKeyException,
        UnsupportedEncodingException, IllegalBlockSizeException,
        BadPaddingException {
    this();
    encrypt(msg);
}

public String encrypt(String msg) throws NoSuchAlgorithmException,
        InvalidKeyException, UnsupportedEncodingException,
        IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
    AEScipher.init(Cipher.ENCRYPT_MODE, AESkey);
    cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8")));

    this.msg = msg;
    encMsg = stringToHex(new String(cipherData));
    return encMsg;
}

public String decrypt(String msg, String hexDecodeKey) throws
        InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException, UnsupportedEncodingException,
        NoSuchAlgorithmException, NoSuchPaddingException, DecoderException {
    AEScipher.init(Cipher.DECRYPT_MODE, stringToKey(hexDecodeKey));
    byte[] decryptedData = AEScipher.doFinal(handleString(hexToString(msg).getBytes("UTF-8")));
    encMsg = msg;
    msg = new String(decryptedData);
    System.out.println(msg);
    return msg;
}

public String getEncryptedMsg() {
    return encMsg;
}

public String getDecryptedMsg() {
    return msg;
}

public String getDecodeKey() {
    return hexDecodeKey;
}

public SecretKeySpec getKey() {
    return decodeKey;
}

//AEScipher requires that 16 divides the length of b
public static byte[] handleString(byte[] b) throws UnsupportedEncodingException {
    byte[] temp = b;
    if (temp.length % 16 != 0) {
        byte[] byteMsg = Arrays.copyOf(temp, temp.length + 16 - (temp.length % 16));
        return byteMsg;
    }
    return temp;
}

public static String keyToString(SecretKeySpec key) {
    String decoded = Hex.encodeHexString(key.getEncoded());
    return decoded;
}

public static SecretKeySpec stringToKey(String key) throws DecoderException {
    byte[] decodedKey = Hex.decodeHex(key.toCharArray());
    return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
}

public static String stringToHex(String msg) throws UnsupportedEncodingException {
    return Hex.encodeHexString(msg.getBytes("UTF-8"));
}

public static String hexToString(String msg) throws DecoderException {
    return new String(Hex.decodeHex(msg.toCharArray()));
}

}

3
  • 1
    Did you copy-paste this from somewhere? It's wrong on so many levels... Commented Mar 3, 2014 at 20:50
  • I did copy some pieces but not all. Commented Mar 3, 2014 at 20:54
  • 1
    -1 for not appropriately researching the basic usage of the libraries you are attempting to perform security related operations with. While this is a Q&A forum and your question is valid, some level of research and troubleshooting is expected before you ask a question. Since your question was not adequately researched and had a simple error, it is unlikely that the solution will be useful to people who happen to find your question responsive to their search queries. This question nearly falls under the "simple typographic error" criteria in my opinion. Commented Mar 3, 2014 at 21:25

2 Answers 2

4

Just removing the UTF8 conversions of your ciphertext removes your decryption problem, just use the pure byte arrays. UTF-8 encode + decode does not guarantee that you'll get back the same result when used on a binary string, in fact it's more likely to not come back the same, and decryption tends to frown on bit errors.

public static String byteArrayToHex(byte[] bytes) throws UnsupportedEncodingException {
    return Hex.encodeHexString(bytes);
}

public static byte[] hexToByteArray(String hex) throws DecoderException {
    return Hex.decodeHex(hex.toCharArray());
}

public String encrypt(String msg) throws NoSuchAlgorithmException,
        InvalidKeyException, UnsupportedEncodingException,
        IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
    AEScipher.init(Cipher.ENCRYPT_MODE, AESkey);
    cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8")));

    this.msg = msg;
    encMsg = byteArrayToHex(cipherData);
    return encMsg;
}

public String decrypt(String msg, String hexDecodeKey) throws
        InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException, UnsupportedEncodingException,
        NoSuchAlgorithmException, NoSuchPaddingException, DecoderException {
    SecretKeySpec key = stringToKey(hexDecodeKey);
    AEScipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decryptedData = AEScipher.doFinal(handleString(hexToByteArray(msg)));
    encMsg = msg;
    msg = new String(decryptedData);
    System.out.println(msg);
    return msg;
}

It may also be a good idea to use some standard padding, like AES/ECB/PKCS5Padding.

Sign up to request clarification or add additional context in comments.

5 Comments

+1 for mentioning that they should use standard padding. But, remember that PKCS#7 padding is what people should be using with any cipher these days, primarily because it is less error prone when using arbitrary ciphers that may have large block sizes.
@MichaelJ.Gray: Remember that in a Java algorithm specification, PKCS5Padding and PKCS7Padding are equivalent, namely they both perform PKCS7 padding.
@GregS The SunJCE provider doesn't support "PKCS7Padding" so you'll have to use "PKCS5Padding" in any case. :)
@ntoskrnl: Good point. I wonder why I ever thought you could use PKCS7Padding?
@GregS Well, if I remember correctly, the Bouncy Castle provider supports both strings. PKCS5 is a bit of a misnomer anyway since technically it's only defined for 64-bit blocks.
2

well ... somehow the encryption should output a byte array...

the decryption should convert it back to a byte Array, which has to be interpreted as UTF-8 - encodes String using Snew String( UTF_encoded string

then you do some string magic here:

encMsg = stringToHex(new String(cipherData));

Why??? You dont need that!

Also in decryption:

msg = new String(decryptedData);

you need to give the same encoding as in encryption:

msg = new String(decryptedData, "UTF-8");

A try to clean up and fix your code:

import java.io.UnsupportedEncodingException;
import javax.crypto.*;
import java.security.*;
import java.util.Arrays;
import javax.crypto.spec.*;

public class AESCrypto2 {

    private Cipher AEScipher;
    private KeyGenerator AESgen;
    private SecretKeySpec AESkey;
    private SecretKeySpec decodeKey;
    private byte[] cipherData;
    private String msg;

    public static void main(String[] args) {
        try {
            AESCrypto2 a = new AESCrypto2();
            a.encrypt("Hello!");
            a.decrypt(a.getCipherData(), a.getKey());
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        } catch (NoSuchPaddingException ex) {
            ex.printStackTrace();
        } catch (InvalidKeyException ex) {
            ex.printStackTrace();
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        } catch (IllegalBlockSizeException ex) {
            ex.printStackTrace();
        } catch (BadPaddingException ex) {
            ex.printStackTrace();
        }

    }

    public AESCrypto2() throws NoSuchAlgorithmException,
            NoSuchPaddingException, UnsupportedEncodingException {
        AESgen = KeyGenerator.getInstance("AES");
        AESgen.init(128);
        AESkey = (SecretKeySpec) AESgen.generateKey();
        decodeKey = new SecretKeySpec(AESkey.getEncoded(), "AES");
        AEScipher = Cipher.getInstance("AES/ECB/NoPadding");
    }

    public AESCrypto2(String msg) throws NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException,
            UnsupportedEncodingException, IllegalBlockSizeException,
            BadPaddingException {
        this();
        encrypt(msg);
    }

    public byte[] encrypt(String msg) throws NoSuchAlgorithmException,
            InvalidKeyException, UnsupportedEncodingException,
            IllegalBlockSizeException, BadPaddingException,
            NoSuchPaddingException {
        AEScipher.init(Cipher.ENCRYPT_MODE, AESkey);
        cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8")));

        this.msg = msg;
        return cipherData;
    }

    public String decrypt(byte[] enocdedData, SecretKeySpec decodeKey)
            throws InvalidKeyException, IllegalBlockSizeException,
            BadPaddingException, UnsupportedEncodingException,
            NoSuchAlgorithmException, NoSuchPaddingException {
        AEScipher.init(Cipher.DECRYPT_MODE, decodeKey);
        byte[] decryptedData = AEScipher.doFinal(enocdedData);
        String result = new String(decryptedData, "UTF-8");
        System.out.println(result);
        return result;
    }

    public byte[] getCipherData() {
        return cipherData;
    }

    public String getDecryptedMsg() {
        return msg;
    }


    public SecretKeySpec getKey() {
        return decodeKey;
    }

    // AEScipher requires that 16 divides the length of b
    public static byte[] handleString(byte[] b)
            throws UnsupportedEncodingException {
        byte[] temp = b;
        if (temp.length % 16 != 0) {
            byte[] byteMsg = Arrays.copyOf(temp, temp.length + 16
                    - (temp.length % 16));
            return byteMsg;
        }
        return temp;
    }

    public static String byteToHex(byte[] msg) throws UnsupportedEncodingException {
        return Hex.encodeHexString(msg);
    }

    public static byte[] hexToByte(String msg) throws DecoderException {
        return Hex.decodeHex(msg);
    }

}

6 Comments

I want all the encryptions to be in hexadecimal. I tried your other suggestion, and got the same result.
You can't treat binary data like ciphertext as UTF-8.
so your main problem in the middle is to convert byte[] to hex Strings and back
public static String byteToHex(byte[] msg) throws UnsupportedEncodingException { return Hex.encodeHexString(msg); } public static byte[] hexToByte(String msg) throws DecoderException { return Hex.decodeHex(msg); }
to be clear: in any case hex is waste of bandwidth... if alphanumericality is needed, use base64
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.