package org.zarroboogs.smartzpn.tunnel.shadowsocks;
import org.zarroboogs.smartzpn.tunnel.IEncryptor;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
public class TableEncryptor implements IEncryptor {
private byte[] encryptTable = new byte[256];
private byte[] decryptTable = new byte[256];
public TableEncryptor(String password) {
long a = passwordToInt64(password);
for (int i = 0; i < 256; i++) {
encryptTable[i] = (byte) i;
}
System.out.println("mergeSort....");
long startTime = System.nanoTime();
encryptTable = mergeSort(encryptTable, a);
long endTime = System.nanoTime();
System.out.printf("mergeSort: %3fms\n", (endTime - startTime) / 1000D / 1000D);
for (int i = 0; i < 256; i++) {
decryptTable[encryptTable[i] & 0xFF] = (byte) i;
}
}
long passwordToInt64(String password) {
try {
byte[] passwordBytes = password.getBytes("UTF-8");
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] hashPwd = md5.digest(passwordBytes);
long a = bytesToInt64(hashPwd);
return a;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
long bytesToInt64(byte[] data) {
long value = data[0];
value |= ((long) (data[1] & 0xFF) << 8);
value |= ((long) (data[2] & 0xFF) << 16);
value |= ((long) (data[3] & 0xFF) << 24);
value |= ((long) (data[4] & 0xFF) << 32);
value |= ((long) (data[5] & 0xFF) << 40);
value |= ((long) (data[6] & 0xFF) << 48);
value |= ((long) (data[7] & 0xFF) << 56);
return value;
}
private byte[] mergeSort(byte[] srcArray, long a) {
byte[] dstArray = new byte[256];
long a1 = Long.MAX_VALUE;
long a2 = (a & Long.MAX_VALUE);
int stepSize, leftOffset, leftMaxOffset, rightOffset, rightMaxOffset, dstOffset, leftValue, rightValue;
for (int i = 1; i < 1024; i++) {
for (stepSize = 1; stepSize < 256; stepSize <<= 1) {
for (dstOffset = 0; dstOffset < 256; ) {
leftOffset = dstOffset;
leftMaxOffset = leftOffset + stepSize;
rightOffset = leftMaxOffset;
rightMaxOffset = rightOffset + stepSize;
for (; dstOffset < rightMaxOffset; dstOffset++) {
if (rightOffset == rightMaxOffset) {
dstArray[dstOffset] = srcArray[leftOffset++];
} else if (leftOffset == leftMaxOffset) {
dstArray[dstOffset] = srcArray[rightOffset++];
} else {
leftValue = (srcArray[leftOffset] & 0xFF) + i;
rightValue = (srcArray[rightOffset] & 0xFF) + i;
boolean isLeftSmallThanRight = a > 0 ? ((a % leftValue - a % rightValue) <= 0) : (((a1 % leftValue + a2 % leftValue + 1) % leftValue - (a1 % rightValue + a2 % rightValue + 1) % rightValue) <= 0);
if (isLeftSmallThanRight) {
dstArray[dstOffset] = srcArray[leftOffset++];
} else {
dstArray[dstOffset] = srcArray[rightOffset++];
}
}
}
}
byte[] temp = dstArray;
dstArray = srcArray;
srcArray = temp;
}
}
return srcArray;
}
@Override
public void encrypt(ByteBuffer buffer) {
byte[] data = buffer.array();
for (int i = buffer.arrayOffset() + buffer.position(); i < buffer.limit(); i++) {
data[i] = encryptTable[data[i] & 0xFF];
}
}
@Override
public void decrypt(ByteBuffer buffer) {
byte[] data = buffer.array();
for (int i = buffer.arrayOffset() + buffer.position(); i < buffer.limit(); i++) {
data[i] = decryptTable[data[i] & 0xFF];
}
}
}