java 使用预定义字符混合/混淆字符串的简单算法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16384444/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simple algorithm for mixing/obfuscating a string with pre-defined chars
提问by boomboom
I have a string as follows:
我有一个字符串如下:
- Its length is 10.
- It represents base 36 and as such includes digits and uppercase letters.
- The origin of the string is a sequence being generated by the database, (i.e. from 1 and up), that is being converted to base 36.
- 它的长度是 10。
- 它表示基数为 36,因此包括数字和大写字母。
- 字符串的来源是由数据库生成的序列(即从 1 开始),该序列被转换为基数 36。
My problem is that the results of the conversion to base 36 conversion are also consecutive/sequential; for example:
我的问题是转base 36的结果也是连续/连续的;例如:
ID: 1402 -> 000000012Y ID: 1403 -> 000000012Z ID: 1404 -> 0000000130 ID: 1404 -> 0000000131 ID: 1404 -> 0000000132
ID: 1402 -> 000000012Y ID: 1403 -> 000000012Z ID: 1404 -> 0000000130 ID: 1404 -> 0000000131 ID: 1404 -> 0000000132
I'm looking for a short simple algorithm that can mix the base 36 result where:
我正在寻找一个简短的简单算法,可以混合 base 36 结果,其中:
- I can use only the allowed base 36 chars, (digits and uppercase letters).
- The algorithm is just for obfuscating/mixing the base 36 string; I don't need encryption etc.
- The main issue here is that the result won't be consecutive.
- I need to have the ability to deobfuscate/demix the obfuscation result.
- 我只能使用允许的基本 36 个字符(数字和大写字母)。
- 该算法仅用于混淆/混合 base 36 字符串;我不需要加密等。
- 这里的主要问题是结果不会是连续的。
- 我需要能够对混淆结果进行反混淆/分解。
I tried it with some shifting chars logic but I'm stuck in the consecutive result issue.
I guess I need to add some mathematical aspect here.
我尝试了一些转换字符逻辑,但我陷入了连续的结果问题。
我想我需要在这里添加一些数学方面的内容。
I would appreciate any ideas as simple as possible and if possible then with code example.
我希望尽可能简单的任何想法,如果可能,然后使用代码示例。
回答by maybeWeCouldStealAVan
Are you looking for something like this?
你在寻找这样的东西吗?
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)));
}
}
}
output:
输出:
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
Basically, this is a toy, totally non-secure, though fun to write, encryption algorithm. (Encryption really iswhat you asked for --- output that's unintelligible to others but reversible by you.) I've implemented a Feistel network (http://en.wikipedia.org/wiki/Feistel_cipher) using a simple prng as the f function.
基本上,这是一个玩具,完全不安全,但编写起来很有趣,加密算法。(加密确实是您所要求的 --- 其他人无法理解但您可以逆转的输出。)我已经使用简单的 prng实现了 Feistel 网络(http://en.wikipedia.org/wiki/Feistel_cipher)作为f 功能。
The results are pretty, though, right? DES, as suggested above, would be more secure. But, if you'd rather reinvent the wheel (I struggle with that impulse a bit myself) and real security isn't a concern, this is a reasonable place to start. BTW, DES is also based on a Feistel network.
不过,结果很漂亮,对吧?如上所述,DES 会更安全。但是,如果您更愿意重新发明轮子(我自己也有点与这种冲动作斗争)并且真正的安全性不是问题,那么这是一个合理的起点。顺便说一句,DES 也是基于 Feistel 网络的。
Actually, a non-encryption-based solution might exist, depending on your requirements. If this is, say, a coupon code that needs to be checked but not guessed, I'd just create a table in my database relating the id to a randomly-generated 10 character code (or add the code column to an existing table of coupons) and look them up as they come in. This would of course require the encoding and recovering software to have access to the same database, or to be able to communicate.
实际上,可能存在非基于加密的解决方案,具体取决于您的要求。如果这是一个需要检查但不需要猜测的优惠券代码,我只需在我的数据库中创建一个表,将 id 与随机生成的 10 个字符代码相关联(或将代码列添加到优惠券)并在它们进来时查找它们。这当然需要编码和恢复软件能够访问相同的数据库,或者能够进行通信。
回答by Pablo Lozano
What about having just an array with the 36 characters in a random order? Something like a One-time pad encryption but with a fixed pad:
如果只拥有一个随机顺序包含 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<s.length();i++) {
char c=s.charAt(i);
int index=source.indexOf(c);
result[i]=target.charAt(index);
}
return new String(result);
}
public static String unobfuscate(String s) {
char[] result= new char[10];
for (int i=0;i<s.length();i++) {
char c=s.charAt(i);
int index=target.indexOf(c);
result[i]=source.charAt(index);
}
return new String(result);
}
So a 10 characters string like "HELLO12345"
becomes "0ZCCF2MI1K"
. Obfuscated, but not encrypted
所以一个 10 个字符的字符串"HELLO12345"
就变成了"0ZCCF2MI1K"
. 混淆但未加密
回答by Ilya Gazman
This is a generic solution, this a very fast algorithm that can handle any string in any encoding.
这是一个通用的解决方案,这是一个非常快的算法,可以处理任何编码的任何字符串。
Source code
源代码
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);
}
}
Usage
用法
String obfuscate = Translator.obfuscate("Hi there");
System.out.println(obfuscate + " - " + Translator.unobfuscate(obfuscate));
Output:
输出:
¢áP¢£ - Hi there
回答by Ebbe M. Pedersen
Just reversethe bits on your counter before doing the base36 encoding. Something like this
在进行 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);
}
}
Result:
结果:
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
回答by AlexR
Unless this is a homework assignment I'd suggest you to use Base64 encoding: new sun.misc.BASE64Encoder().encode(string.getBytes())
.
除非这是家庭作业,否则我建议您使用 Base64 编码:new sun.misc.BASE64Encoder().encode(string.getBytes())
.
This does not encrypt string but makes it unreadable.
这不会加密字符串,但会使其不可读。
If you really want to encrypt the string use java cryptography API, e.g:
如果您真的想加密字符串,请使用 java 加密 API,例如:
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, password);
String encrypedStr = base64encoder.encode(cipher.doFinal(cleartext));
Now encryptedString
is encrypted and stored in base64 format.
现在encryptedString
已加密并以 base64 格式存储。
You can easily find how to decrypt the string back. Good luck.
您可以轻松找到如何解密字符串。祝你好运。