【问题标题】:Encrypting and Decrypting a 19-digits long BigInteger加密和解密 19 位长的 BigInteger
【发布时间】:2013-03-21 22:46:35
【问题描述】:

我怎样才能使用最多 19 位长的 BigInteger 并使用以下规则对其进行加密:

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

我尝试过的事情

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

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

【问题讨论】:

  • 这看起来很像家庭作业。是吗?
  • 家庭作业怎么样?这个问题的复杂性比大多数家庭作业要困难得多。
  • 我说它看起来像家庭作业,主要是针对有限任务的详细说明。
  • 我建议将其发布到 crypto.stackexchange.com 而不是 SO。
  • @Guffa 如果这不是家庭作业,我不寒而栗想想它的用途。

标签: c# encryption cryptography biginteger


【解决方案1】:

19 位略小于 64 位,因此您可以简单地在 ECB 模式下使用 TDEA 之类的 8 字节分组密码来加密 BigInteger 值。首先检索 BigInteger 的默认 64 位编码,然后使用密钥加密,最后进行 base 36 编码。结果将是少于 16 个字符的几个字符,但您始终可以使用任何值填充。

请注意,如果您将相同的值加密两次,您将得到相同的结果,因此在这方面密文确实会泄露一些关于纯文本的信息。

【讨论】:

  • 我使用 C# 中的 BigInteger 和 TripleDES 类实现了这一点。我遇到的问题是接近 9999999999999999999 的数字对于一个块来说太大了。此外,大多数数字的长度在 12-13 位之间,我需要它们都具有固定长度。在这里填充 0 不是一个选项,因为大多数结果都以 0 开头。
  • @Alon: 9999999999999999999 应该适合一个无符号的 64 位变量。不过,它不适合已签名的。
  • @IlmariKaronen 是的,似乎我注意了,19 个零和一个之前的 1 应该适合。当 Alon 说它不合身时,我只是站错了脚。
  • Alon,加密前后填充都很好。只要该值保持唯一(并且它会),那么您可以简单地用前导零字节填充。如果您在加密后填充,那么您当然会看到具有特殊值的字节,但这不会说明纯文本。
  • @imichaelmiers:要求是保留最初只是数字的输入的长度。这提供了更多的空间 - 二进制输出可以是二进制输入大小的两倍,并且我们仍然可以保留原始 text 长度。
【解决方案2】:

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

不幸的是,这种技术的高效版本实施起来有些困难,事实上,如果您选择错误的参数,实施起来会非常不安全。有它的图书馆。 This one 是开源的。不幸的是,它在 C++ 中,不清楚它是否在 Windows 上运行。 Voltage 也有一个图书馆,不过大概要花钱,而且我不确定他们支持什么语言。

【讨论】:

    【解决方案3】:

    这是一段似乎可以做到这一点的代码,前提是您可以将BigInteger 转换为ulong(99999999999999999999 实际上是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);
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-11
      • 1970-01-01
      • 1970-01-01
      • 2012-10-03
      • 1970-01-01
      相关资源
      最近更新 更多