在java中使用两个字符串进行XOR操作

yas*_*tha 50 java string operators xor

如何对java中的两个字符串进行按位XOR运算.

use*_*257 50

你想要这样的东西:

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

    }
}
Run Code Online (Sandbox Code Playgroud)

完成base64编码是因为xor'ing字符串的字节可能不会为字符串返回有效字节.

  • 很棒的答案!但是读者应该确保使用[`java.util.Base64`](http://docs.oracle.com/javase/8/docs/api/java/util/Base64.html)而不是[soon-to]来自`sun.misc`的-be-unreachable类(http://blog.codefx.org/java/dev/how-java-9-and-project-jigsaw-may-break-your-code/#Internal-的API,成为-不可用). (5认同)
  • 我使用android.Base64而不是sun的这个示例:import android.util.Base64; 这两个方法也改为:private byte [] base64Decode(String s){try {return Base64.decode(s,Base64.DEFAULT); } catch(IllegalArgumentException e){throw new RuntimeException(e);}} private String base64Encode(byte [] bytes){return Base64.encodeToString(bytes,Base64.DEFAULT).replaceAll("\\ s",""); } (2认同)

Pet*_*rey 27

注意:这仅适用于低字符,即低于0x8000,这适用于所有ASCII字符.

我会为每个charAt()做一个XOR来创建一个新的String.喜欢

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();
Run Code Online (Sandbox Code Playgroud)

回应@ user467257的评论

如果你的输入/输出是utf-8而你是"a"和"æ",你将留下一个无效的utf-8字符串,由一个字符组成(十进制135,一个连续字符).

它是char被xor'ed 的值,但字节值和这产生一个UTF-8编码的字符.

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")));
}
Run Code Online (Sandbox Code Playgroud)

版画

135 UTF-8 encoded is [-62, -121]
Run Code Online (Sandbox Code Playgroud)

  • 首先,所产生的字符串没有正确xor'd,因为你不能通过再次使用密钥来取回原始字符串(除非你的密钥保证等于或长于非常的消息)奇怪的是,使代码完全歪曲了xor'ing的概念.其次,您不能保证只通过xoring字符获得有效的字符串字节,因此您的输出字符串可能包含无效的字节序列. (4认同)
  • @PeterLawrey当您的答案提出时,您通过char xor char只有一些限制.这是一个黑客的解决方案,准备陷阱不小心.更好的方法是逐字节xor,base64(或其他)编码结果以确保可印刷性/可读性,然后反转这些步骤进行解码. (2认同)

Paŭ*_*ann 17

请注意:

Java char对应于UTF-16代码单元,在某些情况下,一个真正的Unicode字符(代码点)需要两个连续的chars(所谓的代理对).

异或两个有效的UTF-16序列(即Java字符串char通过char,或逐字节编码后,UTF-16)并不一定会给你另一个有效的UTF-16字符串-你可能有未配对的替代品作为一个结果.(它仍然是一个完全可用的Java字符串,只是与代码点有关的方法可能会混淆,而那些转换为其他编码的输出和类似的.)

如果你首先将你的字符串转换为UTF-8然后将这些字节转换为XOR,那么同样有效 - 如果你的字符串不是纯ASCII字符串,那么你很可能会得到一个无效的UTF-8字节序列.

即使您尝试正确执行并通过代码点迭代两个字符串并尝试对代码点进行异或,您也可以得到有效范围之外的代码点(例如,U+FFFFF(平面15)XOR U+10000(平面16)= U+1FFFFF(这将是最后一个)平面的特征31),高于现有代码点的范围.你也可以用代理点保留的代码点(=无效的代码点)结束这种方式.

如果您的字符串只包含字符<128,256,512,1024,2048,4096,8192,16384或32768,那么(字符方式)XORed字符串将在相同的范围内,因此当然不包含任何代理项.在前两种情况下,您还可以将String编码为ASCII或Latin-1,并对字节具有相同的XOR结果.(你仍然可能最终得到控制字符,这对你来说可能是一个问题.)


我在这里最后说的是:不要指望将字符串加密的结果再次成为有效的字符串 - 而是简单地将其存储并作为byte[](或字节流)传输.(是的,在加密前转换为UTF-8,在解密后转换为UTF-8).


Bri*_*new 3

假设(!)字符串长度相等,为什么不将字符串转换为字节数组,然后对字节进行异或。根据您的编码,生成的字节数组也可能具有不同的长度(例如,UTF8 将针对不同的字符扩展为不同的字节长度)。

您应该小心指定字符编码以确保一致/可靠的字符串/字节转换。

  • 字符串可以具有相同的长度,但字节数组可以具有不同的长度。;) (2认同)