How Good Is Java's Uuid.Randomuuid

Performance of Random UUID generation with Java 7 or Java 6

I tested it

    for (;;) {
long t0 = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
UUID.randomUUID();
}
System.out.println(System.currentTimeMillis() - t0);
}

on my PC it is ~1100 ms, which is pretty slow. UUID.randomUUID() uses SecureRandom internally, to make it faster we can use regular java.util.Random

    Random r = new Random();
for (;;) {
..
new UUID(r.nextLong(), r.nextLong());

it's ~80 ms

How big is the chance to get a Java UUID.randomUUID collision?

According to wikipedia, regarding the probability of duplicates in random UUIDs:

Only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%. Or, to put it another way, the probability of one duplicate would be about 50% if every person on earth owned 600 million UUIDs.

I guess the same reasoning applies to Java's implementation of UUID. So no, you should not worry about this.

Is UUID.randomUUID() suitable for use as a one-time password?

No. According to the UUID spec:

Do not assume that UUIDs are hard to guess; they should not be used as
security capabilities (identifiers whose mere possession grants
access), for example. A predictable random number source will exacerbate
the situation.

Also, UUIDs only have 16 possible characters (0 through F). You can generate a much more compact and explicitly secure random password using SecureRandom (thanks to @erickson).

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

public final class PasswordGenerator {
private SecureRandom random = new SecureRandom();

public String nextPassword() {
return new BigInteger(130, random).toString(32);
}
}

P.S.

I want to give a clear example of how using UUID as a security token may lead to issues:

In uuid-random we discovered an enormous speed-boost by internally re-using random bytes in a clever way, leading to predictable UUIDs. Though we did not release the change, the RFC allows it and such optimizations could sneak into your UUID library unnoticed.

Efficient method to generate UUID String in Java (UUID.randomUUID().toString() without the dashes)

Ended up writing something of my own based on UUID.java implementation. Note that I'm not generating a UUID, instead just a random 32 bytes hex string in the most efficient way I could think of.

Implementation

import java.security.SecureRandom;
import java.util.UUID;

public class RandomUtil {
// Maxim: Copied from UUID implementation :)
private static volatile SecureRandom numberGenerator = null;
private static final long MSB = 0x8000000000000000L;

public static String unique() {
SecureRandom ng = numberGenerator;
if (ng == null) {
numberGenerator = ng = new SecureRandom();
}

return Long.toHexString(MSB | ng.nextLong()) + Long.toHexString(MSB | ng.nextLong());
}
}

Usage

RandomUtil.unique()

Tests

Some of the inputs I've tested to make sure it's working:

public static void main(String[] args) {
System.out.println(UUID.randomUUID().toString());
System.out.println(RandomUtil.unique());

System.out.println();
System.out.println(Long.toHexString(0x8000000000000000L |21));
System.out.println(Long.toBinaryString(0x8000000000000000L |21));
System.out.println(Long.toHexString(Long.MAX_VALUE + 1));
}

java.util.UUID.randomUUID().toString() length

Does java.util.UUID.randomUUID().toString() length always equal to 36?

Yes!! it is.

A UUID actually a 128 bit value (2 long). To represent 128 bit into hex string there will be 128/4=32 char (each char is 4bit long). In string format it also contains 4 (-) that's why the length is 36.

example: 54947df8-0e9e-4471-a2f9-9af509fb5889

32 hex char + 4 hyphen char = 36 char. So the length will be always same.


Update:

I do not know what type 4 means in the case.?

FYI: There are several ways of generating UUID. Here type 4 means this uuid is generated using a random or pseudo-random number. From wiki - Universally_unique_identifier#Versions:

Versions


For both variants 1 and 2, five "versions" are defined in the standards, and each version may be more appropriate than the others in specific use cases. Version is indicated by the M in the string representation.

Version 1 UUIDs are generated from a time and a node id (usually the MAC address);

version 2 UUIDs are generated from an identifier (usually a group or user id), time, and a node id;

versions 3 and 5 produce deterministic UUIDs generated by hashing a namespace identifier and name;

and version 4 UUIDs are generated using a random or pseudo-random number.

Why is the initial call to UUID.randomUUID() slow?

it's the initialization of the SecureRandom that is done once:

//from the source code of randomUUID
private static class Holder {
static final SecureRandom numberGenerator = new SecureRandom();
}

But that's not all here. Those zeroes should really jump into your face. So the operation took 0 milliseconds; does it mean they took less? like a few nano-seconds or you are doing something wrong?

There's a proper tool to measure this things, called jmh.

@BenchmarkMode({ Mode.AverageTime, Mode.SingleShotTime })
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class UUIDRandom {

public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(UUIDRandom.class.getSimpleName()).build();
new Runner(opt).run();
}

@Benchmark
@Fork(1)
public UUID random() {
return UUID.randomUUID();
}
}

and the output says:

Benchmark          Mode  Cnt  Score   Error  Units
UUIDRandom.random avgt 2 0.002 ms/op
UUIDRandom.random ss 2 0.094 ms/op

Indeed single-shot time is far worse then the average.

Are Java random UUID's predictable?

Well if you want to know how random a UUID is you have to look onto the source.

The following code section is taken from OpenJDK7 (and it is identical in OpenJDK6):

public static UUID randomUUID() {
SecureRandom ng = numberGenerator;
if (ng == null) {
numberGenerator = ng = new SecureRandom();
}

byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version (set highest 4 bits to zero) */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant (set highest 2 bits to zero) */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}

As you can see only 2 of 16 bytes are not completely random. In the sixth byte you lose 4 of 8 bits and on byte 8 you loose 2 bits of randomness.

Therefore you will get an 128 bit value with 122 bit randomness.

The only problem that may arise from the manipulation is that with a high chance your data can be identified as an UUID. Therefore if you want to hide it in other random data this will not work...



Related Topics



Leave a reply



Submit