3

I'm trying to encrypt a string, part of it is to XOR the text with IV string. After having some difficulties I ended up in stackoverflow where a guy gave the following code:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.IOException;

public class StringXORer {

public String encode(String s, String key) {
    return base64Encode(xorWithKey(s.getBytes(), key.getBytes()));
}

public String decode(String s, String key) {
    return new String(xorWithKey(base64Decode(s), key.getBytes()));
}

private byte[] xorWithKey(byte[] a, byte[] key) {
    byte[] out = new byte[a.length];
    for (int i = 0; i < a.length; i++) {
        out[i] = (byte) (a[i] ^ key[i%key.length]);
    }
    return out;
}

private byte[] base64Decode(String s) {
    try {
        BASE64Decoder d = new BASE64Decoder();
        return d.decodeBuffer(s);
    } catch (IOException e) {throw new RuntimeException(e);}
}

private String base64Encode(byte[] bytes) {
    BASE64Encoder enc = new BASE64Encoder();
    return enc.encode(bytes).replaceAll("\\s", "");

}
}

It seemed to work except for 2 issues: The result string becomes longer. When tried to do XOR between "abcdefgh" and "abcdefgh" I got : "aaaaaaaaaaaa". Secondly, result of two identical strings becomes "aaaa...." - string of "a"s....

So the two questions are:

  1. Why is the resulted string becomes longer?
  2. Why the result of XOR between identical strings consists of list of "a"s...?

This is homework, appreciate any help.

Thanx!

Mat
  • 202,337
  • 40
  • 393
  • 406
Dana Root
  • 75
  • 1
  • 1
  • 4

1 Answers1

2

The string gets longer because in addition to XORing it with the key, it is Base64 encoded.

Replace the call to base64Encode(...) with new String(...) and base64Decode(s) with s.getBytes() in order to get the original XORed String. But note that the encoded string will not look good when printed. A string XORed with itself will consist of \0 characters, which is printed as white space.

Even after that change, it is possible that getBytes() returns a byte array longer that the string length, depending on the platform default charset. E.g. UTF-8 will encode characters >= 128 as two or three bytes. Use ISO-8859-1 as a charset with 1-to-1 correspondence of characters <= 255 and bytes. Similarly, new String(...) might fail to produce the expected characters, because the given bytes are not valid for the platform default encoding.

Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • I did what you have told me , it work but after 30 round gone bad. I wanted to add screenshots but not sure how to do that here so I uploaded zip file with screenshots: http://www.2shared.com/file/O4B5MctP/steps.html You can see round number there. around round 50 it became too slow and somewhere after I got some memory fault - Which was why I asked this question in the first place. Any idea what happened there? BTW, IV is constantly changing as in the CBC encrypting scheme (the result of XOR becomes new IV). – Dana Root Apr 18 '12 at 19:49
  • Can you check that encrypting and then decrypting a String with the same key yields the original String? If this fails, you may need to specify the charSet `"ISO-8859-1"` with the `getBytes()` and `new String()` methods. Consult the JavaDoc for how to do that. – Christian Semrau Apr 18 '12 at 20:05
  • it does yield the original String. Thanx for the help. – Dana Root Apr 20 '12 at 09:09
  • @DanaRoot Did my suggestions solve your problem? If so, you should accept my answer. If not, you could provide more detail, e.g. whether you located the cause somethere else. Since this was homework, you may not be interested yourself, which would be fine, too. – Christian Semrau May 10 '12 at 20:08