瀏覽代碼

add IDObfuscation

reghao 11 月之前
父節點
當前提交
6c95ea578d
共有 1 個文件被更改,包括 136 次插入0 次删除
  1. 136 0
      jdk/src/main/java/cn/reghao/jutil/jdk/string/IDObfuscation.java

+ 136 - 0
jdk/src/main/java/cn/reghao/jutil/jdk/string/IDObfuscation.java

@@ -0,0 +1,136 @@
+package cn.reghao.jutil.jdk.string;
+
+/**
+ * ID 混淆算法
+ * https://gist.github.com/megayu/d42e7b209954f459f9a76b79287cfa58
+ *
+ * @author reghao
+ * @date 2025-03-29 18:39:54
+ */
+public class IDObfuscation {
+    private static final char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
+    private static final int BASE = ALPHABET.length;
+    private static final byte[] PADDING = {0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17};
+    private static final byte NEGATIVE = 0x2A;
+    private final int key;
+
+    public IDObfuscation(int key) {
+        this.key = key;
+    }
+
+    public String obfuscate(long id) {
+        return toStr(swap(id));
+    }
+
+    private String toStr(long n) {
+        byte[] bytes = Long.toString(n).getBytes();
+        int len = bytes.length;
+        int paddingLen = 0;
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i <= 16; i += 4) {
+            int chunk;
+            if (i + 4 <= len) {
+                chunk = encode(bytes, i, i + 4);
+            } else if (i <= len) {
+                chunk = encode(bytes, i, len, paddingLen, 4 + i - len);
+                paddingLen += len - i;
+            } else {
+                chunk = encode(paddingLen, 4);
+                paddingLen += 4;
+            }
+            while (chunk > 0) {
+                chunk = mod(chunk, sb);
+            }
+        }
+        return sb.reverse().toString();
+    }
+
+    private int mod(int i, StringBuilder sb) {
+        sb.append(ALPHABET[i % BASE]);
+        return i / BASE;
+    }
+
+    private int encode(int paddingStartIndex, int paddingNum) {
+        int n = 0;
+        for (int i = 0; i < paddingNum; i++) {
+            n += PADDING[paddingStartIndex + i] << (paddingNum - 1 - i) * 8;
+        }
+        return n;
+    }
+
+    private int encode(byte[] bytes, int start, int end, int paddingStartIndex, int paddingNum) {
+        return encode(bytes, start, end) + encode(paddingStartIndex, paddingNum);
+    }
+
+    private int encode(byte[] bytes, int start, int end) {
+        int n = 0;
+        for (int i = start; i < end; i++) {
+            n += (bytes[i] - 3) << (3 - i) * 8;
+        }
+        return n;
+    }
+
+    private long swap(long i) {
+        long low = i & 0xFFFFFFFFL;
+        long high = i >> 32 & 0xFFFFFFFFL ^ opaque(low);
+        return ((low ^ opaque(high)) << 32) + high;
+    }
+
+    private long opaque(long i) {
+        i = ((i ^ key) + 0x7886) * 0xEA03122921L;
+        return i >> (i & 0xF) & 0xFFFFFFFFL;
+    }
+
+    public long restore(String obfuscatedId) {
+        if (obfuscatedId == null || obfuscatedId.length() != 25) throw new IllegalArgumentException("invalid obfuscatedId");
+        try {
+            return swap(toLong(obfuscatedId));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("invalid obfuscatedId");
+        }
+    }
+
+    private long toLong(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 25; i >= 5; i -= 5) {
+            String chunk = decode(base(s.substring(i - 5, i)));
+            sb.append(chunk);
+            if (chunk.length() < 4) break;
+        }
+        return Long.parseLong(sb.toString());
+    }
+
+    private String decode(int n) {
+        char[] c = new char[4];
+        int i = 3;
+        for (; i >= 0; i--) {
+            int x = (n >> i * 8) & 0xFF;
+            if (x <= PADDING[0]) {
+                return i == 3 ? "" : new String(c, 0, 3 - i);
+            } else if (x == NEGATIVE) {
+                c[3 - i] = '-';
+            } else {
+                c[3 - i] = (char) (x + 3);
+            }
+        }
+        return new String(c);
+    }
+
+    private int base(String s) {
+        int n = 0;
+        int power = 1;
+        for (int i = s.length() - 1; i >= 0; i--) {
+            int digit = s.charAt(i);
+            if (digit <= '9') {
+                digit += 4;//52 - 48
+            } else if (digit >= 'a') {
+                digit -= 71;//26 - 97
+            } else {
+                digit -= 65;
+            }
+            n += digit * power;
+            power *= BASE;
+        }
+        return n;
+    }
+}