Java异或解密

  • 本文关键字:解密 Java java
  • 更新时间 :
  • 英文 :


为一个类项目提供了一个自定义的异或加密函数。我们的目标是获取这个函数并创建一个解密函数。这几天我都快被它逼疯了。有人能帮帮我吗?

如果我输入hello并使用key password,我的输出是:35266a676e6e6d

希望扭转这一局面。

class StringUtils {
private static final char[] hexArray = "0123456789abcdef".toCharArray();
StringUtils() {
}
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[(bytes.length * 2)];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 255;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[(j * 2) + 1] = hexArray[v & 15];
}
return new String(hexChars);
}
static String xor(String input, String key) throws InterruptedException {
int index;
String lengthString = input.length() + "&";
byte[] buffer = new byte[(input.length() + lengthString.length())];
int k_len = key.length();
int index2 = 0;
int c = 0;
int i = 0;
while (i < lengthString.length()) {
int c2 = c + 1;
int index3 = index2 + 1;
buffer[c] = (byte) (((byte) lengthString.charAt(i)) ^ (((byte) key.charAt(index2)) & 10));
if (index3 >= k_len) {
index2 = 0;
} else {
index2 = index3;
}
i++;
c = c2;
}
int i2 = 0;
while (i2 < input.length()) {
int c3 = c + 1;
int index4 = index2 + 1;
buffer[c] = (byte) (((byte) input.charAt(i2)) ^ (((byte) key.charAt(index2)) & 10));
if (index4 >= k_len) {
index = 0;
} else {
index = index4;
}
i2++;
c = c3;
}
return bytesToHex(buffer);
}
}

逻辑的重构版本:

static String encrypt(String input, String key) {
String plain = (input.length() + "&" + input); // add length
return DatatypeConverter.printHexBinary(xor2(plain.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8)));
}
static String decrypt(String encrypted, String key) {
String plain = new String(xor2(DatatypeConverter.parseHexBinary(encrypted), key.getBytes(StandardCharsets.UTF_8)));
return plain.substring(plain.indexOf('&') + 1);  // remove length
}
static byte[] xor2(byte[] in, byte[] key) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
out[i] = (byte)(in[i] ^ (key[i % key.length] & 10));
}
return out;
}

…和一个测试用例:

@Test
public void xorTest() {
String message = "hello";
String key = "password";
String encrypted = StringUtils.encrypt(message, key);
System.out.println("encrypted:  " + encrypted);
String plain = StringUtils.decrypt(encrypted, key);
System.out.println("plain:  " + plain);
}

这产生:

encrypted:  35266A676E666D
plain:  hello

在不给你的家庭作业给出答案的情况下,这里有一个提示来帮助你开始。

提示1:

稍微重构后,xor函数是这样的

static String xor(String input, String key) {
String lengthString = input.length() + "&";
byte[] buffer = new byte[(input.length() + lengthString.length())];
int keyIndex = 0;
int bufferIndex = 0;
for (int i = 0; i < lengthString.length(); i++) {
buffer[bufferIndex] = (byte) (((byte) lengthString.charAt(i)) ^ (((byte) key.charAt(keyIndex)) & 10));
keyIndex = (keyIndex + 1) % key.length();
bufferIndex++;
}
for (int i = 0; i < input.length(); i++) {
buffer[bufferIndex] = (byte) (((byte) input.charAt(i)) ^ (((byte) key.charAt(keyIndex)) & 10));
bufferIndex++;
}
return bytesToHex(buffer);
}

提示2:

输入字符串的长度可以先取一个较大的估定值,然后通过反复试验来减少长度,直到找到正确的值。

// Move input length down until it matches the calculation for buffer length
int inputLength = buffer.length - 1;
while (inputLength + (inputLength + "&").length() > buffer.length) {
inputLength--;
}
// So now we know the length string
String lengthString = inputLength + "&";

提示3:

有三种情况你需要考虑。

  • lengthString.length() > key.length():这种情况要求我们找到键重复的地方并抓取下一个字符。这是可行的,但可能需要额外的工作。
  • lengthString.length() == key.length():这是最容易解决的情况,因为它意味着输入的字符是键中的第一个字符。
  • lengthString.length() < key.length():如果是这种情况,您将无法解决这个问题,因为用于xor输入的字节不在缓冲区的长度部分。所以为了讨论起见,请完全忽略这种情况。

解决方案我很无聊,所以我决定解决这个问题。它只是归结为计算缓冲区的lengthString部分有多长。之后,您可以尝试通过检查模式或仅列出所有4种可能的解决方案来进行智能操作,因为我们知道输入只能用0,2,8或10进行xor(因为之前的& 10)。
static String extractSolution(byte[] buffer, int start, byte xor) {
char[] solution = new char[buffer.length - start];
for (int i = start; i < buffer.length; i++) {
solution[i - start] = (char)(buffer[i] ^ xor);
}
return new String(solution);
}
static void decode(byte[] buffer) {
// Move input length down until it matches the calculation for buffer length
int inputLength = buffer.length - 1;
while (inputLength + (inputLength + "&").length() > buffer.length) {
inputLength--;
}
String lengthString = inputLength + "&";
// Extract part of the key used in the first section
byte[] keyFragment = new byte[lengthString.length()];
for (int i = 0; i < keyFragment.length; i++) {
keyFragment[i] = (byte) (buffer[i] ^ (byte) lengthString.charAt(i));
}
System.out.println("Most likely solutions:");
// Look for repeating patterns to find solution
periodCheck:
for (int i = 1; i < keyFragment.length + 1; i++) {
for (int j = i; j < keyFragment.length; j++) {
if (keyFragment[j] != keyFragment[j % i])
continue periodCheck;
}
// A possible period has been found
byte specialByte = keyFragment[keyFragment.length % i];
String possibleSolution = extractSolution(buffer, keyFragment.length, specialByte);
System.out.println(""" + possibleSolution + """);
}

System.out.println("All Possible Solutions:");

// List out all possible inputs that could have given this buffer
// In reality key can only be one of [0, 2, 8, 10], but go through all bytes for verbosity
for (int key = Byte.MIN_VALUE; key <= Byte.MAX_VALUE; key ++) {
if ((key & 10) != key)
continue;

String possibleSolution = extractSolution(buffer, keyFragment.length, (byte) key);
System.out.println(""" + possibleSolution + """);
}
}

我如何提问和回答作业问题?

最新更新