具有不同字母长度的替代密码 [英] substitution cipher with different alphabet length

查看:90
本文介绍了具有不同字母长度的替代密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个简单的替换密码来掩盖URL中的私有ID。



我知道我的ID如何(大写ASCII字母,数字的组合和下划线),它们将是相当长的,因为它们是组合键。我想使用较长的字母表来缩短生成的代码(我想使用大小写ASCII字母,数字等等)。所以我输入的字母将是

  [A-Z0-9_](37个字符)

,我的传出字母将为

  [A-Za-z0-9](62个字符)

所以压缩几乎50%可以获得合理的压缩数量。



我们的网址如下所示:

  / my / page / GFZHFFFZFZTFZTF_24_F34 

我想要他们看起来像这样:

  / my / page / Ft32zfegZFV5 

显然,这两个数组都会被洗牌,以便带来一些随机顺序。



这不一定要安全。如果有人说出来:好的,但是我不希望这个方案是显而易见的。



我想要的解决方案是将字符串转换为基数的整数表示37,将小数转换为62,并使用第二个字母表写出该数字。有没有可用的示例代码做类似的事情? Integer.parseInt() 有一些类似的逻辑,但是使用标准数字行为是硬编码的。



任何想法?



我正在使用Java来实现这一点,但是使用任何其他语言的代码或伪代码当然也是有帮助的。

解决方案

不可思议的是, Character.MAX_RADIX 只有36,但你可以随时写你自己的基础转换程序。以下实现不是高性能的,但它应该是一个很好的起点:

  import java.math.BigInteger; 
public class BaseConvert {
static BigInteger fromString(String s,int base,String symbols){
BigInteger num = BigInteger.ZERO;
BigInteger biBase = BigInteger.valueOf(base);
for(char ch:s.toCharArray()){
num = num.multiply(biBase)
.add(BigInteger.valueOf(symbols.indexOf(ch)));
}
return num;
}
static String toString(BigInteger num,int base,String symbols){
StringBuilder sb = new StringBuilder();
BigInteger biBase = BigInteger.valueOf(base);
while(!num.equals(BigInteger.ZERO)){
sb.append(symbols.charAt(num.mod(biBase).intValue()));
num = num.divide(biBase);
}
return sb.reverse()。toString();
}
static String span(char from,char to){
StringBuilder sb = new StringBuilder();
for(char ch = from; ch <= to; ch ++){
sb.append(ch);
}
return sb.toString();
}
}

然后你可以有一个 main()测试工具如下:

  public static void main(String [] args) {
final String SYMBOLS_AZ09_ = span('A','Z')+ span('0','9')+_;
final String SYMBOLS_09AZ = span('0','9')+ span('A','Z');
final String SYMBOLS_AZaz09 = span('A','Z')+ span('a','z')+ span('0','9');

BigInteger n = fromString(GFZHFFFZFZTFZTF_24_F34,37,SYMBOLS_AZ09_);

//先转换回基数37
System.out.println(toString(n,37,SYMBOLS_AZ09_));
//打印GFZHFFFZFZTFZTF_24_F34

//现在让我们看看它在底层62中的外观...
System.out.println(toString(n,62,SYMBOLS_AZaz09 ));
//打印ctJvrR5kII1vdHKvjA4

//现在让我们用更熟悉的东西进行测试...
System.out.println(fromString(CAFEBABE, 16,SYMBOLS_09AZ));
//打印3405691582

n = BigInteger.valueOf(3405691582L);
System.out.println(toString(n,16,SYMBOLS_09AZ));
//打印CAFEBABE
}



一些观察




  • BigInteger 如果数字可以超过 long

  • 您可以在符号 String 中的 char 只要坚持一个秘密排列



关于50%压缩的注意事项



你不能一般期望base 62字符串的长度大约是基础36字符串的一半。这是$ 10 $,$ 20 $和$ 30 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ System.out.format(%s%n%s%n%s%n,
Long.toString(Long.MAX_VALUE,10),//9223372036854775807
Long.toString $ MAX_VALUE,20),//5cbfjia3fh26ja7
Long.toString(Long.MAX_VALUE,30)//hajppbc1fc207
);


