【问题标题】:How do I use boost::random_device to generate a cryptographically secure 64 bit integer?如何使用 boost::random_device 生成加密安全的 64 位整数?
【发布时间】:2014-06-15 20:07:37
【问题描述】:

我想做这样的事情:

boost::random_device rd;
boost::random::mt19937_64 gen(rd());
boost::random::uniform_int_distribution<unsigned long long> dis;
uint64_t value = dis(gen);

但我听说梅森捻线机在密码学上并不安全。但是,我还读到 random_device 可能是,如果它从 /dev/urandom 中提取数据,这可能在 linux 平台(我的主要平台)上。因此,如果 random_device 是非确定性随机的,并且它用于播种 mersenne twister(如上所示),那是否也使 mersenne twister 在密码学上安全(即使它本身不是)?

我在这个领域有点新手,所以任何建议都值得赞赏。

那么,如何生成可以存储在 uint64_t 中的加密安全 64 位数字?

谢谢,

本。

【问题讨论】:

  • 免责声明 - 不是专家。 Mersenne twister 永远不可能是加密安全的,无论你如何播种它,因为攻击者一旦了解了它的内部状态,就可以很容易地确定下一个结果。要生成 64 位数字,您可以调用 random_device 两次(假设是 32 位 int),然后附加结果。此外,您可能不想使用默认的/dev/urandom 源,而是将参数"/dev/random" 传递给random_device 构造函数。与前者不同,后者将在熵池中没有更多可用的随机位时阻塞。
  • 感谢您对 Paetorian 的评论——似乎与 gha.st 的回答相似!干杯。
  • @Praetorian 我推荐/dev/urandom 而不是/dev/random。一旦充分播种(例如 200 位熵),无论您阅读多少,PRNG 都不会耗尽熵。所以/dev/random 做了很多不必要的阻塞。 /dev/urandom 的唯一问题是它可能还没有充分播种,这主要与嵌入式设备启动过程的早期有关。

标签: c++ boost random cryptography mersenne-twister


【解决方案1】:

分析您的问题比看起来更难:

您使用rd() 为mersenne twister 播种,它返回unsigned int,因此(在大多数平台上)最多包含32 个随机位。

从那时起,梅森捻线机所做的一切都是由这 32 位决定的。

这意味着value 只能采用 2**32 个不同的值,如果存在任何攻击向量,通过蛮力攻击你对这个数字所做的任何事情,这可能会成为问题。事实上,mersenne twister 的播种例程甚至可能会减少第一个结果的可能值的数量,因为它将 32 个随机位分布在其完整状态中(为确保不是这种情况,您必须分析播种例程提升使用)。

然而,在这种情况下,mersenne twister (its state can be derived after seeing 624 numbers) 的主要弱点甚至不感兴趣,因为您生成的序列非常短(1 个值)。

生成 64 个加密安全位

假设unsigned int在您的平台上等价于uint32_t,您可以使用boost::random_device轻松生成64个密码安全随机位:

boost::random_device rd;
std::uint64_t value = rd();
value = (value << 32) | rd();

这是相当安全的,因为 linux 和 windows use the operating system's own cryptographically secure randomness sources 的实现。

生成具有任意分布的加密安全值

虽然前面的方法足够好,但您可能希望有一个更灵活的解决方案。这很容易做到,因为您意识到您实际上也可以使用 random_device 提供的随机分布提升。一个简单的例子是像这样重写以前的解决方案:

boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
std::uint64_t value = dis(rd);

(虽然如果前一个实际上在 [0, 2**32 中不包含数字,这在理论上也可以提供更稳健的解决方案),但实际上这不是问题。)

绑定分发到生成器

为了提高可用性,您经常会发现使用boost::bind 将分发和生成器绑定在一起。由于boost::bind复制了它的参数,而boost::random_device的copy ctor被删除了,你需要使用一个小技巧:

boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
boost::function<std::uint64_t()> gen = boost::bind(dis, boost::ref(rd));
std::uint64_t value = gen();

【讨论】:

  • 我了解到 MSVC 的 std::random_device 实现使用了 PRNG (and this is allowed by the standard)。所以无论如何,坚持为random_device提升,我想。
  • @sehe:见this
  • @user3521733 谢谢。这只是在依赖它之前检查您的实现的原则点。
  • @sehe 你的评论确实让我去挖掘 MSDN,似乎 MSVC 实现 ignores the constructor argument。因此,即使您愿意,也无法更改熵源。
  • 感谢 gha.st。我会使用你的后一个例子:-)
【解决方案2】:

仅将随机设备用于播种并不是真正的加密安全。然后将问题简化为找出初始种子,这是一个大大简化的问题。而是直接使用随机设备。

val = dis(rd);

为了提高安全性,请使用/dev/random 而不是/dev/urandom 初始化随机设备。如果没有足够的“熵”,/dev/random 将阻塞,直到发生一些随机的事情。但是,它可能会慢得多。

顺便说一句,假设您有一个不会为 entropy 函数返回虚假值的高质量 C++11 实现,如果您尝试删除依赖项,则使用 C++11 可能是一个更好的主意。

编辑:显然有一些关于 /dev/random 是否比 /dev/urandom 更好的争论。我推荐你this

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-12-05
  • 2014-06-02
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
相关资源
最近更新 更多