java - 如何生成超过 2^30 个组合的随机唯一字符串。我也想扭转这个过程。这可能吗?

标签 java security random checksum xor

我有一个包含 3 个元素的字符串:

  • 3 位数代码(例如:SIN、ABD、SMS 等)
  • 1 位数字代码类型(例如:1、2、3 等)
  • 3 位数字(例如:500、123、345)

示例字符串:SIN1500、ABD2123、SMS3345 等。

我想生成一个唯一的 10 位字母数字和区分大小写的字符串(仅允许 0-9/a-z/A-Z),每个字符串提供超过 2^30(约 10 亿)个唯一组合。生成的代码必须具有特定的算法,以便我可以反转该过程。例如:

public static void main(String[] args) {
    String test = "ABD2123";
    String result = generateData(test);
    System.out.println(generateOutput(test)); //for example, the output of this is: 1jS8g4GDn0
    System.out.println(generateOutput(result)); //the output of this will be ABD2123 (the original string supplied)
}

我想问的是java中是否有任何想法/示例/库可以做到这一点?或者至少有关于我应该在谷歌上放置什么关键字的提示?

我尝试使用关键字 java checksum、rng、security、random number 等进行谷歌搜索,还尝试查看一些随机数解决方案(java SecureRandom、xorshift RNG、java.util.zip 的 checksum 等),但我似乎找不到?

谢谢!

编辑:

我对该程序的用例是生成某种唯一的优惠券编号以供特定客户使用。

提供的字符串将包含 3 位数的公司 ID 代码、1 位数的凭证类型代码以及 3 位数的凭证名称。我还尝试添加 3 个随机字母数字(因此最后的数字是 7 + 3 位数字 = 10 位数字)。这是我到目前为止所做的,但结果不是很好(只有大约10万个组合):

public static String in ="somerandomstrings";
public static String out="someotherrandomstrings";

public static String encrypt(String kata)
throws Exception {
    String result="";
    String ina=in;
    String outa=out;
    Random ran = new Random();
    Integer modulus=in.length();
    Integer offset= ((Integer.parseInt(Utils.convertDateToString(new Date(), "SS")))+ran.nextInt(60))/2%modulus;

    result=ina.substring(offset, offset+1);
    ina=ina+ina;
    ina=ina.substring(offset, offset+modulus);
    result=result+translate(kata, ina, outa);

    return result;
}

编辑:

很抱歉我忘记添加“翻译”功能:

    public static String translate(String kata,String  seq1, String  seq2){
    String result="";
    if(kata!=null&seq1!=null&seq2!=null){
        String[] a=kata.split("");
        for (int j = 1; j < a.length; j++) {
            String b=a[j];                      
            String[]seq1split=seq1.split("");
            String[]seq2split=seq2.split("");
            int hint=seq1.indexOf(b)+1;

            String sq="";
            if(seq1split.length>hint)
                sq=seq1split[hint];
            String sq1="";
            if(seq2split.length>hint)
                sq1=seq2split[hint];

            b=b.replace(sq, sq1);

            result=result+b;
        }
    }
    return result;
}

编辑:

好吧,几天后我正在努力转换 @sarnold 提供的 Ruby 代码,这是我想出的代码:

