【问题标题】:substitution cipher with different alphabet length具有不同字母长度的替换密码
【发布时间】:2011-02-21 06:42:53
【问题描述】:

我想实现一个简单的替换密码来屏蔽 URL 中的私有 id。

我知道我的 ID 会是什么样子(大写 ASCII 字母、数字和下划线的组合),而且它们会相当长,因为它们是组合键。我想使用更长的字母来缩短生成的代码(我想使用大写和小写的 ASCII 字母、数字,仅此而已)。所以我传入的字母是

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

我的输出字母是

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

因此压缩率接近 50% 可以得到合理的压缩量。

假设我的网址如下所示:

/my/page/GFZHFFFZFZTFZTF_24_F34

我希望它们看起来像这样:

/my/page/Ft32zfegZFV5

显然两个数组都会被打乱以带来一些随机顺序。

这不一定是安全的。如果有人想通了:很好,但我不希望这个方案很明显。

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

有什么想法吗?

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

【问题讨论】:

    标签: java string algorithm encryption


    【解决方案1】:

    我现在有一个可行的解决方案,您可以在这里找到:

    http://pastebin.com/Mctnidng

    问题在于 a) 我在这部分的长代码中失去了精度:

    value = value.add(//
        BigInteger.valueOf((long) Math.pow(alphabet.length, i)) // error here
            .multiply(
                BigInteger.valueOf(ArrayUtils.indexOf(alphabet, c))));
    

    (只是不够长)

    和 b) 每当我有一个以字母表中偏移量 0 处的字符开头的文本时,它就会被删除,所以我需要添加一个长度字符(单个字符在这里就可以了,因为我的代码永远不会和字母一样长)

    【讨论】:

      【解决方案2】:

      莫名其妙的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_);
      
          // 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"        
      }
      

      一些观察

      • 如果数字可以超过longBigInteger 可能是最简单的
      • 您可以将符号 String 中的 char 改组,只需坚持一个“秘密”排列

      关于“50% 压缩”的说明

      您通常不能期望 base 62 字符串的长度大约是 base 36 字符串的一半。这是基数为 10、20 和 30 的 Long.MAX_VALUE

          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"
          );
      

      【讨论】:

      • 是的,听起来和我现在写的代码一模一样。完成后我会发布我自己的答案
      【解决方案3】:

      【讨论】:

      • 这是正确的方向,但我想要一些更符合我自己需求的定制
      最近更新 更多