Use non-cryptographic random number generation in Uuids.random()

Description

The UUIDs.random() method currently provides a shortcut for UUID.randomUUID() in both 3.x and 4.x. It turns out that internally randomUUID() relies on SecureRandom to generate a random number. In the context of Cassandra primary key generation it was likely not considered as a requirement but was just overlooked.

A quick JMH benchmark iterating over a 1000 calls to nextLong() for various *Random classes give the following results:

So in short, SecureRandom is at least 250x slower than the usual Java alternatives and generates some garbage for each generated random number whereas the alternatives don't.

To work around this problem, I see 3 options:
1. Replace the UUIDs.random() implementation with a custom, non-secure UUID generation one.
2. Do 1. and move the current implementation to a new UUIDs.secureRandom() method, if you feel that there could be some value in keeping a secure implementation.
3. Add a UUIDs.nonSecureRandom() with the custom implementation discussed in 1. as a safest way to add a workaround without introducing any potential (if any?) security regression.

Note that we don’t make any guarantee on the security aspect of UUIDs.random() in its Javadoc, making the fact that we actually use SecureRandom arguably an implementation detail.

Let me know what you think and I can submit a patch accordingly.

Environment

None

Pull Requests

None

relates to

Activity

Alex Dutra 
December 18, 2020 at 4:00 PM

I took a note to do a round of micro-benchmarks before 4.10 release, but I don't expect regressions.

Alex Dutra 
November 19, 2020 at 11:05 PM

I will propose a new implementation for Uuids.random() within this ticket, then I will open a different ticket + PR for improving Blockhound integration with the driver.

Alex Dutra 
September 9, 2020 at 2:08 PM

Tentatively scheduling for 4.10.

Alex Dutra 
September 9, 2020 at 2:07 PM

As a side note, we should also investigate the usage of ThreadLocalRandom as it seems it has better performance under contention.

Alex Dutra 
September 9, 2020 at 2:07 PM
(edited)

Another argument in favor of switching to non-cryptographic number generators was just brought to my attention: it turns out that SecureRandom needs to read from /dev/random and the like, and that is a blocking call. It’s noted in the class javadocs:

Note: Depending on the implementation, the generateSeed and nextBytes methods may block as entropy is being gathered, for example, if they need to read from /dev/random on various Unix-like operating systems.

Such a blocking call can be detected by tools like BlockHound, see this SO question for an example.

Some users already reported this problem using driver 4.x.

The typical stack trace is:

What is really concerning is that it comes from the client ID generation when composing the STARTUP message, so it’s not even something that was caused by user intervention. A workaround is to provide a pre-computed client ID when building the session.

Fixed

Details

Assignee

Reporter

Affects versions

Fix versions

Priority

Created September 17, 2019 at 8:27 PM
Updated December 18, 2020 at 4:00 PM
Resolved December 18, 2020 at 4:00 PM