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