package com.app.mvc.util; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import java.util.List; /** * 通用加密解密工具,支持Integer加密解密。生成10位加密结果 * Created by jimin on 16/2/10 */ @Slf4j public class IDEncryptor { //TODO use object pool to reuse IDEncryptor //Take care! IDEncryptor is not thread safe //so to resue IDEncryptor, we have to set up //a pool, maybe we should consider apache common pool private static IDEncryptor getInstance() { return new IDEncryptor(DEFAULT_KEY); } ////////////////// // Private Data // ////////////////// /** * Non-zero default key, from www.random.org */ private final static int DEFAULT_KEY = 0x6CFB18E2; private static long LARGE_VAL = 1l << 32; private final static int LOW_16_MASK = 0xFFFF; private final static int HALF_SHIFT = 16; private final static int NUM_ROUNDS = 4; /** * Permutation key */ private int mKey; /** * Round key schedule */ private int[] mRoundKeys = new int[NUM_ROUNDS]; ////////////////// // Constructors // ////////////////// private IDEncryptor() { this(DEFAULT_KEY); } private IDEncryptor(int key) { setKey(key); } //////////////////// // Public Methods // //////////////////// /** * Sets a new value for the key and key schedule. */ private void setKey(int newKey) { assert (NUM_ROUNDS == 4) : "NUM_ROUNDS is not 4"; mKey = newKey; mRoundKeys[0] = mKey & LOW_16_MASK; mRoundKeys[1] = ~(mKey & LOW_16_MASK); mRoundKeys[2] = mKey >>> HALF_SHIFT; mRoundKeys[3] = ~(mKey >>> HALF_SHIFT); } // end setKey() /** * Returns the current value of the key. */ private int getKey() { return mKey; } /** * Calculates the enciphered (i.e. permuted) value of the given integer * under the current key. * * @param plain the integer to encipher. * @return the enciphered (permuted) value. */ private long encipher(int plain) { // 1 Split into two halves. int rhs = plain & LOW_16_MASK; int lhs = plain >>> HALF_SHIFT; // >>>表示无符号右移位 // 2 Do NUM_ROUNDS simple Feistel rounds. for (int i = 0; i < NUM_ROUNDS; ++i) { if (i > 0) { // Swap lhs <-> rhs final int temp = lhs; lhs = rhs; rhs = temp; } // end if // Apply Feistel round function F(). rhs ^= F(lhs, i); } // end for // 3 Recombine the two halves and return. long v = (lhs << HALF_SHIFT) + (rhs & LOW_16_MASK); //把负数变成正数 if (v < 0) { v += LARGE_VAL; } return v; } // end encipher() /** * Calculates the deciphered (i.e. inverse permuted) value of the given * integer under the current key. * * @return the deciphered (inverse permuted) value. */ private int decipher(long cypherlong) { int cypher = 0; if (cypherlong > Integer.MAX_VALUE) { cypher = (int) (cypherlong - LARGE_VAL); } else { cypher = (int) cypherlong; } // 1 Split into two halves. int rhs = cypher & LOW_16_MASK; int lhs = cypher >>> HALF_SHIFT; // 2 Do NUM_ROUNDS simple Feistel rounds. for (int i = 0; i < NUM_ROUNDS; ++i) { if (i > 0) { // Swap lhs <-> rhs final int temp = lhs; lhs = rhs; rhs = temp; } // end if // Apply Feistel round function F(). rhs ^= F(lhs, NUM_ROUNDS - 1 - i); } // end for // 4 Recombine the two halves and return. return (lhs << HALF_SHIFT) + (rhs & LOW_16_MASK); } // end decipher() ///////////////////// // Private Methods // ///////////////////// // The F function for the Feistel rounds. private int F(int num, int round) { // XOR with round key. num ^= mRoundKeys[round]; // Square, then XOR the high and low parts. num *= num; return (num >>> HALF_SHIFT) ^ (num & LOW_16_MASK); } // end F() private String encryptWithoutException(int id) { String str = null; try { str = this.encrypt(id); } catch (Exception e) { log.warn("error in encrypt. id:" + id); // e.printStackTrace(); } return str; } private int decryptWithoutException(String str) { int id = -1; try { id = this.decipher(Long.valueOf(str)); } catch (Exception e) { log.warn("error in decrypt. str:" + str); // e.printStackTrace(); } return id; } /** * 产生异常的解密方式 * * @param str * @return * @throws Exception */ public static int decrypt(String str) throws Exception { return getInstance().decipher(Long.valueOf(str)); } /** * 进行批量的解密 * * @param ids * @return * @throws Exception 其中有一个id出错就抛出异常 */ public static List<Integer> decrypt(List<String> ids) throws Exception { List<Integer> list = Lists.newArrayList(); for (String id : ids) { list.add(decrypt(id)); } return list; } /** * 批量解密id,这些id使用separator进行分割。 * * @param ids * @param separator * @return * @throws Exception */ public static List<Integer> decrypt(String ids, String separator) throws Exception { List<Integer> list = Lists.newArrayList(); for (String id : Splitter.on(separator).trimResults().omitEmptyStrings().split(ids)) { list.add(decrypt(id)); } return list; } /** * 产生异常的加密方式 * * @param id * @return * @throws Exception */ public static String encrypt(int id) throws Exception { return "" + getInstance().encipher(id); } /** * 进行批量的加密 * * @param ids * @return */ public static List<String> encrypt(List<Integer> ids) throws Exception { List<String> list = Lists.newArrayList(); for (Integer id : ids) { list.add(encrypt(id)); } return list; } /** * 进行批量的加密,将加密结果拼接成一个字符串,使用separator指定 * * @param ids * @param separator * @return */ public static String encrypt(List<Integer> ids, String separator) throws Exception { StringBuilder sb = new StringBuilder(); for (int i = 0; i < ids.size(); i++) { if (i != 0) { sb.append(separator); } sb.append(encrypt(ids.get(i))); } return sb.toString(); } /** * 使用源有方式,代码太长,很不好看,因此这里提供了encode,用来代替 * IDEncryptor.getInstance().encryptWithoutException() * 现在只需 * import static com.qunar.vacation.b2c.util.IDEncryptor.*; * 直接使用encode和decode即可 * <p/> * {@link #encryptWithoutException(int)} * * @param id * @return 如果错误的id,那么将会返回null */ public static String encode(int id) { return getInstance().encryptWithoutException(id); } /** * 加密id的便捷方法 * * @param id {@link #encryptWithoutException(int)} * @return 如果id==null那么返回null * 如果产生异常那么返回null */ public static String encode(Integer id) { if (id == null) return null; return getInstance().encryptWithoutException(id); } /** * 进行批量的加密 * * @param ids * @return */ public static List<String> encode(List<Integer> ids) { List<String> list = Lists.newArrayList(); for (Integer id : ids) { list.add(encode(id)); } return list; } /** * 进行批量的加密,将加密结果拼接成一个字符串,使用separator指定 * * @param ids * @param separator * @return */ public static String encode(List<Integer> ids, String separator) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < ids.size(); i++) { if (i != 0) { sb.append(separator); } //tolerate the null String result = encode(ids.get(i)); if (!Strings.isNullOrEmpty(result)) { sb.append(result); } } return sb.toString(); } /** * 解密id的便捷方法 * <p/> * {@link #decryptWithoutException(String)} * * @param id * @return 如果id==null,那么返回null * 如果id发生错误那么返回-1 */ public static Integer decode(String id) { if (Strings.isNullOrEmpty(id)) return null; return getInstance().decryptWithoutException(id); } /** * 进行批量的解密 * * @param ids * @return */ public static List<Integer> decode(List<String> ids) { List<Integer> list = Lists.newArrayList(); for (String id : ids) { list.add(decode(id)); } return list; } /** * 批量解密id,这些id使用separator进行分割。 * * @param ids * @param separator * @return */ public static List<Integer> decode(String ids, String separator) { List<Integer> list = Lists.newArrayList(); for (String id : Splitter.on(separator).trimResults().omitEmptyStrings().split(ids)) { Integer result = decode(id); //tolerate the illegal result if (result != null && !result.equals(-1)) { list.add(result); } } return list; } }