整数ID混淆技术

时间:2010-04-02 07:12:31

标签: c# encryption obfuscation

我正在寻找一种简单且可逆的混淆整数ID的方法。理想情况下,我希望得到的混淆最多为8个字符长度和非顺序,这意味着“1”的混淆应该看起来不像“2”的混淆,依此类推。

这并不意味着任何方式都是安全的,所以这不是一个大问题。另外,我将要混淆的整数并不大 - 介于1到10,000之间 - 但我也不希望发生任何碰撞。

是否有人对符合此标准的内容有任何想法?

10 个答案:

答案 0 :(得分:11)

如果你只有大约10,000个整数,那么最简单和最可靠的方法可能是整数和随机生成的字符串之间的映射表。要么预先生成一堆对应于每个整数的随机标识符,要么根据需要填充它们。

通过这种方式,您可以保证不会发生冲突,并且不必担心加密,因为没有任何内容可以解密,因为字符串不是从整数本身派生的。

您可以根据需要在数据库表或内存(例如双向字典)中实现它。

答案 1 :(得分:6)

我意识到这是在7个月前被问到所以你现在已经找到了解决方案,但我遇到的解决方案是Skip32 / Skipjack密码+ base32编码的组合。 perl示例(因为我知道的那个)显示:

use Crypt::Skip32::Base32Crockford;
my $key    = pack( 'H20', "112233445566778899AA" ); # Always 10 bytes!
my $cipher = Crypt::Skip32::Base32Crockford->new($key);
my $b32    = $cipher->encrypt_number_b32_crockford(3493209676); # 1PT4W80
my $number = $cipher->decrypt_number_b32_crockford('1PT4W80'); # 3493209676

我不知道c#实现,但perl是http://search.cpan.org/perldoc?Crypt::Skip32::Base32Crockford,而ruby的两个组成部分是https://github.com/levinalex/base32https://github.com/patdeegan/integer-obfuscator。在他们两个之间,你应该能够将它移植到你需要的任何语言。

答案 2 :(得分:5)

我从Pearson散列中得出了一个想法,它也适用于任意输入,而不仅仅是32位整数。我不知道这是否与Greg的答案完全相同,但我无法理解他的意思。但我所知道的是内存需求在这里是不变的。无论输入多大,这仍然是一个可靠的混淆/加密技巧。

对于记录,此方法不是散列,并且没有冲突。这是混淆字节字符串的完美声音方法。

您需要使用的是密钥_encryptionTable,它是包含范围0..255的随机排列。你用它来改变字节周围的字节。为了使它很难反转它使用XOR来混合字节串。

public byte[] Encrypt(byte[] plaintext)
{
    if (plaintext == null)
    {
        throw new ArgumentNullException("plaintext");
    }
    byte[] ciphertext = new byte[plaintext.Length];
    int c = 0;
    for (int i = 0; i < plaintext.Length; i++)
    {
        c = _encryptionTable[plaintext[i] ^ c];
        ciphertext[i] = (byte)c;
    }
    return ciphertext;
}

然后,您可以使用BitConverter在值和字节数组之间进行转换,或者转换为基数64或32以获得文本表示。如果这很重要,Base 32编码可以是URL友好的。解密就像通过计算_encryptionTable的倒数来反转操作一样简单。

    public byte[] Decrypt(byte[] ciphertext)
    {
        if (ciphertext == null)
        {
            throw new ArgumentNullException("ciphertext");
        }
        byte[] plaintext = new byte[ciphertext.Length];
        int c = 0;
        for (int i = 0; i < ciphertext.Length; i++)
        {
            plaintext[i] = (byte)(_decryptionTable[ciphertext[i]] ^ c);
            c = ciphertext[i];
        }
        return plaintext;
    }

如果您正在处理32位整数并且只关心大于或等于0的数字,那么您也可以做其他有趣的事情,这使得更难猜测混淆的数字。

我还使用一个秘密字来为伪数字生成器播种,并使用它来设置初始排列。这就是为什么我可以通过知道我用来创造每件事的秘密词来简单地获得价值。

var mt = new MersenneTwister(secretKey.ToUpperInvariant());
var mr = new byte[256];
for (int i = 0; i < 256; i++)
{
    mr[i] = (byte)i;
}
var encryptionTable = mt.NextPermutation(mr);
var decryptionTable = new byte[256];
for (int i = 0; i < 256; i++)
{
    decryptionTable[encryptionTable[i]] = (byte)i;
}
this._encryptionTable = encryptionTable;
this._decryptionTable = decryptionTable;

这有些安全,这里最大的缺陷是加密,XOR为0,恰好是XOR的标识,并没有改变值(a ^ 0 == a)。因此,第一个加密字节表示该字节的随机位置。要解决这个问题,您可以选择c的初始值,这不是常量,基于密钥,只需要询问PRNG(在init之后使用种子)一个随机字节。这样,只要您无法观察输入和输出,即使使用大量样本来破解加密也会非常困难。

答案 3 :(得分:4)

XOR是一种很好的快速混淆整数的方法:

1 xor 1234 = 1235
2 xor 1234 = 1232
3 xor 1234 = 1233
100 xor 1234 = 1206
120 xor 1234 = 1194

速度很快,再次使用相同的数字再次回到原来的状态!唯一的麻烦是,如果一个“攻击者”知道任何一个数字,他们可以通过用已知的原始结果xor-ing来找出xor掩码......

例如我(“攻击者”)现在该列表中的第4个数字是混淆的“100”。所以我会这样做:

