有没有办法使用 [u8; 64]阵列?

Is there a way to seed a cryptographically secure RNG engine in rust using a [u8; 64] array?

原始问题:

我目前正在尝试用 Rust 编写一个库 - 将被编译为 WASM - 用于将 bip39 助记密码短语转换为 Arweave JWK。我目前正在使用 tiny-bip39 and RSA.

根据 RSA I want to seed the rng based on the mnemonic passphrase I have passed into the function. I tried achieving this by simply getting the seed from the mnemonic object generated by tiny-bip39 中给出的示例使用 RSA 生成私钥时,这似乎生成了长度为 64&[u8]。但是,Seed 被定义为 [u8; 32],而不必编写自己的 rng,我无法弄清楚如何使用 len 64 种子。

#[wasm_bindgen]
pub fn get_key_from_mnemonic(phrase: &str) {
    let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();

    assert_eq!(phrase, mnemonic.phrase());

    let seed = Seed::new(&mnemonic, "");
    let seed_bytes = seed.as_bytes();

    let mut rng = ChaCha12Rng::from_seed(seed_bytes);

    [...]
}

是否有允许 len 64 种子的加密安全 rng?

我试过简单地尝试一下,但这似乎没有用,这是有道理的。

let seed_bytes: <ChaCha12Rng as SeedableRng>::Seed = seed.as_bytes().try_into().unwrap();

编辑:

我想出了一个似乎在所有方面都有效的解决方案,但随机数生成除外。

    let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();

    assert_eq!(phrase, mnemonic.phrase());

    let seed = Seed::new(&mnemonic, "");
    let seed_bytes = seed.as_bytes();
    let mut seed_buf: [u8; 32] = Default::default();

    let mut hmac_drgb = HmacDRBG::<Sha256>::new(&seed_bytes, &[], &[]);
    hmac_drgb.generate_to_slice(&mut seed_buf, None);

    let mut chacha = ChaCha20Rng::from_seed(seed_buf);

    let modulus_length = 4098;
    let rsa_private_key = RsaPrivateKey::new(&mut chacha, modulus_length).unwrap();

    let der = rsa_private_key.to_pkcs1_der().unwrap();

    let jwk = JWK {
        modulus: der.private_key().modulus.as_bytes().to_vec(),
        public_exponent: der.private_key().public_exponent.as_bytes().to_vec(),
        private_exponent: der.private_key().private_exponent.as_bytes().to_vec(),
        prime1: der.private_key().prime1.as_bytes().to_vec(),
        prime2: der.private_key().prime2.as_bytes().to_vec(),
        exponent1: der.private_key().exponent1.as_bytes().to_vec(),
        exponent2: der.private_key().exponent2.as_bytes().to_vec(),
        coefficient: der.private_key().coefficient.as_bytes().to_vec(),
    };

当我试图重写 arweave-mnemonic-keys 提供的一些功能时,我试图遍历所有依赖项,弄清楚我需要哪些 rust 模块,并认为我已经设法弄清楚了一切,除了如何为 RSA 算法生成随机数。

我尝试查看 node-forge/lib/rsa.js 文件,发现了这个片段:

function generateRandom(bits, rng) {
      var num = new BigInteger(bits, rng);
      // force MSB set
      var bits1 = bits - 1;
      if(!num.testBit(bits1)) {
        num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num);
      }
      // align number on 30k+1 boundary
      num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0);
      return num;
}

但是,我不确定如何在 Rust 中重现它。到目前为止,我已经尝试使用 ChaCha8RngChaCha12RngChaCha20RngPcg64、none,它们产生了想要的结果。

这取决于 CSPRNG。如果您使用 HMAC-SHA-512 为 HMAC DRBG 播种,那么这将是一个完全正常的输入量。但是,在您的情况下,CSPRNG 是 ChaCha,它被配置为具有 256 位密钥。

如果这个助记词是由CSPRNG生成的,并且有足够的熵,那么你只需要一个像HKDF这样简单明了的密钥推导函数。您可以将 HKDF 与 SHA-256 或 SHA-512 一起使用,种子作为输入键控 material,无盐,输出键控 material 大小为 32 字节。然后,您可以使用它来播种您的 CSPRNG。

您还需要一个信息字符串,通常是一些文本字符串。我喜欢使用版本号来证明未来,因此您可以使用“v1 PRNG seed”之类的东西。

我的建议是,由于您有一个 64 字节的输入种子,因此使用 SHA-512 的 HKDF 是最好的,因为它可以避免在您最终需要为其他数据播种时丢失熵。此外,虽然 ChaCha12Rng 是默认值,但 ChaCha20Rng 更为保守,可能适合生成长期密钥。