public class Test {

static char START_A = "A".charAt(0);
static char START_a = "a".charAt(0);
static char START_0 = "0".charAt(0);
static int CODEMASK = ((1 << 28) - 1); //turn on lower 28 bits
static int RANDOMMASK = ((1 << 60) - 1) & ~ CODEMASK; //turn on upper 32 bits

public static void main(String[] args) {

    String[] test = new String[]{
            //"AAA0000", "SIN1500", "ABD2123", "SMS3345", "ZZZ9999",
            //"ABD2123", "ABD2123", "ABD2123", "ABD2123", "ABD2123"
            "ABD2123"
            };

    for(String t : test){
        long c = compress(t);
        long a = add_random(c);
        String output = to_output(a);
        long input = from_output(output);

        String[] new_c_r = remove_random(input);
        String u = uncompress(Long.valueOf(new_c_r[0]));

        System.out.println("Original input: " + t);
        System.out.println("    compressed: " + c);
        System.out.println("    after adding random amount: " + a);
        System.out.println("    *output: " + output);
        System.out.println("    *input: " + input);
        System.out.println("    random amount added: " + new_c_r[1]);
        System.out.println("    after removing random amount: " + new_c_r[0]);
        System.out.println("    uncompressed: " + u);
        System.out.println("-----------------------------------------------------------------");
    }

}

public static long compress(String line){ //7 character
    char a = line.charAt(0);
    char b = line.charAt(1);
    char c = line.charAt(2);
    char h = line.charAt(3);
    char i = line.charAt(4);
    char j = line.charAt(5);
    char k = line.charAt(6);

    long small_a = (long) a - START_A;
    long small_b = (long) b - START_A;
    long small_c = (long) c - START_A;
    long letters = (small_a * 26 * 26) + (small_b * 26) + small_c;
    long numbers = letters * 10000 + h * 1000 + i*100 + j*10 + k;
    return numbers;
}

public static String uncompress(long number){
    long k = number % 10;
    number /= 10;
    long j = number % 10;
    number /= 10;
    long i = number % 10;
    number /= 10;
    long h = number % 10;
    number /= 10;
    long small_c = number % 26;
    number /= 26;
    long small_b = number % 26;
    number /= 26;
    long small_a = number % 26;
    number /= 26;

    if (number != 0) throw new RuntimeException("input wasn't generated with compress()");

    long a = small_a + START_A;
    long b = small_b + START_A;
    long c = small_c + START_A;

    StringBuffer result = new StringBuffer();
    result.append((char) a).append((char) b).append((char) c).append(h).append(i).append(j).append(k);

    return result.toString();
}

public static long add_random(long number){
    return (((long) (Math.random()* Math.pow(2, 31))) << 28) + number;
}

public static String[] remove_random(long number){
    return new String[]{String.valueOf(number & CODEMASK), String.valueOf(number & RANDOMMASK)};
}

public static String to_output(long number){
    List<Character> a = new ArrayList<Character>();
    do{
        a.add(transform_out(number % 62));
        number /= 62;
    }while(number > 0);

    Collections.reverse(a);

    StringBuffer result = new StringBuffer();
    for(int i=0; i<a.size(); i++){
        Character s = (Character) a.get(i);
        result.append(s);
    }

    return result.toString();
}

public static long from_output(String string){
    long num = 0;
    for(char c : string.toCharArray()){
        num *= 62;
        num += transform_in(c);
    }
    return num;
}

public static char transform_out(long small){
    long out;

    if (small < 0 || small > 61){
        throw new RuntimeException("small should be between 0 and 61, inclusive");
    }
    if(small < 26){
        out = START_A + small;
    }else if(small < 52){
        out = START_a + (small-26);
    }else{
        out = START_0 + (small-52);
    }
    return (char) out;
}


public static long transform_in(char c){
    if(!String.valueOf(c).matches("[a-zA-Z0-9]")){ 
        throw new RuntimeException("char should be A-Z, a-z, or 0-9, inclusive");
    }
    long num = (long) c;

    long out;
    if(num >= START_A && num <= START_A+26) out = num-START_A;
    else if(num >= START_a && num <= START_a+26) out = (num-START_a) + 26;
    else if(num >= START_0 && num <= START_0+10) out = (num-START_0) + 52;
    else throw new RuntimeException("Salah, bego!");

    return out;
}}

但我似乎无法使这段代码正确,结果是这样的:

Original input: ABD2123
compressed: 345451
after adding random amount: 62781252268541291
*output: EnhZJdRFaj
*input: 62781252268541291
random amount added: 0
after removing random amount: 345451
uncompressed: ABI5451

您可能已经注意到“压缩”和“未压缩”字段没有显示相同的数量。 “随机添加量”字段也始终返回 0 值。 有没有人可以帮我看看这段代码哪里错了?

很抱歉,如果将此代码放入此线程中是错误的,我将创建另一个线程。

谢谢你, 优素福

最佳答案

你的要求很不明确。所以我将把我的答案限制为一般性:

有一些称为加密哈希函数的函数,可以将任意字节序列映射到“哈希”,其特性是任何两个相关输入给出相同输出的概率非常小。然而,加密哈希函数(根据设计)是不可逆的......根据设计。

从字符串的一个“空间”到另一个可逆的映射可以通过两种方式实现:

  • 您可以生成任意字符串作为映射字符串,并使用哈希表等数据结构来存储正向和反向映射。

  • 您可以使用加密哈希函数来生成映射的字符串,并使用哈希表等数据结构来存储反向映射。

  • 您可以使用可逆函数在原始字符串和映射字符串之间进行转换。这存在一个问题,即映射可能很容易进行逆向工程。

后者的一个示例可能是将原始字符串转换为字节,然后对其进行 Base64 编码。或者更简单的是,您可以在输入字符串中的每个字符之间插入一个随机字符。 (显然,如果有足够多的例子,像这样的转换可以在几分钟内进行逆向工程。所以人们不得不怀疑这种方法的智慧。)

如果没有更好的要求,就不清楚您需要这些方法中的哪一种(如果有的话)。

关于java - 如何生成超过 2^30 个组合的随机唯一字符串。我也想扭转这个过程。这可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5293967/

相关文章:

java - 这段代码有什么问题?

java - 设置类变量的最佳方法是什么,它是基于 java 中依赖枚举的某些条件逻辑的枚举?

java - 从 XML 或 JSON 反序列化不受信任的数据

sql-server-2005 - 微软 SQL Server 2005 : Error log is too big and getting bigger

每次我执行查询时,MySQL 注入(inject) : If I use a function that replaces\, <, >, ', "及其 HTML 代码,它是防弹的吗?

c++ - rand() 在 OS X Mavericks/XCode 5.1 上坏了吗? (或者, "is this a massive security hole, or am I just a bad programmer??")

java - 数组洗牌(具有相同的开始值和结束值)

java - 从数据库中检索时间戳记录

java - 为什么这个生成随机数的程序不断生成数百个数字?

java - 如何避免调用 handler.postDelayed(Runnable run) ?