user1231737
user1231737

Reputation: 33

Why does adding a character to an encrypted base64 encoded string NOT break the decryption?

I have java code using aes algorithm. It can encrypt and decrypt strings properly. However what we found that, if I add a (only one) character to the end of encrypted string, I can still decrypt it to correct plain text value. If I append 2 or more, it can't decrypt.

I tried des and other alogorithm and still the same behavior. I also tried padding etc, no luck

Is that normal behavior? How I can get around it?

Thanks

M

public class testCipher 
{
    public static final String PROVIDER = "SunJCE";
    private static final String ALGORITHM = "AES";
    private static final String aesKey = "some long key";
    static Cipher ecipher;
    static Cipher dcipher;

    public static void main(String[] args)  
    {

    try {

    byte[] buf1 = aesKey.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    buf1 = sha.digest(buf1);
    buf1 = Arrays.copyOf(buf1, 16);
    SecretKeySpec keySpec = null;
    keySpec = new SecretKeySpec(buf1, "AES");

    ecipher = Cipher.getInstance(ALGORITHM, PROVIDER);
    dcipher = Cipher.getInstance(ALGORITHM, PROVIDER);

    ecipher.init(1, keySpec);
    dcipher.init(2, keySpec, ecipher.getParameters());

    if (args[0].equals("encrypt"))
    System.out.println(encrypt(args[1]));
    else if (args[0].equals("decrypt"))
    System.out.println(decrypt(args[1]));
    else {
    System.out.println("USAGE: encrypt/decrypt '<string>'");
    System.exit(15);
   }

} catch (Exception e) {
    System.exit(5);
} 

}

public static String encrypt(String str) 
{
    try {

        byte[] utf8 = str.getBytes("UTF8");
        byte[] enc = ecipher.doFinal(utf8);
        return new sun.misc.BASE64Encoder().encode(enc);

    } catch (Exception e) {
        System.exit(7);
    }

    return null;
}

public static String decrypt(String str) 
{
    try {
        // Decode base64 to get bytes
        byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

        // Decrypt
        byte[] utf8 = dcipher.doFinal(dec);

        // Decode using utf-8
        return new String(utf8, "UTF8");
    } catch (Exception e) {
        System.exit(7);
    } 
    return null;
}
}

Upvotes: 1

Views: 1944

Answers (1)

Jherico
Jherico

Reputation: 29240

It's impossible to answer properly without some sort of source code to indicate what exactly you're doing, but there are a number of possibilities, mostly related to encoding sizes.

Encoding and encryption typically blocks sizes. For instance, hex encoding of a set of bytes requires two output bytes for every one input byte. Base 64 encoding uses 5 output bytes for every 4 input bytes. Most encryption algorithms work in 64 or 128 bit blocks, i.e. 8 or 16 bytes.

If you're fiddling with an encoded string and add only a single character to it, it's possible (again, impossible to say for sure without source code) that you're adding insufficient information for the additional character to be treated as a block in whatever processing it's undergoing, and so it sounds like it's being silently ignored. Adding two character crashes, so that's probably pushing you over some limit.

As blorgbeard points out in the comments, a) why do you care and b) why are you fiddling with encrypted strings in the first place?

EDIT:

Based on your code it's exactly what I said. It has nothing to do with the encryption, and everything to do with the Base64 encoding you're using.

    String str = "foo";
    String enc = new sun.misc.BASE64Encoder().encode(str.getBytes(Charsets.UTF_8));
    // enc = enc + "x";
    // enc = enc + "x";
    byte [] decBytes = new sun.misc.BASE64Decoder().decodeBuffer(enc);
    String dec = new String(decBytes, Charsets.UTF_8);
    System.out.println(dec);

If you comment out one of those enc = enc + "X"; lines, the program will still print 'foo', but if you comment out two of them, then it will print foo + some garbage characters afterwards. This is because a single character of Base64 encoded data is meaningless. It requires at least two characters to encode a single byte in Base64, so that's why the first character is ignored and the second causes problems.

However, going back to the root of the problem, your comments suggests that users might be able to edit these values? That's.... well, that's insane. You don't ever provide any functionality for modifying encrypted data except to move it from one location to another, or to encrypt or decrypt data.

Also, you shouldn't really be using any of the classes in sun.misc package. sun.misc is considered internal to Java, and using it means there's no guarantees that it will work in a given fashion, or that it will exist from one JVM to another. There are open source libraries out that do Base64 transcoding (Apache Commons-Codec is popular) and you should be using one of those. Using undocumented features inside the JVM could easily be considered your main problem. I haven't checked the docs on Commons-Codec, but it's possible that it will throw an exception if it encounters an unexpected number of input bytes for decoding.

Upvotes: 4

Related Questions