I would like to implement a simple substitution cipher to mask private ids in URLs.

I know how my IDs will look like (combination of uppercase ASCII letters, digits and underscore), and they will be rather long, as they are composed keys. I would like to use a longer alphabet to shorten the resulting codes (I'd like to use upper- and lowercase ASCII letters, digits and nothing else). So my incoming alphabet would be

[A-Z0-9_] (37 chars)

and my outgoing alphabet would be

[A-Za-z0-9] (62 chars)

so a compression of almost 50% reasonable amount of compression would be available.

Let's say my URLs look like this:

/my/page/GFZHFFFZFZTFZTF_24_F34

and I want them to look like this instead:

/my/page/Ft32zfegZFV5

Obviously both arrays would be shuffled to bring some random order in.

This does not have to be secure. If someone figures it out: fine, but I don't want the scheme to be obvious.

My desired solution would be to convert the string to an integer representation of radix 37, convert the radix to 62 and use the second alphabet to write out that number. is there any sample code available that does something similar? Integer.parseInt() has some similar logic, but it is hard-coded to use standard digit behavior.

Any ideas?

I am using Java to implement this but code or pseudo-code in any other language is of course also helpful.

解决方案

Inexplicably Character.MAX_RADIX is only 36, but you can always write your own base conversion routine. The following implementation isn't high-performance, but it should be a good starting point:

import java.math.BigInteger;
public class BaseConvert {
    static BigInteger fromString(String s, int base, String symbols) {
        BigInteger num = BigInteger.ZERO;
        BigInteger biBase = BigInteger.valueOf(base);
        for (char ch : s.toCharArray()) {
            num = num.multiply(biBase)
                     .add(BigInteger.valueOf(symbols.indexOf(ch)));
        }
        return num;
    }
    static String toString(BigInteger num, int base, String symbols) {
        StringBuilder sb = new StringBuilder();
        BigInteger biBase = BigInteger.valueOf(base);
        while (!num.equals(BigInteger.ZERO)) {
            sb.append(symbols.charAt(num.mod(biBase).intValue()));
            num = num.divide(biBase);
        }
        return sb.reverse().toString();
    }
    static String span(char from, char to) {
        StringBuilder sb = new StringBuilder();
        for (char ch = from; ch <= to; ch++) {
            sb.append(ch);
        }
        return sb.toString();
    }
}

Then you can have a main() test harness like the following:

public static void main(String[] args) {
    final String SYMBOLS_AZ09_ = span('A','Z') + span('0','9') + "_";
    final String SYMBOLS_09AZ = span('0','9') + span('A','Z');
    final String SYMBOLS_AZaz09 = span('A','Z') + span('a','z') + span('0','9');

    BigInteger n = fromString("GFZHFFFZFZTFZTF_24_F34", 37, SYMBOLS_AZ09_);

    // let's convert back to base 37 first...
    System.out.println(toString(n, 37, SYMBOLS_AZ09_));
    // prints "GFZHFFFZFZTFZTF_24_F34"

    // now let's see what it looks like in base 62...       
    System.out.println(toString(n, 62, SYMBOLS_AZaz09));
    // prints "ctJvrR5kII1vdHKvjA4"

    // now let's test with something we're more familiar with...
    System.out.println(fromString("CAFEBABE", 16, SYMBOLS_09AZ));
    // prints "3405691582"

    n = BigInteger.valueOf(3405691582L);
    System.out.println(toString(n, 16, SYMBOLS_09AZ));
    // prints "CAFEBABE"        
}

Some observations

  • BigInteger is probably easiest if the numbers can exceed long
  • You can shuffle the char in the symbol String, just stick to one "secret" permutation

Note regarding "50% compression"

You can't generally expect the base 62 string to be around half as short as the base 36 string. Here's Long.MAX_VALUE in base 10, 20, and 30:

    System.out.format("%s%n%s%n%s%n",
        Long.toString(Long.MAX_VALUE, 10), // "9223372036854775807"
        Long.toString(Long.MAX_VALUE, 20), // "5cbfjia3fh26ja7"
        Long.toString(Long.MAX_VALUE, 30)  // "hajppbc1fc207"
    );

这篇关于具有不同字母长度的替代密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