简体   繁体   中英

Converting an int to a String and then encrypt it with XOR

I'm trying to convert an Integer to a String, and then encrypt the String with a XOR encryption. But when i'm decrypting my Strin again, i get a different answer, that the String i typed before the encryption, and i don't know what i'm doing wrong?

public class Krypte {
public static void main (String [] args) {
    int i = 12345;

    String k = Integer.toString(i);
    String G = secure(k.getBytes());
    System.out.println("Encrypted: " + G);

    String U = secure(G.getBytes());
    System.out.println("Decrypted: " + U);
    int X = Integer.parseInt(U);
    System.out.println("As an int: " + X);

}

public static String secure(byte[] msg) {
    // Variables
    int outLength = msg.length;
    byte secret = (byte) 0xAC; // same as 10101100b (Key)
    // XOR kryptering
    for (int i = 0; i < outLength; i++) {
        // encrypting each byte with XOR (^)
        msg[i] = (byte) (msg[i] ^ secret);
    }
    return new String(msg);
}
}

There's a subtle (yet very important) difference between char and byte types. Consider this:

class Krypte {
    public static void main (String [] args) {
        int i = 12345;
        String k = Integer.toString(i);
        System.out.println("Before: " + k);    
        String G = secure(k.toCharArray());
        System.out.println("Encrypted: " + G);
        String U = secure(G.toCharArray());
        System.out.println("Decrypted: " + U);
        int X = Integer.parseInt(U);
        System.out.println("As an int: " + X);
    }

    public static String secure(char[] msg) {
        // Variables
        int outLength = msg.length;
        byte secret = (byte) 0xAC; // same as 10101100b (Key)
        // XOR kryptering
        for (int i = 0; i < outLength; i++) {
            // encrypting each byte with XOR (^)
            System.out.println("Byte before: " + msg[i]);
            msg[i] = (char) (msg[i] ^ secret);
            System.out.println("Byte after: " + msg[i]);
        }
        return new String(msg);
    }
}

This works ( proof ), because XORing some character value with a byte will ( most probably ) give you a valid character .

Not let's see what happens in the original snippet - by adding this debugging output into the main loop of secure method:

 System.out.println("Byte before: " + msg[i]);
 msg[i] = (byte) (msg[i] ^ secret);
 System.out.println("Byte after: " + msg[i]);

And the output would be:

Byte before: 49
Byte after: -99
Byte before: 50
Byte after: -98
Byte before: 51
Byte after: -97
Byte before: 52
Byte after: -104
Byte before: 53
Byte after: -103

It's quite ok: first getBytes function encoded the string given into an array of bytes using the platform's default charset . Character '1' gets encoded into 49 byte value; '2' becomes 50 , etc.

Then we're XORing these values with our key - and get this sequence of bytes:

-99 -98 -97 -104 -103

The final step seems easy: we just make (and return) a new String from this sequence of bytes, what can go wrong here? But in fact it's the very step where, well, the fan get hit. )

See, String constructor tries to process this sequence of bytes using the platform's default charset . Indeed, for some charsets these bytes represent a sequence of valid characters just fine - but not for UTF-8!

...You probably already guessed what happens next. For each 'undecodable' sequence of bytes, as described here , the first byte is transformed into so-called Replacement character , and others are retried. In this particular example there would be five of these signs of failure in the string returned by the first secure invokation.

Decoding this string is, well, quite meaningless - as it doesn't store any information (except length) about the target string. That's why the original code ultimately failed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM