使用预定义字符混合/混淆字符串的简单算法

我有一个字符串如下:

  • 它的长度是10。
  • 它代表基数36,因此包括数字和大写字母。
  • 字符串的起源是由数据库生成的序列(即从1开始向上),其被转换为基数36。

我的问题是转换到base 36转换的结果也是连续的/顺序的; 例如:

ID: 1402 -> 000000012Y ID: 1403 -> 000000012Z ID: 1404 -> 0000000130 ID: 1404 -> 0000000131 ID: 1404 -> 0000000132 

我正在寻找一个简单的简单算法,可以将基数36的结果混合在一起:

  • 我只能使用允许的36个字符(数字和大写字母)。
  • 该算法仅用于混淆/混合基本36串; 我不需要加密等
  • 这里的主要问题是结果不会是连续的。
  • 我需要能够对混淆结果进行反混淆/分离。

我尝试了一些变化的字符逻辑,但我陷入了连续的结果问题。
我想我需要在这里添加一些数学方面。

我将尽可能简单地感谢任何想法,如果可能的话,我会感谢代码示例。

你在找这样的东西吗?

 import java.util.Locale; public class Obfuscate { //adjust to suit: final static int feistelRounds = 4; final static int randRounds = 4; final static int seed = 12345; // modulus for half a string: final static int mod = 60466176; //36^5 private static int f (int x) { // http://en.wikipedia.org/wiki/Linear_congruential_generator final int a = 12+1; final int c = 1361423303; x = (x + seed) % mod; int r = randRounds; while (r-- != 0) { x = (a*x+c) % mod; } return x; } public static String obfuscate (int i) { int a = i / mod; int b = i % mod; int r = feistelRounds; while (r-- != 0) { a = (a + f(b)) % mod; b = (b + f(a)) % mod; } return pad5(Integer.toString(a, 36)) + pad5(Integer.toString(b, 36)); } public static int illuminate (String s) { int a = Integer.valueOf(s.substring(0,5),36); int b = Integer.valueOf(s.substring(5,10),36); int r = feistelRounds; while (r-- != 0) { b = (b - f(a)) % mod; a = (a - f(b)) % mod; } // make the modulus positive: a = (a + mod)%mod; b = (b + mod)%mod; return a*mod+b; } public static String pad5(String s) { return String.format("%5s", s).replace(' ', '0').toUpperCase(Locale.ENGLISH); } public static String pad10(String s) { return String.format("%10s", s).replace(' ', '0').toUpperCase(Locale.ENGLISH); } // demonstration public static void main(String[] args) { for (int i = 0; i<20; i++) { System.out.printf("%08d -> %s -> %08d\n", i, obfuscate(i), illuminate(obfuscate(i))); } } } 

输出:

 00000000 -> P2TH9ZW2VI -> 00000000 00000001 -> G47GI9ZR9S -> 00000001 00000002 -> 75LFRK3FO2 -> 00000002 00000003 -> Y6ZF0U742C -> 00000003 00000004 -> P8DE94ASGM -> 00000004 00000005 -> G9RDIEEGUW -> 00000005 00000006 -> 7B5CROI596 -> 00000006 00000007 -> YCJC0YLTNG -> 00000007 00000008 -> PDXB98PI1Q -> 00000008 00000009 -> GFBAIIT6G0 -> 00000009 00000010 -> 7GP9RSWUUA -> 00000010 00000011 -> YI39030J8K -> 00000011 00000012 -> PJH89D47MU -> 00000012 00000013 -> GKV7IN7W14 -> 00000013 00000014 -> 7M96RXBKFE -> 00000014 00000015 -> YNN607F8TO -> 00000015 00000016 -> PP159HIX7Y -> 00000016 00000017 -> GQF4IRMLM8 -> 00000017 00000018 -> 7RT3R1QA0I -> 00000018 00000019 -> YT730BTYES -> 00000019 

基本上,这是一个玩具,完全不安全,虽然编写加密算法很有趣。 (加密确实是你要求的 – 输出对别人来说是难以理解的,但你可以逆转。)我使用一个简单的prng实现了一个Feistel网络( http://en.wikipedia.org/wiki/Feistel_cipher ) ffunction。

结果很漂亮,对吧? 如上所述,DES将更安全。 但是,如果你宁愿重新发明轮子(我自己也有点冲动),真正的安全性不是问题,这是一个合理的起点。 顺便说一下,DES也是基于Feistel网络。

实际上,根据您的要求,可能存在基于非加密的解决方案。 如果这是一个需要检查但没有猜到的优惠券代码,我只是在我的数据库中创建一个表,将id与随机生成的10个字符代码相关联(或者将代码列添加到现有的优惠券)并在他们进来时查看它们。这当然要求编码和恢复软件能够访问同一个数据库,或者能够进行通信。

那么只有一个随机顺序的36个字符的数组怎么样? 像一次性密码加密,但有一个固定的垫:

 static String source="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static String target="Q5A8ZWS0XEDC6RFVT9GBY4HNU3J2MI1KO7LP"; public static String obfuscate(String s) { char[] result= new char[10]; for (int i=0;i 

因此,像"HELLO12345"这样的10个字符的字符串变为"0ZCCF2MI1K" 。 模糊,但未加密

在执行base36编码之前,只需反转计数器上的位。 像这样的东西

 public static void main(String[] args) { for (int i = 1400; i < 1420; i++) { String base36 = Integer.toString(i, 36); String reverse = Integer.toString(Integer.reverse(i << 1), 36); System.out.println("i: " + i + " base36: " + base36 + " reverse: " + reverse); } } 

结果:

 i: 1400 base36: 12w reverse: 48ya68 i: 1401 base36: 12x reverse: m08ao0 i: 1402 base36: 12y reverse: d4laf4 i: 1403 base36: 12z reverse: uvvaww i: 1404 base36: 130 reverse: 8orsao i: 1405 base36: 131 reverse: qg1ssg i: 1406 base36: 132 reverse: hkesjk i: 1407 base36: 133 reverse: zbot1c i: 1408 base36: 134 reverse: 8464g i: 1409 base36: 135 reverse: hze6m8 i: 1410 base36: 136 reverse: 93r6dc i: 1411 base36: 137 reverse: qv16v4 i: 1412 base36: 138 reverse: 4nxo8w i: 1413 base36: 139 reverse: mf7oqo i: 1414 base36: 13a reverse: djkohs i: 1415 base36: 13b reverse: vauozk i: 1416 base36: 13c reverse: 2g0x6o i: 1417 base36: 13d reverse: k7axog i: 1418 base36: 13e reverse: bbnxfk i: 1419 base36: 13f reverse: t2xxxc 

这是一个通用的解决方案,这是一种非常快速的算法,可以处理任何编码中的任何字符串。

源代码

 public class Translator { private static final String key = "Zx" + Math.log(2) / 3; public static String obfuscate(String s) { char[] result = new char[s.length()]; for (int i = 0; i < s.length(); i++) { result[i] = (char) (s.charAt(i) + key.charAt(i % key.length())); } return new String(result); } public static String unobfuscate(String s) { char[] result = new char[s.length()]; for (int i = 0; i < s.length(); i++) { result[i] = (char) (s.charAt(i) - key.charAt(i % key.length())); } return new String(result); } } 

用法

 String obfuscate = Translator.obfuscate("Hi there"); System.out.println(obfuscate + " - " + Translator.unobfuscate(obfuscate)); 

输出:

 ¢áP¢£ - Hi there 

除非这是一个家庭作业,我建议你使用Base64编码: new sun.misc.BASE64Encoder().encode(string.getBytes())

这不会加密字符串但会使其无法读取。

如果你真的想加密字符串使用java加密API,例如:

  Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, password); String encrypedStr = base64encoder.encode(cipher.doFinal(cleartext)); 

现在, encryptedString被加密并以base64格式存储。

您可以轻松找到如何解密字符串。 祝你好运。