加密和解密一个19位长的BigInteger

时间:2013-03-16 17:28:25

标签: c# encryption cryptography biginteger

如何获取最多19位长BigInteger并使用以下规则对其进行加密:

  • 结果必须仅基于数字和小写英文字母。
  • 所有输出必须与任何输入具有相同的长度。长度必须介于11到16个字符之间,具体取决于您的方法,但应与所有可能的输入保持一致
  • 没有简单的模式。例如,如果加密000 ... 1和000 ... 2,结果应该看起来完全不同。
  • 根本没有碰撞
  • 应该能够解密回原来的BigInteger。

我尝试过的事情

  • 取原始数字,用某个键对其进行异或,将其乘以一个因子并将其转换为基数为36的字符串。该因子的目的是扩大范围,因此不会有太多的填充。因子必须介于1到36^16/10^19之间。这种方法的问题在于:a)它不够“安全”,而b)关闭数字的结果非常相似。

  • This answer.但是,结果往往太短或太长,之前使用的因子方法在这里不起作用。

3 个答案:

答案 0 :(得分:3)

19位略小于64位,因此您只需在ECB模式下使用类似TDEA的8字节分组密码来加密BigInteger值。首先检索BigInteger的默认64位编码,然后用密钥加密,最后基数36对其进行编码。结果将是少于16个字符的几个字符,但您可以随时填充任何值。

请注意,如果您将相同的值加密两次,则会获得相同的结果,因此在这方面,密文会泄漏有关纯文本的一些信息。

答案 1 :(得分:0)

您想要的技术是format perserving encryption。这将允许您将19位数字加密为另一个19位数字。

不幸的是,这种技术的有效版本有点难以实现,事实上,如果选择错误的参数,可能会非常不安全。有图书馆。 This one是开源的。不幸的是它在C ++中,如果它在Windows上运行则不清楚。 Voltage也有一个图书馆,虽然它可能需要花钱,而且我不确定他们支持哪种语言。

答案 2 :(得分:0)

如果您可以将BigInteger转换为ulong(9999999999999999999实际上是ulong),则可以使用以下代码。结果始终是一个固定的16个字符的字符串(十六进制)。

    byte[] key = // put your 16-bytes private key here
    byte[] iv = Guid.NewGuid().ToByteArray(); // or anything that varies and you can carry

    string s = EncryptUInt64(ul, key, iv); // encode
    ulong dul = DecryptUInt64(s, key, iv).Value; // decode if possible


    public static string EncryptUInt64(ulong ul, byte[] key, byte[] iv)
    {
        using (MemoryStream output = new MemoryStream())
        using (var algo = TripleDES.Create())
        {
            algo.Padding = PaddingMode.None;
            using (CryptoStream stream = new CryptoStream(output, algo.CreateEncryptor(key, iv), CryptoStreamMode.Write))
            {
                byte[] ulb = BitConverter.GetBytes(ul);
                stream.Write(ulb, 0, ulb.Length);
            }
            return BitConverter.ToUInt64(output.ToArray(), 0).ToString("x16");
        }
    }

    public static ulong? DecryptUInt64(string text, byte[] key, byte[] iv)
    {
        if (text == null)
            return null;

        ulong ul;
        if (!ulong.TryParse(text, NumberStyles.HexNumber, null, out ul))
            return null;

        using (MemoryStream input = new MemoryStream(BitConverter.GetBytes(ul)))
        using (var algo = TripleDES.Create())
        {
            algo.Padding = PaddingMode.None;
            using (CryptoStream stream = new CryptoStream(input, algo.CreateDecryptor(key, iv), CryptoStreamMode.Read))
            {
                byte[] olb = new byte[8];
                try
                {
                    stream.Read(olb, 0, olb.Length);
                }
                catch
                {
                    return null;
                }
                return BitConverter.ToUInt64(olb, 0);
            }
        }
    }