112

Is SecureRandom thread safe? That is, after initializing it, can access to the next random number be relied on to be thread safe? Examining the source code seems to show that it is, and this bug report seems to indicate that its lack of documentation as thread safe is a javadoc issue. Has anyone confirmed that it is in fact thread safe?

Yishai
  • 90,445
  • 31
  • 189
  • 263

3 Answers3

118

Yes, it is. It extends Random, which always had a de facto threadsafe implementation, and, from Java 7, explicitly guarantees threadsafety.

If many threads are using a single SecureRandom, there might be contention that hurts performance. On the other hand, initializing a SecureRandom instance can be relatively slow. Whether it is best to share a global RNG, or to create a new one for each thread will depend on your application. The ThreadLocalRandom class could be used as a pattern to provide a solution that supports SecureRandom.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 3
    Thanks for the update. Oddly, the bug is marked closed as "will not fix." But they fixed it anyway. Oh well, I don't envy them the size of their bug database. – Yishai Sep 14 '11 at 19:30
  • 4
    initializing a `SecureRandom` can not only be slow, but can potentially hang because of missing entropy – Walter Tross Jul 25 '14 at 09:37
  • 1
    @WalterTross Hang? I have seen systems take 10 or 15 minutes, but I've never seen one hang. An implementation that isn't guaranteed to continue feeding its entropy pool, albeit slowly, seems like a bug in the OS. – erickson Jul 25 '14 at 14:05
  • 1
    Correct. Let's say "almost hang"... ;-) – Walter Tross Jul 25 '14 at 17:52
  • 10
    Please keep in mind that ThreadLocalRandom is very easy to crack, so if you plan to expose generated value to the world, use SecureRandom instead http://jazzy.id.au/default/2010/09/20/cracking_random_number_generators_part_1.html – walv Aug 04 '14 at 09:19
  • @erickson - I used to have a diskless workstation running a fairly old version of Linux (probably 2.0.something) where disk interrupt times were basically the only large scale source of entropy. If you tried to grab too much random data during startup it would hang until somebody typed on the keyboard. The default script to set up the X11 "magic cookie" would take too much, and had to be rewritten to use `/dev/urandom` rather than `/dev/random`. I imagine things are a little better these days, but I would definitely not rely on being able to acquire random bits in any particular timeframe. – Jules Sep 04 '17 at 21:45
  • @Jules If seeding a `SecureRandom` blocks for a perceptible duration, your system is misconfigured. You should definitely not stop using `SecureRandom` out of some fear that it will block indefinitely. – erickson Sep 04 '17 at 22:52
  • 4
    I'm going to go out on a limb here and say this answer is incorrect. The contract for Random, which guarantees thread safety, is not binding on subclasses. Certainly all the other properties of Random documented are not binding on subclasses, so I don't see why thread-safety should be assumed. – President James K. Polk Dec 06 '17 at 18:16
  • 2
    @JamesKPolk Failure to preserve a property of the supertype would violate the substitutability principle. – erickson Jan 31 '18 at 07:14
  • This answer is incorrrect. Thread safety is not garantee if a sub-class override the method. The oviridden method must respect the same thread safety contract as the parent (otherwise it's a mess) but there is no garantee. See https://stackoverflow.com/questions/50545604/how-to-ensure-thread-safety-of-subclass-methods-from-a-superclass and https://wiki.sei.cmu.edu/confluence/display/java/TSM00-J.+Do+not+override+thread-safe+methods+with+methods+that+are+not+thread-safe. – Algiz Jan 28 '19 at 14:15
  • 2
    @Algiz That’s true, any code could have a bug that makes it malfunction. But, “no class is thread-safe, because you can’t guarantee there are no bugs” isn’t a useful answer. Until I find a widely-used `SecureRandom` implementation that’s not thread-safe, I believe this answer is correct for any practical situation. – erickson Jan 28 '19 at 14:29
  • @erickson I believe SecureRandom is thread safe but it is not due to what you explain. The answer from Matt Quail give a more strong background. – Algiz Jan 28 '19 at 14:39
  • 2
    At least in JDK 10, SecureRandom is based on a provider and checks if the provider is thread safe, synchronizing if it's not, in nextBytes. So while it's possible for a subclass to override that behavior, it would be foolish, and alternative algorithms should be providers not subclasses anyway. – nafg Feb 06 '19 at 18:09
  • It's interesting that over time the SecureRandom implementation has more carefully taken care to be threadsafe. In Java 7 the appropriate methods are `synchronized`. In Java 8 they are not. By Java 10 they are thread-safe again and the javadocs explicitly describe how they achieve this and what service providers need to do to announce their thread safety. – President James K. Polk Aug 05 '21 at 17:33
13

The current implementation of SecureRandom is thread safe, specifically the two mutating methods nextBytes(bytes[]) and setSeed(byte[]) are synchronized.

Well, as far as I've been able to tell, all mutating methods are eventually routed through those two methods, and SecureRandom overrides a few methods in Random to ensure that. Which works but could be brittle if the implementation is changed in the future.

The best solution is to manually synchronize on the SecureRandom instance first. This means each call stack will acquire two locks on the same object, but that is usually very cheap on modern JVMs. That is, there is not much harm in explicitly synchronizing yourself. For example:

    SecureRandom rnd = ...;

    byte[] b = new byte[NRANDOM_BYTES];
    synchronized (rnd) {
        rnd.nextBytes(b);
    }
Matt Quail
  • 6,189
  • 2
  • 23
  • 20
  • 3
    At least in JDK 10, SecureRandom is based on a provider and checks if the provider is thread safe, only synchronizing if it's not, in nextBytes. – nafg Feb 06 '19 at 18:10
  • 1
    `java.security.SecureRandom#nextBytes` in Java 8 is not synchronized. Could you please specify in what Java version did you find a synchronized `#nextBytes`?. – Jaime Hablutzel Mar 13 '19 at 01:54
2

Please see https://bugs.openjdk.java.net/browse/JDK-8165115 which was fixed in Java 9.

It says:

SecureRandom objects are safe for use by multiple concurrent threads. A SecureRandom service provider can advertise that it is thread-safe by setting the service provider attribute "ThreadSafe" to "true" when registering the provider. Otherwise, the SecureRandom class will synchronize access to the following SecureRandomSpi methods: SecureRandomSpi.engineSetSeed(byte[]), SecureRandomSpi.engineNextBytes(byte[]), SecureRandomSpi.engineNextBytes(byte[], SecureRandomParameters), SecureRandomSpi.engineGenerateSeed(int), and SecureRandomSpi.engineReseed(SecureRandomParameters).

Yoseph
  • 730
  • 1
  • 7
  • 8