4

In order to access resources in my web service application, client applications need to provide a shared secret unique for each resource.

Question is: Are Longs generated by a SecureRandom reasonably safe for this purpose (e.g. against brute force attacks)? Or should I use a UUID instead?

The web service runs over HTTPS and I can guarantee that no collision (with either Long or UUID) occurs. Question really only is whether the domain of a Long in Java is large enough to provide protection against exhaustive attacks over HTTPS.

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
Pascal Kesseli
  • 1,620
  • 1
  • 21
  • 37
  • 64 bits does not look very safe to me... of course it depends of what you are trying to secure. What is wrong with a `byte[256]`? – SJuan76 Feb 19 '13 at 07:31
  • 1
    This is a "How long is a piece of String" kind of question ... – Stephen C Feb 19 '13 at 07:44
  • 1
    I agree 64-bits look a bit short. For instance, if you can create 32-bits worth of targets and can make 32-bits of attempts you'll probably get a collision (shift bits between the two as you prefer). / Why `java.lang.Long`? Presumably to avoid writing an appropriate class, but that class should be written. – Tom Hawtin - tackline Feb 19 '13 at 08:04
  • Hm, I guess "it depends" is the answer I knew all along, but didn't want to hear. I changed my model to use String ids, which present themselves expandable should I find out that collisions or leaks occur. Currently, alphanumeric sequences of 30 characters, valid for two weeks, should provide an acceptable amount of security for the kind of data I'm protecting. – Pascal Kesseli Feb 19 '13 at 10:14

2 Answers2

2

The simple answer is that you can't EVER guarantee there won't be any collisions for a randomly generated number pair / sequence. All you can do is design things so that the probability of a collision is acceptably low for the application. How low that probability needs to be depends on the details of the application.

The thing that puzzles me about this is why a collision would be a problem with shared secrets at all. Are you really asking about the probability of someone guessing the shared secret?


OK, so this is a simple maths problem. Take the long example.

  • There are 2^64 possible values of a long.
  • About V of these are "valid secrets".
  • Some bad guy could plausibly try out N guessed secrets per second.
  • You can derive a formula for the probability P that someone can guess one of your secrets in a given time interval T.

Derive the formula, plug in the variables V, N and T, and decide whether P is acceptable.

Note that "a practically relevant chance" is not something we can advise you on. Rather you should be deciding what an acceptable risk ... based on an analysis of the costs / consequences of someone succeeding in breaking your scheme.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • "Are you really asking about the probability of someone guessing the shared secret?" - Yes. The probability of a collision is zero, because I have a list of all issued secrets and can verify whether a generated secret already exists (and regenerate accordingly). My only worry was whether, in a pure Long-based domain, exhaustive searches over HTTPS on my web server might have a practically relevant chance of success, given that at any time less than 100 valid secrets are active in the system. – Pascal Kesseli Feb 19 '13 at 10:19
  • Thanks for that assessment - and the real answer to this question, which is that I need to judge for myself whether that probability is acceptable. – Pascal Kesseli Feb 20 '13 at 08:23
1

Perhaps, but why use them when the JCE supports this very function?

DHParameterSpec dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, skip1024Base);
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH", "BC");
aliceKpairGen.initialize(dhSkipParamSpec);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

aliceKeyAgree = KeyAgreement.getInstance("DH", "BC");
aliceKeyAgree.init(aliceKpair.getPrivate());


//... obtaining Bob's Public Key
aliceKeyFac = KeyFactory.getInstance("DH", "BC");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);

aliceKeyAgree.doPhase(bobPubKey, true);
SecretKey aliceAesKey = aliceKeyAgree.generateSecret("AES");

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, aliceAesKey);
byte[] cipherText = cipher.doFinal(plaintext.getBytes());

And your AES-encrypted text is in cipherText now. Hope that helped...

hd1
  • 33,938
  • 5
  • 80
  • 91