100 xor 1206 = 1234

...现在我已经有了XOR模板,我可以对任何数字进行模糊处理。令人高兴的是,这个问题有一个微不足道的解决方案。算法改变XOR掩模。例如,如果需要在数组中混淆1000个整数,请从XOR掩码“1234”开始,并为arrray中的每个数字增加MASK 4。

答案 4 :(得分:2)

如果其他人感兴趣,有人会在几年后调整32位分组密码,这对于此任务特别有用。

上面还有Perl和Ruby端口:

如果您需要8个字符或更少的结果,您可以使用十六进制或base64表示。

答案 5 :(得分:1)

2017年5月更新

随意使用(或修改)我开发的库,可以通过Nuget安装:

  

Install-Package Kent.Cryptography.Obfuscation

这会将非负的ID(例如127)转换为 8个字符的字符串,例如 xVrAndNb ,然后返回(有一些可用的选项可以在每次生成序列时随机化序列。)

使用示例

var obfuscator = new Obfuscator();
string maskedID = obfuscator.Obfuscate(15);

完整文档位于:Github


旧答案

只是为旧答案添加多样性。也许有人需要它。这是我在某个时候做过的混淆课。

Obfuscation.cs - Github

您可以通过以下方式使用它:

Obfuscation obfuscation = new Obfuscation();
string maskedValue = obfuscation.Obfuscate(5);
int? value = obfuscation.DeObfuscate(maskedValue);

干杯,希望它可以使用。

答案 6 :(得分:1)

使用大多数语言的库处理这个问题的好项目:http://hashids.org/

答案 7 :(得分:0)

您可以使用数字的位模式 - 例如旋转和交换位。这将为您提供一种在多个26位和另一个26位之间移动的方法,这对于人类观察者来说不会立即显而易见。虽然它绝不是“安全”。

答案 8 :(得分:-1)

我意识到这是一个老帖子,但我认为发布我的技术来混淆整数id可能会有所帮助

缺点:确实使用超过8个字符,仅适用于3300万以下的id值

优点:不需要密钥去混淆,URL / cookie友好,每次生成不同的值,这使得它更难破坏,没有冲突,包括校验和功能,以消除随机/强力企图破坏(上述帖子没有解决的一个问题是,人们试图&#34;刮擦你的网站。如果我看到一个以id = 123结尾的网址,我知道我可以尝试id = 124等...来获得更多数据,这就是为什么一些XOR示例可能不是一个好主意的原因)

我建议稍微调整一下(我已经为我做过),因为我认为你不应该使用公开发布的混淆技术,但这是一个很好的起点。

快乐的编码!

    public static string ObfuscateId(int id)
    {
        try
        {
            string rtn;
            int sid = id + 279;
            int xm = sid * 3;
            int xl = xm.ToString().Length + 10;
            string sc = xl.ToString().Substring(1, 1);
            string fc = xl.ToString().Substring(0, 1);
            string csum = sid.ToString().Substring(sid.ToString().Length - 3);
            rtn = Guid.NewGuid().ToString().Replace("-", "").ToLower();
            rtn = sc + rtn.Substring(2, 26) + fc;
            rtn = rtn.Remove(4, 3).Insert(4, csum);
            rtn = rtn.Remove(xl, (xl - 10)).Insert(xl, xm.ToString());
            rtn = rtn.Replace('1', 'g');
            rtn = rtn.Replace('2', 'h');
            rtn = rtn.Replace('3', 'i');
            rtn = rtn.Replace('4', 'w');
            rtn = rtn.Replace('5', 'y');
            rtn = rtn.Replace('6', 'u');
            rtn = rtn.Replace('7', 'z');
            rtn = rtn.Replace('8', 'l');
            rtn = rtn.Replace('9', 'v');
            rtn = rtn.Replace('0', 'n');
            rtn = rtn.Replace('c', 'j');
            rtn = rtn.Replace('d', 'p');
            rtn = rtn.Replace('f', 'q');

            return rtn.ToUpper();
        }
        catch
        {
            return "ERROR BAD ID";
        }
    }

    public static int DeObfuscateId(string obtxt)
    {
        try
        {
            string rtn;
            int id;

            rtn = obtxt.ToLower();
            rtn = rtn.Replace('g', '1');
            rtn = rtn.Replace('h', '2');
            rtn = rtn.Replace('i', '3');
            rtn = rtn.Replace('w', '4');
            rtn = rtn.Replace('y', '5');
            rtn = rtn.Replace('u', '6');
            rtn = rtn.Replace('z', '7');
            rtn = rtn.Replace('l', '8');
            rtn = rtn.Replace('v', '9');
            rtn = rtn.Replace('n', '0');
            rtn = rtn.Replace('j', 'c');
            rtn = rtn.Replace('p', 'd');
            rtn = rtn.Replace('q', 'f');

            string sc = rtn.Substring(0, 1);
            string fc = rtn.Substring(rtn.Length - 1);
            int xl = int.Parse(fc + sc);
            int mv = int.Parse(rtn.Substring(xl, (xl - 10)));
            int sid = mv / 3;
            id = sid - 279;
            string csum = sid.ToString().Substring(sid.ToString().Length - 3);
            string xsum = rtn.Substring(4, 3);

            if (csum!=xsum)
            {
                return -99999;
            }

            return id;
        }
        catch
        {
            return -99999;
        }
    }

}

答案 9 :(得分:-2)

只需获取整数字节表示的MD5 / SHA1哈希值。保证不会发生碰撞。