固定长度Int混淆器。有谁知道如何做到这一点?

时间:2014-02-24 11:36:20

标签: c#

我使用泛型类将INT转换为X base:

BaseX basex = new BaseX("abcdefghijklmnopqrstuvwxyz");

var a = basex.ToBaseX(1002);
var b = basex.FromBaseX("aghe");

BaseX类如下:

public class BaseX {
  private readonly string _digits;

  public BaseX(string digits) {
    _digits = digits;
  }
  public string ToBaseX(int number) {
    var output = "";
    do {
      output = _digits[number % _digits.Length] + output;
      number = number / _digits.Length;
    }
    while (number > 0);
    return output;
  }

  public int FromBaseX(string number) {
    return number.Aggregate(0, (a, c) => a * _digits.Length + _digits.IndexOf(c));
  }
}

我使用的是小写字母,但我可以使用任何其他基础。

是否可以使基本X中的输出始终具有相同的长度?

我认为我应该使用“Multiplicative Inverse”和一些类似的映射和编码过程,但我不知道该怎么做...

我可以帮助创建这个吗?

基本上,我的目标是创建一个固定长度的INT(数据库中的ID),而不是创建随机固定长度代码以用于促销或ID混淆。

谢谢你, 米格尔

1 个答案:

答案 0 :(得分:4)

如果我理解正确,你想用“零”填充生成的值。例如。如果您使用普通数字并且您想要一个长度为10且ID为1234的ID,则填充的ID将为0000001234。

最简单的方法是填充生成的值。您可以向BaseX类添加新方法:

public string ToBaseX(int number, int width) {
  var output = ToBaseX(number);
  return output.PadLeft(width, _digits[0]);
}

使用此方法basex.ToBaseX(1002, 10)返回

aaaaaaabmo

basex.FromBaseX("aaaaaaabmo")返回

1002

在评论中,您指出结果字符串aaaaaaabmo似乎不是随机的。但是,您可以使用Eric Lippert在您所指的文章A practical use of multiplicative inverses中描述的方法。

首先,您需要为要混淆的数字选择一个上限(此数字应该适合32位整数)。 Eric Lippert使用了10亿(10亿)。然后,您需要选择一个小于极限的极限值(例如,它们不共享任何素因子)。 Eric Lippert选择了387420489(并解释说,以9结尾的任何数字都将是一个10的幂数的互质)。然后,您需要计算此数字的模乘乘数,例如,满足以下条件的数字inverse-x

387420489 * inverse-x = 1 (mod 1000000000)

您可以使用扩展欧几里德算法进行此计算,例如使用an online calculator。模乘法逆是513180409。

要对您的编号进行模糊处理,您可以使用此代码(为避免溢出,使用64位整数执行计算非常重要):

var value = 1002;
var m = 1000000000L;
var x = 387420489L;
var inverseX = 513180409L;
var encoded = value*x%m;
var decoded = encoded*inverseX%m;  

对于此特定计算,encoded为195329978。

如果您想使用小写字母来表示模糊编号,您可以使用BaseX类将数字转换为基数26.您可以计算代表10亿以下任何数字所需的最大字母数:

Math.Log(1000000000)/Math.Log(26) = 6.36054383137796

这意味着您需要不超过7个字母来代表您的电话号码。

我已将所有这些结合到两个简单的方法中,使用一些您可以轻松自定义的常量:

static class Obfuscator {

  const Int64 modulo = 1000000000L;

  const Int64 coprime = 280619659L;

  const Int64 inverseCoprime = 687208739L;

  const String digits = "abcdefghijklmnopqrstuvwxyz";

  const Int32 maxDigits = 7; // Math.Log(modulo)/Math.Log(digits.Length) rounded up.

  public static String Obfuscate(Int32 originalValue) {
    if (originalValue >= modulo || originalValue < 0)
      throw new ArgumentOutOfRangeException();
    var value = (Int32) (originalValue*coprime%modulo);
    var buffer = new Char[maxDigits];
    var i = maxDigits;
    do {
      buffer[--i] = digits[value%digits.Length];
      value /= digits.Length;
    } while (value > 0);
    while (i > 0)
      buffer[--i] = digits[0];
    return new String(buffer);
  }

  public static Int32 Deobfuscate(String obfuscatedValue) {
    if (String.IsNullOrEmpty(obfuscatedValue))
      throw new ArgumentException();
    var value = obfuscatedValue
      .Aggregate(0, (a, c) => a*digits.Length + digits.IndexOf(c));
    return (Int32) (value*inverseCoprime%modulo);
  }

}

只有要注意的细节是0被混淆为aaaaaaa。对于介于1和999999999之间的任何数字(包括7和999字符),您将得到一个7个字符的随机字符串。