3

I need to generate cryptographically secure, random and unique strings each of which will be used as an access token actually. For this purpose, I plan to use Java's SecureRandom class. But, I'm not sure that SecureRandom guarantees the uniqueness. In other words, does SecureRandom produces a different value on each time of the generation?

It seems like creating the instance with a seed value (i.e. new SecureRandom(byte[] seed)) may work. But, I'm not sure of that. Moreover, this answer states that the seed is neither safe nor portable. Does seed value serve my purpose?

If you have suggestions other than SecureRandom I want to hear them also.

ovunccetin
  • 8,443
  • 5
  • 42
  • 53
  • 3
    By the definition of random, it is merely unprobable that two consecutively generated strings are unique. You will have to check manually whether or not two strings are the same. – Olavi Mustanoja Oct 23 '14 at 12:08
  • This kind of question can often be answered by taking extremes. If you take just a single random bit, will it be unique? Well, the first time it will be, the second time it will be with a chance of 50% and the third time (if we didn't fail already), then you're certainly out of luck :) – Maarten Bodewes Oct 25 '14 at 10:46

2 Answers2

11

No, a SecureRandom instance does not guarantee unique results. If it did guarantee that, it wouldn't be entirely random, as you would know that you couldn't get a result that you already received.

Setting the seed value does not improve this situation. It also doesn't make it worse, because the seed you pass is added (supplements) the seed that was internally generated by the SecureRandom implementation.

If you want guaranteed unique random numbers, you need to keep all the previously generated numbers, and then check when you generate new number if it has already been returned. If it has, you need to generate a new number (and repeat the check).

However, if the number that you generate is significantly large, the chance of generating a non-unique number becomes insignificantly small. Try generating a number of 256 bits or more (32 bytes). This is also the mechanism the UUIDs use to generate "unique" numbers. These are also not guaranteed to be unique, but you'd have to wait a very, very long time (on average) before you get a duplicate.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • IIRC, one of the cryptographic weakness of the WW2 German Enigma system was that they insisted that some of the key values *had* to be different from each other. – Raedwald Oct 23 '14 at 12:20
  • 2
    For distinct random values see [How to generate a list of unique random strings?](http://crypto.stackexchange.com/questions/1379/how-to-generate-a-list-of-unique-random-strings). – rossum Oct 23 '14 at 15:45
1

You could leverage the Stream API support for generating an IntStream from the SecureRandom:

SecureRandom random = new SecureRandom();
OfInt iterator = random.ints().distinct().iterator();

int random = iterator.next();

The ints method returns an "effectively unlimited stream of pseudorandom int values", which you can make distinct and obtain an iterator over the elements.

Given that there are 2^32 possible values, I would guess this should be enough for practical usages.

M A
  • 71,713
  • 13
  • 134
  • 174