XOR operation with two strings in java

前端 未结 7 501
有刺的猬
有刺的猬 2020-11-28 05:48

How to do bitwise XOR operation to two strings in java.

相关标签:
7条回答
  • 2020-11-28 06:13

    Pay attention:

    A Java char corresponds to a UTF-16 code unit, and in some cases two consecutive chars (a so-called surrogate pair) are needed for one real Unicode character (codepoint).

    XORing two valid UTF-16 sequences (i.e. Java Strings char by char, or byte by byte after encoding to UTF-16) does not necessarily give you another valid UTF-16 string - you may have unpaired surrogates as a result. (It would still be a perfectly usable Java String, just the codepoint-concerning methods could get confused, and the ones that convert to other encodings for output and similar.)

    The same is valid if you first convert your Strings to UTF-8 and then XOR these bytes - here you quite probably will end up with a byte sequence which is not valid UTF-8, if your Strings were not already both pure ASCII strings.

    Even if you try to do it right and iterate over your two Strings by codepoint and try to XOR the codepoints, you can end up with codepoints outside the valid range (for example, U+FFFFF (plane 15) XOR U+10000 (plane 16) = U+1FFFFF (which would the last character of plane 31), way above the range of existing codepoints. And you could also end up this way with codepoints reserved for surrogates (= not valid ones).

    If your strings only contain chars < 128, 256, 512, 1024, 2048, 4096, 8192, 16384, or 32768, then the (char-wise) XORed strings will be in the same range, and thus certainly not contain any surrogates. In the first two cases you could also encode your String as ASCII or Latin-1, respectively, and have the same XOR-result for the bytes. (You still can end up with control chars, which may be a problem for you.)


    What I'm finally saying here: don't expect the result of encrypting Strings to be a valid string again - instead, simply store and transmit it as a byte[] (or a stream of bytes). (And yes, convert to UTF-8 before encrypting, and from UTF-8 after decrypting).

    0 讨论(0)
  • 2020-11-28 06:14

    Note: this only works for low characters i.e. below 0x8000, This works for all ASCII characters.

    I would do an XOR each charAt() to create a new String. Like

    String s, key;
    
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < s.length(); i++)
        sb.append((char)(s.charAt(i) ^ key.charAt(i % key.length())));
    String result = sb.toString();
    

    In response to @user467257's comment

    If your input/output is utf-8 and you xor "a" and "æ", you are left with an invalid utf-8 string consisting of one character (decimal 135, a continuation character).

    It is the char values which are being xor'ed, but the byte values and this produces a character whichc an be UTF-8 encoded.

    public static void main(String... args) throws UnsupportedEncodingException {
        char ch1 = 'a';
        char ch2 = 'æ';
        char ch3 = (char) (ch1 ^ ch2);
        System.out.println((int) ch3 + " UTF-8 encoded is " + Arrays.toString(String.valueOf(ch3).getBytes("UTF-8")));
    }
    

    prints

    135 UTF-8 encoded is [-62, -121]
    
    0 讨论(0)
  • 2020-11-28 06:14

    This solution is compatible with Android (I've tested and used it myself). Thanks to @user467257 whose solution I adapted this from.

    import android.util.Base64;
    
    public class StringXORer {
    
    public String encode(String s, String key) {
        return new String(Base64.encode(xorWithKey(s.getBytes(), key.getBytes()), Base64.DEFAULT));
    }
    
    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) {
        return Base64.decode(s,Base64.DEFAULT);
    }
    
    private String base64Encode(byte[] bytes) {
        return new String(Base64.encode(bytes,Base64.DEFAULT));
    
    }
    }
    
    0 讨论(0)
  • 2020-11-28 06:15

    This is the code I'm using:

    private static byte[] xor(final byte[] input, final byte[] secret) {
        final byte[] output = new byte[input.length];
        if (secret.length == 0) {
            throw new IllegalArgumentException("empty security key");
        }
        int spos = 0;
        for (int pos = 0; pos < input.length; ++pos) {
            output[pos] = (byte) (input[pos] ^ secret[spos]);
            ++spos;
            if (spos >= secret.length) {
                spos = 0;
            }
        }
        return output;
    }
    
    0 讨论(0)
  • 2020-11-28 06:25

    the abs function is when the Strings are not the same length so the legth of the result will be the same as the min lenght of the two String a and b

    public String xor(String a, String b){
        StringBuilder sb = new StringBuilder();
        for(int k=0; k < a.length(); k++)
           sb.append((a.charAt(k) ^ b.charAt(k + (Math.abs(a.length() - b.length()))))) ;
           return sb.toString();
    }
    
    0 讨论(0)
  • 2020-11-28 06:26

    You want something like this:

    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", "");
    
        }
    }
    

    The base64 encoding is done because xor'ing the bytes of a string may not give valid bytes back for a string.

    0 讨论(0)
提交回复
热议问题