1

As a beginner it seems that a scheme derived from a CSPRNG should be as secure as that CSPRNG. Is this a correct assumption? Are there restrictions or known special cases? A rough outline would be:

  1. Generate an IV using a non-deterministic CSPRNG.
  2. Use that IV to seed a deterministic CSPRNG.
  3. XOR each byte of input with a byte from the d-CSPRNG #2.
  4. Concatenate(IV, output of #3)
  5. Use key to seed a deterministic CSPRNG.
  6. XOR each byte of #4 with a byte from the d-CSPRNG #5

In pseudo-code:

# encrypt
iv = randomBytes(IV_SIZE)
c1 = xorUsingPRNG(plaintext, dCSPRNG(seed = iv))
iv_c1 = iv ++ c1
c2 = xorUsingPRNG(c1, dCSPRNG(seed = key))

# decrypt
iv_c1 = xorUsingPRNG(c2, dCSPRNG(seed = key))
iv = iv_c1[0:IV_SIZE]
c1 = iv_c1[IV_SIZE:]
plaintext = xorUSingPRNG(c1, dCSPRNG(seed = iv))

Both the Key and IV are of reasonable size (meaning they are significantly larger than just a few bits).

Are there any known attacks that would work on such a scheme - under assumption that the CSPRNG used is secure.

If the CSPRNG is secure and produces "random" numbers than the output of (any_data XOR random_numbers) should have the same properties in terms of randomness/distribution for as long as those two are independent.

If the CSPRNG is secure then even if one knows or choses the plaintext it shouldn't be feasible to reconstruct the seed used nor should it be possible to extract the keystream because of the randomization in #3.

Obviously the following doesn't work:

  1. Seed a d-CSPRNG with the key
  2. XOR input with output of d-CSPRNG

because this is trivially broken with known/chosen plaintext attacks.

mroman
  • 173
  • 5

1 Answers1

3

Your scheme can be easily rewritten to adhere to a more common scheme:

  1. generate a random data key (called "the IV" in your scheme)
  2. use the data key to encrypt a message giving the ciphertext (using a stream cipher)
  3. wrap (encrypt) the data key using a cipher parameterized with the master key and store it with the ciphertext.

And the additional step:

  1. encrypt the ciphertext using a cipher parameterized with the master key as well.

Other than #4 this is a very common construction and known to be secure - given that the parameters are indeed configured / generated correctly.

It is also easy to see that the pass with the master key over the ciphertext is spurious if the previous encryption with the data key is secure. That means that a whole pass of a cipher over the ciphertext is performed for no reason, presuming that the stream cipher using the data key is secure.


Relying on deterministic CSPRNG's is often very dangerous from an implementation perspective. CSPRNG's are generally designed to produce random data. They may automatically reseed at times and the implementation may change between versions. A very good example of this is SHA1PRNG used in Java, which is not well described and had all of the described issues (and more) on Android.

Besides that, CSPRNG's are often designed to be very sturdy - a good stream cipher will generally beat the heck out of a CSPRNG in practice when it comes to generating output. The fact that a stream cipher could be seen as a CSPRNG (with a predetermined seed size and without reseeding) doesn't change that.


Likewise XOR with a static key stream is not a brilliant wrapping mechanism. If any data is leaked the data key (your IV) may be at risk. Theoretically it may be perfectly secure given that the message is randomized, but I'd rather use a wrapping mechanism found in FIPS certified hardware (for instance).


Note that the scheme does not protect the integrity of the ciphertext (nor the wrapped key, but the integrity of the wrapped key can be determined by decrypting integrity protected ciphertext). Generally you should try and use authenticated modes of encryption.

Maarten Bodewes
  • 96,351
  • 14
  • 169
  • 323