【问题标题】:no cryptography random generator seed allowed in C#?C# 中不允许加密随机生成器种子?
【发布时间】:2013-12-01 22:30:19
【问题描述】:

似乎没有办法在 C# 中手动设置 RNGCryptoServiceProvider 的种子。我真的没有什么简单的方法可以在下面获取可重复的随机字节进行调试吗?

  RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
  byte[] randomBytes = new byte[20];
  rngCsp.GetBytes(randomBytes);
  MessageBox.Show(Convert.ToBase64String(randomBytes));

我知道我可以手动输入 20 个字节,但这很痛苦,因为我真的需要超过 20 个字节。另外,我知道我可以使用非密码随机数生成器,但最后,我需要最好的随机生成。

顺便说一句,我猜有些 CPU 内置了真正的随机生成,但实际上无法进行播种,但我认为我的 CPU 不具备这种能力。我想知道是否有人确切知道我可以用我的 CPU 做什么来重置 RNGCryptoServiceProvider 环境并欺骗 RNGCryptoServiceProvider 使用先前的种子......我想我可以将时钟调回去并在某处重置一些“用户日志位”......我知道这不切实际,但想知道是否有人在这方面取得过成功(尽管微软的目标可能是防止这种情况发生)。

【问题讨论】:

  • 种子不可避免地会使其不安全。谷歌“.net mersenne twister”并获得第一击。
  • @HansPassant Mersenne Twister 在密码学上不安全。
  • @bobuhito 我无法想象你怎么能需要那种再现性——如果你每次都生成不同的密钥有什么问题你调试?你到底需要这些字节做什么?

标签: c# visual-studio random prng


【解决方案1】:

没有办法播种RNGCryptoServiceProvider。为调试生成确定性值的一种解决方案是派生您自己的类,该类从 System.Security.Cryptography.RandomNumberGeneratorRNGCryptoServiceProvider 的基类)实现:

class DeterministicRandomGenerator : System.Security.Cryptography.RandomNumberGenerator
{
    Random r = new Random(0);
    public override void GetBytes(byte[] data)
    {
        r.NextBytes(data);
    }
    public override void GetNonZeroBytes(byte[] data)
    {
        // simple implementation
        for (int i = 0; i < data.Length; i++)
            data[i] = (byte)r.Next(1, 256);
    }
}

请注意,该实现使用种子为 0 的标准 Random 实现,以确保确定性结果。现在您可以使用这个类代替RNGCryptoServiceProvider 进行调试:

    RandomNumberGenerator rngCsp = 
#if DEBUG
    new DeterministicRandomGenerator(); // get deterministic values if debugging
#else
    new RNGCryptoServiceProvider(); // otherwise, use CryptoRNG
#endif
    byte[] randomBytes = new byte[20];
    rngCsp.GetBytes(randomBytes);
    MessageBox.Show(Convert.ToBase64String(randomBytes));

编辑添加

我想知道是否有人确切知道我可以用我的 CPU 做什么来重置 RNGCryptoServiceProvider 环境并欺骗 RNGCryptoServiceProvider 使用先前的种子

在内部,RNGCryptoServiceProvider 调用 Win32 的 CryptGenRandom 函数以加密随机值 (Source and additional information) 填充缓冲区。它不是基于单个种子。 (尽管 Win32 API 允许调用者提供带有补充随机数据的种子,但 .NET API 不公开此功能。在此上下文中种子的目的是提供应用程序可以访问的额外熵,而不是强制一个确定性序列。)CryptGenRandom 文档指出:

为了形成随机数生成器的种子,调用应用程序提供它可能具有的位(例如,鼠标或键盘计时输入),然后将这些位与存储的种子以及各种系统数据和用户数据(例如进程 ID 和线程 ID、系统时钟、系统时间、系统计数器、内存状态、空闲磁盘集群、散列的用户环境块。该结果用于播种伪随机数生成器 (PRNG)。在带有 Service Pack 1 (SP1) 及更高版本的 Windows Vista 中,使用了 NIST 特别出版物 800-90 中指定的基于 AES 计数器模式的 PRNG 的实现。在 Windows Vista、Windows Storage Server 2003 和 Windows XP 中,使用联邦信息处理标准 (FIPS) 186-2 中指定的 PRNG。

结果是“重置”RNGCryptoServiceProvider 以强制它重复之前的序列,从设计上讲,这不是一种实用的方法。

【讨论】:

    【解决方案2】:

    另外,我知道我可以使用非密码随机数生成器,但最终我需要最好的随机数生成器。

    使用 Mersenne Twister 或类似的作为可播种 PRNG 用于测试目的 - 仅在需要可重复结果的那些测试中 - 以及 RCPCryptoServiceProvider 用于其他所有内容。

    另一种选择是预先生成一批randomBytes 数组并将它们保存到磁盘以供您在测试阶段使用。这具有在保持 RCP CSP 相同的随机分布和其他特性的同时为您提供可重复性的优势。此外,忘记删除临时代码比忘记不包含无关文件更容易。

    【讨论】:

    • Mersenne Twister 不具备加密质量。
    • @RBarryYoung 我并不是真的建议这样做,只是为了测试目的,这是一个合理的选择。它相当快速、易于实施并且在众多平台和环境中是对称的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2013-08-23
    • 1970-01-01
    相关资源
    最近更新 更多