5

I would like to generate random identifier in java. The identifier should have a fixed size, and the probability of generating the same identifier twice should be very low(The system has about 500 000 users).In addition; the identifier should be so long that it’s unfeasible to “guess it” by a brute force attack.

My approach so far is something along the lines of this:

String alphabet = "0123456789ABCDE....and so on";
int lengthOfAlphabet = 42; 
long length = 12; 

public String generateIdentifier(){
    String identifier = "";
    Random random = new Random(); 
    for(int i = 0;i<length;i++){
        identifier+= alphabet.charAt(random.nextInt(lengthOfAlphabet));
    }
    return identifier; 
}

I’m enforcing the uniqueness by a constraint in the database. If I hit an identifier that already has been created, I’ll keep generating until I find one that’s not in use.

My assumption is that I can tweak lenghtOfAlpahbet and length to get the properties I’m looking for:

  1. Rare collisions
  2. Unfeasible to brute force
  3. The identifier should be as short as possible, as the users of the system will have to type it.

Is this a good approach? Does anyone have any thoughts on the value of “length”?

Jonathan Muller
  • 7,348
  • 2
  • 23
  • 31
magnarwium
  • 235
  • 2
  • 14
  • 13
    Before we begin: please specify what is wrong with `UUID.randomUUID()`? Is it peraphs too long? It could be transformed into something shorter, for example encoding in base 64. – Marko Topolnik Oct 29 '12 at 14:30
  • true random numbers generated from quantum fluctuations of the vacuum http://150.203.48.55/index.php – NimChimpsky Oct 29 '12 at 14:31
  • @Marko: I guess the problem is requirement #3. There are easier-to-type random identifiers (but that might just be a formatting/parsing thing). – Joachim Sauer Oct 29 '12 at 14:31
  • @JoachimSauer What do you think of my idea to start off with randomUUID and post-process it into something denser, like base-64 representation? – Marko Topolnik Oct 29 '12 at 14:32
  • Not too bad, Marko. @letterboy: keep in mind that an alternative to very long random strings is to severely reduce the lifetime of that string and make do with shorter, but short-lived strings instead. For example instead of creating a huge, life-time-valid authentication token, generate a short (~6 character) token that is only valid once (and accepts at most 2 tries before it's invalidated). This way you can safe your users the pain of having to enter long strings and still get high security. – Joachim Sauer Oct 29 '12 at 14:34
  • @JoachimSauer Good point. For example, state-of-the-art security for e-banking uses 6-8 digits for a One-Time Password or a Challenge-Response. These are good role models for OP's problem. – Marko Topolnik Oct 29 '12 at 14:39
  • Combine short Strings for user with the hashed values of those Strings stored in database. Users only need to know the short String which is hashed and compared with the stored value. – Averroes Oct 29 '12 at 14:57
  • Thanks @MarkoTopolnik. I initially rejected the UUID–api thinking I could generate a token with fever characters that met my other requirements. I did not think to transform. – magnarwium Oct 29 '12 at 15:37
  • That’s a good point @JoachimSauer. I definitely see why this would be an advantage. Unfortunately it’s a hard requirement that the token should be long lived. – magnarwium Oct 29 '12 at 15:41
  • In addition to simply representing the full 128 bits as a base-64 number, you can also drop some parts of it or, for example, XOR two halves together. This will maintain uniqueness and randomness, I think, and will bring down the length. – Marko Topolnik Oct 29 '12 at 15:41
  • Any numeric identifier can be converted to a character string, by parsing it modulo 36 (or even just using Base64). On a single processor, `millisecondsSinceWhatever...` will give you as unique a number as you could hope for. If you, in addition, want it "random", run it through a cryptographic hash. Or use randomUUID. – Hot Licks Nov 12 '12 at 18:56

2 Answers2

2

I think randomUUID is your friend. It is fixed width. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/UUID.html#randomUUID()

If I remember my math correctly, since the UUID is 32 hex numbers (0-f) then the number of permutations are 16^32, which is a big number, and therefore pretty hard to guess.

Joel
  • 449
  • 1
  • 5
  • 12
1

I would suggest keeping it simple, and use built in methods to represent normal pseudo-random integers encoded as Strings:

Random random = new Random(); 

/**
 * Generates random Strings of 1 to 6 characters. 0 to zik0zj
 */
public String generateShortIdentifier() {
    int number;
    while((number=random.nextInt())<0);
    return Integer.toString(number, Character.MAX_RADIX);
}

/**
 * Generates random Strings of 1 to 13 characters. 0 to 1y2p0ij32e8e7
 */
public String generateLongIdentifier() {
    long number;
    while((number=random.nextLong())<0);
    return Long.toString(number, Character.MAX_RADIX);
}

Character.MAX_RADIX is 36, which would equal an alphabet of all 0 to 9 and A to Z. In short, you would be converting the random integers to a number of base 36.

If you want, you can tweak the length you want, but in just 13 characters you can encode 2^63 numbers.

EDIT: Modified it to generate only 0 to 2^63, no negative numbers, but that's up to you.

Joel Westberg
  • 2,656
  • 1
  • 21
  • 27