基于UTF-8编码的等长加解扰算法(java)
使用“三区映射”方法针对中英文数字混杂的字符串进行等长的加解扰,适用于安全性较低的情景,方便查询出库再加扰入库,字段长度不变。(gbk编码的环境同样可以使用三区映射方法进行加解扰设计)
/** * 等长加扰解扰 * @author Jerry */public final class UTFBasedEqualLengthCipher{ private static final char[] EN_RED = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u'}; private static final char[] EN_YELLOW = {'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '@', '5', '6', '7', '8', '9', 'Z', 'Y', 'X', 'W', 'V'}; private static final char[] EN_BLUE = {'U', 'T', 'S', 'R', 'Q', 'P', 'O', 'N', 'M', 'L', 'K', 'J', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A'}; private static final int RED_BEGINNING = 0x4E00; private static final int RED_ENDING = 0x6936; private static final int YELLOW_BEGINNING = 0x6937; private static final int YELLOW_ENDING = 0x846D; private static final int BLUE_BEGINNING = 0x846f; private static final int BLUE_ENDING = 0x9fa5; private static final int CN_ZONE_SPACE = 0x1B37; private static final int EN_ZONE_SPACE = 0x15; private static final int EN_UPPER_BEGINNING = 0x40; private static final int EN_UPPER_ENDING = 0x5A; private static final int EN_LOWER_BEGINNING = 0x61; private static final int EN_LOWER_ENDING = 0x7A; private static final int EN_DIGIT_BEGINNING = 0x30; private static final int EN_DIGIT_ENDING = 0x39; //private static final int SYSTEM_HEX = 16; private UTFBasedEqualLengthCipher() { } /** * encrypt data * @param data data * @param key key * @return encrypted data */ public static String encrypt(String data, String key) { if (data == null) { return null; } int length = data.length(); int iKey = keyAscii(key); int enOffset = (iKey + length) % EN_ZONE_SPACE;//0x15 = 21 int cnOffset = (iKey + length) % CN_ZONE_SPACE;//(0x9FA5 - 0x4E00)/3 = 0x1B37 StringBuffer sb = new StringBuffer(); char[] chars = data.toCharArray(); for (char c : chars) { if ((c >= EN_UPPER_BEGINNING && c <= EN_UPPER_ENDING) //@A ~ Z || (c >= EN_LOWER_BEGINNING && c <= EN_LOWER_ENDING) //a ~ z || (c >= EN_DIGIT_BEGINNING && c <= EN_DIGIT_ENDING))//0 ~ 9 { char newChar = encryptEN(c, enOffset); sb.append(newChar); } else if (c >= RED_BEGINNING && c <= BLUE_ENDING) { char newChar = encryptCN(c, cnOffset); sb.append(newChar); } else { sb.append(c); } } return sb.toString(); } /** * decrypt data * @param data data * @param key key * @return decrypted data */ public static String decrypt(String data, String key) { if (data == null) { return null; } int length = data.length(); int iKey = keyAscii(key); int enOffset = (iKey + length) % EN_ZONE_SPACE;//0x15 = 21 int cnOffset = (iKey + length) % CN_ZONE_SPACE;// (0x9FA5 - 0x4E00)/3 = 0x1B37 StringBuffer sb = new StringBuffer(); char[] chars = data.toCharArray(); for (char c : chars) { if ((c >= EN_UPPER_BEGINNING && c <= EN_UPPER_ENDING) //@A ~ Z || (c >= EN_LOWER_BEGINNING && c <= EN_LOWER_ENDING) //a ~ z || (c >= EN_DIGIT_BEGINNING && c <= EN_DIGIT_ENDING))//0 ~ 9 { char newChar = decryptEN(c, enOffset); sb.append(newChar); } else if (c >= RED_BEGINNING && c <= BLUE_ENDING) { char newChar = decryptCN(c, cnOffset); sb.append(newChar); } else { sb.append(c); } } return sb.toString(); } /** * encrypt cn * red[0x4E00 ~ 0x6936] * yellow[0x6937 ~ 0x846D] * blue[0x846F ~ 0x9fa5] * red --> yellow,blue * yellow --> blue,red * blue -- > red,yellow * @param c character * @param offset offset * @return new character */ private static char encryptCN(char c, int offset) { if (isInRedCN(c)) { int position = c - RED_BEGINNING;//position in red zone char newChar = (char) (YELLOW_BEGINNING + position + offset); if (isInYellowCN(newChar)) { return newChar;//mapping in yellow zone } else { return (char) (BLUE_BEGINNING + (newChar - YELLOW_ENDING));//mapping in blue zone } } else if (isInYellowCN(c)) { int position = c - YELLOW_BEGINNING;//position in yellow zone char newChar = (char) (BLUE_BEGINNING + position + offset); if (isInBlueCN(newChar)) { return newChar;//mapping in blue zone } else { return (char) (RED_BEGINNING + (newChar - BLUE_ENDING));//mapping in red zone } } else if (isInBlueCN(c)) { int position = c - BLUE_BEGINNING;//position in blue zone char newChar = (char) (RED_BEGINNING + position + offset); if (isInRedCN(newChar)) { return newChar;//mapping in red zone } else { return (char) (YELLOW_BEGINNING + (newChar - RED_ENDING));//mapping in yellow zone } } return c; } /** * red --> yellow,blue * yellow --> blue,red * blue -- > red,yellow * @param c character * @param offset offset * @return new character */ private static char encryptEN(char c, int offset) { int index = 0; if ((index = getIndex(c, EN_RED)) != -1) { int newIndex = index + offset; if (newIndex >= EN_ZONE_SPACE) { return EN_BLUE[newIndex - EN_ZONE_SPACE]; } else { return EN_YELLOW[newIndex]; } } else if ((index = getIndex(c, EN_YELLOW)) != -1) { int newIndex = index + offset; if (newIndex >= EN_ZONE_SPACE) { return EN_RED[newIndex - EN_ZONE_SPACE]; } else { return EN_BLUE[newIndex]; } } else if ((index = getIndex(c, EN_BLUE)) != -1) { int newIndex = index + offset; if (newIndex >= EN_ZONE_SPACE) { return EN_YELLOW[newIndex - EN_ZONE_SPACE]; } else { return EN_RED[newIndex]; } } return c; } private static char decryptCN(char c, int offset) { char newChar = (char) (c - offset); if (isInRedCN(c)) { if (isInRedCN(newChar)) { return (char) (newChar - RED_BEGINNING + BLUE_BEGINNING);//search in blue zone } else { return (char) (newChar - RED_BEGINNING + YELLOW_ENDING);//search in yellow zone } } else if (isInYellowCN(c)) { if (isInYellowCN(newChar)) { return (char) (newChar - YELLOW_BEGINNING + RED_BEGINNING);//search in red zone } else { return (char) (newChar - YELLOW_BEGINNING + BLUE_ENDING);//search in blue zone } } else if (isInBlueCN(c)) { if (isInBlueCN(newChar)) { return (char) (newChar - BLUE_BEGINNING + YELLOW_BEGINNING);//search in yellow zone } else { return (char) (newChar - BLUE_BEGINNING + RED_ENDING);//search in red zone } } return c; } private static char decryptEN(char c, int offset) { int index = 0; if ((index = getIndex(c, EN_RED)) != -1) { int newIndex = index - offset; if (newIndex >= 0) { return EN_BLUE[newIndex]; } else { return EN_YELLOW[EN_ZONE_SPACE + newIndex]; } } else if ((index = getIndex(c, EN_YELLOW)) != -1) { int newIndex = index - offset; if (newIndex >= 0) { return EN_RED[newIndex]; } else { return EN_BLUE[EN_ZONE_SPACE + newIndex]; } } else if ((index = getIndex(c, EN_BLUE)) != -1) { int newIndex = index - offset; if (newIndex >= 0) { return EN_YELLOW[newIndex]; } else { return EN_RED[EN_ZONE_SPACE + newIndex]; } } return c; } private static boolean isInRedCN(char c) { if (c >= RED_BEGINNING && c <= RED_ENDING)//[0x4E00 ~ 0x6937] { return true; } return false; } private static boolean isInYellowCN(char c) { if (c >= YELLOW_BEGINNING && c <= YELLOW_ENDING)//[0x6938 ~ 0x846e] { return true; } return false; } private static boolean isInBlueCN(char c) { if (c >= BLUE_BEGINNING && c <= BLUE_ENDING)//[0x846f ~ 0x9fa5] { return true; } return false; } private static int getIndex(char c, char[] area) { for (int i = 0; i < area.length; i++) { if (area[i] == c) { return i; } } return -1; } private static int keyAscii(String key) { int ascii = 0; if (key == null) { return 0; } char[] chars = key.toCharArray(); for (char c : chars) { ascii += c; } return ascii; }}