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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 22:49:56  来源:igfitidea点击:

Simple algorithm for mixing/obfuscating a string with pre-defined chars

java

提问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 encryptedStringis encrypted and stored in base64 format.

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

You can easily find how to decrypt the string back. Good luck.

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