【问题标题】:Deterministic pseudorandom bytes for crypto加密的确定性伪随机字节
【发布时间】:2021-01-01 20:22:44
【问题描述】:

有没有办法从高熵种子中确定性地为 Go 中的加密生成随机字节?

我找到了crypto/rand,这对于加密来说是安全的,但不是确定性的。

我找到了math/rand,可以用种子初始化,但对加密不安全。

我找到了x/crypto/chacha20,我想知道将XORKeyStreamsrc 值1s 一起使用是否安全。种子是密钥和随机数,可以使用 crypto/rand 生成。

编辑

作为我所追求的示例,cryptonite,它是主要的 Haskell 加密库,有一个函数 drgNewSeed,您可以使用它从种子生成随机生成器。

【问题讨论】:

  • 我之前的评论可能有误。这可能会有所帮助:crypto.stackexchange.com/questions/39186/…
  • “确定性”和“加密安全”不是矛盾的吗?如果您出于测试目的需要它,请使用接口并在测试中模拟它。
  • 许多加密 RBG 的输出只有在它们的内部状态保密时才能预测。流密码是真实的。这个问题没有任何矛盾或不合理的地方。
  • @Flimzy 这可能是特定领域的行话,但该短语被接受,并提高了文献搜索结果的准确性。例如,请参阅NIST's Recommendation for Random Number Generation Using Deterministic Random Bit Generators.
  • KDF 不必很慢。您正在考虑的类别是 PBKDF(基于密码的 KDF)。 HKDF(HMAC KDF)是一种快速KDF。但我同意 KDF 通常不是您想要的。您的问题准确地描述了一个 CSPRNG。我不知道为什么会有这么多反对意见。所有 PRNG(包括 CSPRNG)都是确定性的。这就是“P”的全部意义所在。生成随机但确定性的值流是一半加密系统的工作方式。 (其他生成随机但确定性的排列流。)

标签: go random cryptography


【解决方案1】:

是的,XORKeyStream 可以很好地解决这个问题,并且对于 CSPRNG 来说是一个很好的设计。流密码的全部意义在于它在给定种子(密钥和 IV)的情况下生成“有效随机”值的流。然后将这些流值与明文进行异或。在这种情况下,“有效随机”意味着没有“有效算法”(在多项式时间内运行的算法)可以将该序列与“真正随机”序列区分开来。这就是你想要的。

不过,没有必要加入 ChaCha20。您可以使用像 AES 这样的内置密码。任何分组密码都可以使用多种模式之一转换为流密码,例如 CTR、OFB 或 CFB。这些模式之间的差异对于这个问题并不重要。

// Defining some seed, split across a "key" and an "iv"
key, _ := hex.DecodeString("6368616e676520746869732070617373")
iv, _ := hex.DecodeString("0123456789abcdef0123456789abcdef")

// We can turn a block cipher into a stream cipher, and AES is handy
block, err := aes.NewCipher(key)

if err != nil {
    panic(err)
}

// Convert block cipher into a stream cipher using a streaming mode like CTR
// OFB or CFB would work, too
stream := cipher.NewCTR(block, iv)

for x := 0; x < 10; x++ {
        // Create a fixed value of the size you want
    value := []byte{0}
    
    // Transform it to a random value
    stream.XORKeyStream(value, value)

    fmt.Printf("%d\n", value)
}

Playground

您可以在此处使用其他几种方法。您可以使用像 SHA-256 这样的安全散列来散列一个计数器(选择一个随机的 128 位数字并不断增加它,对每个值进行散列)。或者你可以对之前的结果进行哈希处理(我听说过一些关于重复哈希是否可能影响哈希的安全性的争议。请参阅https://crypto.stackexchange.com/questions/19392/any-weakness-when-performing-sha-256-repeatedlyhttps://crypto.stackexchange.com/questions/15481/will-repeated-rounds-of-sha-512-provide-random-numbers/15488 了解更多信息。)

您也可以使用分组密码来做同样的事情,方法是对计数器或之前的输出进行加密。这与流密码模式所做的非常接近。您也可以手动完成。

如果您想深入研究,可以在 crypto.stackexchange.com 上搜索 "csprng stream cipher"。这是寻求加密建议的更好地方,但 IMO 这是一个特定于编程的问题,所以属于这里。

【讨论】:

    【解决方案2】:

    在随机数生成中,首先,从计算机的不可预测的元素收集有限的随机性。然后将这种物理随机性从可能的偏差(如散列)中清除,然后通过使用伪随机数生成器 (PRNG) 将生成的较小的真正随机性扩展到许多。

    PRNG 是确定性的,这意味着如果初始值(初始真正的随机性 - 种子)已知,那么其余的将是已知的。 永远保密

    我们并没有迷失,PRNG 的重要设计目标是输出不应该可以从任何其他输出中预测。这是一个强烈的要求,表明不可能仅通过查看输出来了解内部状态。

    Go 的 crypto/rand 使用底层系统功能来获取物理随机性。

    在 Linux 和 FreeBSD 上,Reader 使用 getrandom(2)(如果可用),否则使用 /dev/urandom。在 OpenBSD 上,Reader 使用 getentropy(2)。在其他类 Unix 系统上,Reader 从 /dev/urandom 读取。在 Windows 系统上,Reader 使用 CryptGenRandom API。在 Wasm 上,Reader 使用 Web Crypto API。

    然后可以使用可能的良好确定性 RBG,如 NIST 800-90 中定义的 Hash-DRGB、HMAC-DRGB 和 CTR-DRGB

    您可以使用x/crypto/chacha20 生成长确定性随机序列。 保持密钥和随机数固定和保密,您将获得确定性 DRGB。它非常快,而且可搜索。

    【讨论】:

      猜你喜欢
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-09
      • 1970-01-01
      相关资源
      最近更新 更多