Операция XOR с двумя строками в java

Как выполнить побитовую операцию XOR с двумя строками в java.

Вы хотите что-то вроде этого:

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

Кодировка base64 выполняется, поскольку xor'ing байтов строки может не возвращать действительные байты для строки.

Примечание: это работает только для низких символов, т.е. ниже 0x8000. Это работает для всех символов ASCII.

Я бы сделал XOR каждый charAt (), чтобы создать новую 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(); 

В ответ на комментарий пользователя @ user467257

Если ваш вход / выход - utf-8, а вы xor «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"))); } 

печать

 135 UTF-8 encoded is [-62, -121] 

Обращать внимание:

Java- char соответствует коду UTF-16, а в некоторых случаях для одного реального символа Unicode (кодовой точки) необходимы два последовательных char (так называемая суррогатная пара ).

XORing двух действительных последовательностей UTF-16 (т. Е. char Java Strings char или байта за байтом после кодирования в UTF-16) не обязательно дает вам другую действительную строку UTF-16 – в результате вы можете иметь непарные суррогаты. (Это все равно было бы прекрасно используемой Java-строкой, только методы, связанные с кодированием, могли бы запутаться, а те, которые преобразуются в другие кодировки для вывода и аналогичные.)

То же самое верно, если вы сначала конвертируете свои строки в UTF-8, а затем в XOR эти байты – здесь вы, вероятно , закончите с байтовой последовательностью, которая недопустима UTF-8, если ваши строки не были и чистыми ASCII-строками.

Даже если вы попытаетесь сделать это правильно и перейдете по вашим двум строкам по кодовым точкам и попробуйте XOR для кодовых точек, вы можете в конечном итоге с кодовыми точками за пределами допустимого диапазона (например, U+FFFFF (плоскость 15) XOR U+10000 (плоскость 16) = U+1FFFFF (который был бы последним символом плоскости 31), путь выше диапазона существующих кодовых точек. И вы могли бы также оказаться в этом случае с кодовыми точками, зарезервированными для суррогатов (= недействительными).

Если ваши строки содержат только символы <128, 256, 512, 1024, 2048, 4096, 8192, 16384 или 32768, то строки (char-wise) XORed будут находиться в одном диапазоне и, следовательно, не будут содержать никаких суррогатов. В первых двух случаях вы также можете кодировать свою строку как ASCII или Latin-1, соответственно, и иметь тот же XOR-результат для байтов. (Вы все еще можете получить контрольные символы, что может быть проблемой для вас.)


Что я, наконец, говорю здесь : не ожидайте, что результат шифрования строк будет снова корректной строкой – вместо этого просто сохраните и передайте его в виде byte[] (или streamа байтов). (И да, конвертировать в UTF-8 до шифрования и из UTF-8 после дешифрования).

Предполагая (!) Строки одинаковой длины, почему бы не преобразовать строки в байтовые массивы, а затем XOR байты. Результирующие байт-массивы могут быть различной длины также в зависимости от вашего кодирования (например, UTF8 будет расширяться до разных длин байтов для разных символов).

Вы должны быть осторожны, чтобы указать кодировку символов, чтобы обеспечить последовательное / надежное преобразование строк / байтов.

Это код, который я использую:

 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; } 

функция abs – это когда строки имеют одинаковую длину, поэтому нога результата будет такой же, как и минимальная длина двух строк a и 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(); } 

Это решение совместимо с Android (я тестировал и использовал его сам). Благодаря @ user467257, решение которого я адаптировал.

 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)); } } 
  • Как отформатировать строку Java с начальным нулем?
  • Как я могу получить значение свойства string через Reflection?
  • Bash: манипуляция со строками (знак процента)
  • Доступ к случайному элементу в списке
  • Формат метода (String, Object ) в типе String не применим для аргументов (...)
  • Снижение производительности String.intern ()
  • Как проверить, отображается ли один символ в строке?
  • Команда не обнаружила ошибку в присвоении переменной Bash
  • Выключение строки C ++
  • Закрытие сканера вызывает java.util.NoSuchElementException
  • Форматировать строку Go без печати?
  • Давайте будем гением компьютера.