4

I need to create cryptographically secure pseudorandomness in JavaScript. However, when I googled for PRGs, all I found was very sketchy.

My idea is as follows (in pseudocode):

seed = "0x1a29fd..." // long number I always get passed (impossible to guess but used in a different context as well)
hashedAndSaltedSeed = sha256sum("seed: " + seed)
purpose = "..." // my current function's name (no spaces)
usageIndex = 1; // will increment this each time

randomness = myPrg(hashedAndSaltedSeed, purpose, usageIndex)

function myPrg(hashedAndSaltedSeed, purpose, usageIndex, numberOfBytes) {
    if(numberOfBytes > 32) {
        fail()
    }

    input = purpose + " " + usageIndex + " " + hashedAndSaltedSeed
    return sha256sum(input).binary2hex().slice(0, 2*numberOfBytes).hex2binary()
}

I only need a small amount of randomness (at most 32 Byte at a time, very few times), so the speed difference won't matter. But is there anything else wrong with this approach?

The randomness I need doesn't need to be distributed perfectly randomly but it needs to be infeasible to guess the resulting randomness when only given purpose and usageIndex but not seed nor hashedAndSaltedSeed.

Edit: I'm sorry that I forgot to mention an important requirement. I'm sure it was in my question at some point as I wrote it but I seem to have deleted that part accidentally. I need to be able to reproduce the same randomness when given the same seed. That's why I can't just use something that gives me randomness but doesn't let me control the seed.

UTF-8
  • 274
  • 1
  • 11

3 Answers3

6

This is fine, although you should avoid these conversions to and from hexadecimal, that are no needed and may introduce side channels.

Now, since you are using JavaScript, you can simply use the WebCrypto API. Specifically crypto.GetRandomValues, which can fill an array up to 65536 bytes.

Frank Denis
  • 3,073
  • 19
  • 19
3

In practice it is probably fine.

In theory - for anyone looking for the theoretical answer - hash functions only guarantee that collisions are infeasible to find by a PPT attacker while a PRG guarantees the output is indistinguishable from uniform randomness to a PPT attacker. The two are very different. Notably, a hash function can always output $0$ for the first $n/2$ bits and still be collision-resistant but if used for a PRG it would be trivially distinguishable in $O(n)$ time. A PRG is also supposed to be length-expanding whereas hash functions are often length compressing.

One-Way-Functions (OWFs), PRGs, and hash functions are all related. OWFs imply PRGs and vis-versa. A good practical hash function will probably be a PRG, as @fgrieu mentions in comments below.

qz-
  • 131
  • 3
1

If instead of using a hash function, you used a block cipher, this would be precisely using CTR mode as a PRNG. This can definitely work, but I'd recommend you read this post to see some implementation details you'd want to be careful about (for the case of using a block cipher/AES).

Mark Schultz-Wu
  • 15,089
  • 1
  • 22
  • 53