2

I am using Java 1.7 and as the code below demonstrates (compiled with Oracle's Java 7 compiler in Ubuntu) seeding java.security.SecureRandom appears to be unneccessary as the code produces two different BigIntegers for the starting value of the two pseudo-random sequences:

import java.security.SecureRandom;
import java.math.BigInteger;

public class SessionIdTest {

    public static void main (String args[]) {
    long seed = System.currentTimeMillis();
        {
            SecureRandom random = new SecureRandom();
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
        {
            SecureRandom random = new SecureRandom();
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
    }
}

What's the purpose of setSeed then? Or is SecureRandom also using, in addition to the seed, some other source of randomness?

Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331

3 Answers3

2

The javadoc says:

Many SecureRandom implementations are in the form of a pseudo-random number generator (PRNG), which means they use a deterministic algorithm to produce a pseudo-random sequence from a true random seed. Other implementations may produce true random numbers, and yet others may use a combination of both techniques.

So, counting on a secure random to generate a deterministic sequence of values by seeding it won't necessarily work, as documented.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
2

JavaDoc says:

Reseeds this random object, using the eight bytes contained in the given long seed. The given seed supplements, rather than replaces, the existing seed. Thus, repeated calls are guaranteed never to reduce randomness.

hoaz
  • 9,883
  • 4
  • 42
  • 53
  • 2
    OP is seeding a new SecureRandom instance each time. So the seed doesn't have any previous seed to supplement. – JB Nizet Dec 24 '12 at 10:40
  • hm, you are right, also it seems like SecureRandom ignores 0 as a seed (based on Oracle JDK 7 sources), so `setSeed(0L)` call does not make sense at all – hoaz Dec 24 '12 at 10:45
  • @hoaz I updated my code to use System.currentTimeMillis as seed, same results. Seeding both SecureRandoms with the same seed generates different sequences. – Marcus Junius Brutus Dec 24 '12 at 11:11
  • @MarcusJuniusBrutus it will depend on the default `SecureRandom` implementation on your system. Check it with something like `random.getAlgorithm()`. For example, for `SHA1PRNG` both results would be the same. – Jaime Hablutzel Mar 12 '19 at 22:59
1

Seeding a SecureRandom by calling java.security.SecureRandom#setSeed is not necessary, and actually, shouldn't be done unless you have a really good source of entropy and java.lang.System#currentTimeMillis definitely is not one.

Now, from your example where it was producing two different outputs even when the seed was the same. It is a behaviour that I observed in the DRBG SecureRandom implementation in Java 10, where both random numbers produced will differ during one execution but will remain constant if the program restarts:

public class SessionIdTest {

    public static void main (String args[]) throws NoSuchAlgorithmException {
        // Hardcoded seed to evidence the deterministic behavior when the program restarts.
        long seed = 1000;
        {
            SecureRandom random = SecureRandom.getInstance("DRBG");
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
        {
            SecureRandom random = SecureRandom.getInstance("DRBG");
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
    }
}

So the previous will always generate something like this:

724996208419722369188940556616693042555
796664555436785984208644362540465534270

And the differing values in one execution have its cause in a global state being updated every time a DRBG implementation is created.

Now, if you try the SHA1PRNG implementation, both random numbers will be the same and they will remain constant through program restarts:

public class SessionIdTest {

    public static void main (String args[]) throws NoSuchAlgorithmException {
        // Hardcoded seed to evidence the deterministic behavior when the program restarts.
        long seed = 1000;
        {
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
        {
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(seed);
            BigInteger a = new BigInteger(130, random);
            System.out.println(a);
        }
    }
}

So the previous will always generate something like this:

251586625089438840547467272692377284989
251586625089438840547467272692377284989

Finally, in both cases you can confirm that there is a deterministic behavior based on the provided seed, so, do not seed these SecureRandoms manually unless you have a very good source of entropy and again, the current time is not one!. Just let them seed themselves which is safer.

Jaime Hablutzel
  • 6,117
  • 5
  • 40
  • 57