Ссылка NullReferenceException или Object, не установленная на экземпляр объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Как видно из вышеприведенного кода, оператор Student s - объявляет только переменную типа Student, обратите внимание, что класс Student не создается в этой точке. Следовательно, когда выполняется выполнение инструкции s.GetFullName (), она выкинет исключение NullReferenceException.
Предполагая (!) строки одинаковой длины, почему бы преобразовать строки в байтовые массивы , а затем XOR байты. Результирующие байт-массивы могут иметь разную длину также в зависимости от вашего кодирования (например, UTF8 будет расширяться до разных длин байтов для разных символов).
Вы должны быть осторожны, чтобы указать кодировку символов, чтобы обеспечить последовательное / надежное преобразование строк / байт.
функция 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 char
соответствует кодовому модулю UTF-16, а в некоторых случаях два последовательных char
s (так называемая суррогатная пара ) необходимы для одного реального символа Unicode (codepoint).
XORing две допустимые последовательности UTF-16 (например, строки Java char
на char
или байты по байтам после кодирования в UTF-16) не обязательно дает вам другую действительную строку UTF-16 - в результате у вас могут быть непарные суррогаты. (Это все равно будет прекрасно использоваться Java String, только методы, связанные с кодеком, могут запутаться, а те, которые преобразуются в другие кодировки для вывода и аналогичные.)
То же самое верно, если вы сначала конвертируете ваши строки в UTF-8, а затем XOR эти байты - здесь вы, скорее всего, закончите с байтовой последовательностью, которая недействительна UTF-8, если ваши строки не были и чистыми ASCII-строками.
Even если вы попытаетесь сделать это правильно и выполните итерацию по вашим двум строкам по кодовым точкам и попробуйте XOR для кодовых точек, вы можете в конечном итоге с кодовыми точками за пределами допустимого диапазона (например, U+FFFFF
(плоскость 15) XOR U+10000
(плоскость 16) = U+1FFFFF
(который был бы последним символом плоскости 31), который был бы выше диапазона существующих кодовых точек. И вы также могли бы сделать это с помощью кодовых точек, зарезервированных для суррогатов (= недействительных).
Если ваши строки содержат только символы 128, 256, 512, 1024, 2048, 4096, 8192, 16384 или 32768, тогда строковые строки XORed будут находиться в том же диапазоне, и thu безусловно, не содержат суррогатов. В первых двух случаях вы также можете кодировать свою строку как ASCII или Latin-1, соответственно, и иметь тот же XOR-результат для байтов. (Вы все еще можете получить контрольные символы, что может быть проблемой для вас.)
Что я, наконец, говорю здесь: не ожидайте, что результат шифрования строк будет действительным string снова - вместо этого просто сохраните и передайте его как byte[]
(или поток байтов). (И да, конвертировать в UTF-8 до шифрования и из UTF-8 после дешифрования).
Примечание: это работает только для низких символов, то есть ниже 0x8000. Это работает для всех символов ASCII.
Я бы сделал XOR каждый charAt () для создания новой строки. Как
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, символ продолжения).
blockquote>Это значения
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]
Вы хотите что-то вроде этого:
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 байтов строки может не возвращать верные байты для строки.
Это код, который я использую:
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;
}