What is a valid UUID?
Asked Answered
W

5

7

I generate UUIDs, and valid them against a Regex in my code; I just ran into problems that confused me

Here is the code that generates UUIDs (in a mongodb context)

import java.util.UUID;
... ...

Document setOnInsert = new Document(Params.sender, UUID.randomUUID())
                                    .append(Params.userDevice, userDevice)
                                    .append(Params.hostId,"");

This is the code of validating an UUID; I had copied the Regex from this post

static final Pattern UUID = Pattern.compile("([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})");

    public static boolean isUUID(String uuid){
        if(uuid == null){
            return false;
        }else{
            return UUID.matcher(uuid).matches();
        }
    }

and below are the 2 UUIDs that I have problems with

aa4aaa2c-c6ca-d5f5-b8b2-0b5c78ee2cb7
b24dd64c-de6b-5bf6-6283-aa2167cc93a7

These two UUIDs had been generated by the code mentioned above; the validating method (isUUID()) judged them as invalid in my latest debug; yet I posted these UUIDs to an online validator , and it says ok

This is my system information

wjz@bj:~$ java -version 
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
wjz@bj:~$ 
wjz@bj:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:    16.04
Codename:   xenial
wjz@bj:~$ 

Some background: I had been working on jdk 1.8.0_111; these UUIDs had been generated then, and had no problems. then I upgraded to 1.8.0_121 today, and run into this problem...

So my question is: Whether the above mentioned UUIDs are correct or wrong? who to believe, the generator or the validation

Wriggly answered 19/1, 2017 at 8:33 Comment(7)
Why not just use the UUID class to validate them? UUID.fromString()Alissaalistair
Well the problem is with this part of the pattern: [1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}. In the first one you've got a "d" where you should have 1-5; in the second one you've got 6 where you should have 8-b.Spragens
RFC 4122 has no such restrictions on the first hex digit of those groups, it just says the group consists of two hexOctet (which is two hex digits each). You are restricting it more than the specification does. Trust the built-in generator, distrust the "found somewhere on the internet" validator.Tigre
actually, the isUUID() is a protection before UUID.fromString() in my code; otherwise, i might got an exception if my feed of string is not an UUIDWriggly
UUID of java is correct, so the prime suspect is the regex, I posted a valid regex below.Gant
Possible duplicate of Foolproof way of differentiating String and UUIDMaxwell
RFC 4122 does restrict the first hex digit of those groups in §4.1.3 and §4.1.1 for the Version and Variant of the UUID.Nottingham
A
8

My suggestion is, do not reinvent the wheel.

Basically, if you generate the ids with UUID.randomUUID(), there is no need to validate them. If you are anyway curious that they might get manipulated manually. You can just use UUID.fromString(yourUUID) and catch the IllegalArgumentExcepetion and the NumberFormatException that might be thrown.

Throws IllegalArgumentExcepetion:

If name does not conform to the string representation as described in toString()

Furthermore, you can check behind, if the UUID got converted correctly with

UUID id = UUID.fromString(yourUUID);
if(id.toString().equals(yourUUID){
    //success
}
Amplitude answered 21/6, 2017 at 13:37 Comment(2)
In Java 8 fromString will not throw an exception if the UUID is not valid. It will simply cut some digits and consider that the UUID is valid. This is a known bug, see here bugs.java.com/view_bug.do?bug_id=8159339 . As @Amplitude mentions equals gets the job done.Tropo
One thing to look after is that UUID.fromString does not specify the expected UUID version, so it will guess and take whatever works. So you may also check for the version using yourUUID.version() == 4 for example.Gant
S
4

You can use UUID.randomUUID() which will generate a valid UUID, you dont need the regx.

Secateurs answered 19/1, 2017 at 8:52 Comment(3)
thank for giving me the confidence on the generator. well, the scenario is that UUIDs were generated, yet not consumed and expired right away; instead, they might live for quite some time, might be save, copied and transmitted. so it is a precaution against any exception before usingWriggly
@Jobin: we don't see where isUUID is called and the question already contained UUID.randomUUID(). The regex was just used to validate the input, so it's ok to use it.Errhine
I dont think he need to validate the UUID which is generated using UUID.randomUUID() (will return a valid uuid)Secateurs
G
1

Had a look at some other SO answers, other languages ..., and here is a pure Java solution which handles v4 cases (as used by default in Java 8):

 UUID myUuid = UUID.fromString(uuidStr); // Step 1, throws errors !
 ... myUuid.version() == 4 // Step 2, check for the version you desire

See: https://docs.oracle.com/javase/9/docs/api/java/util/UUID.html#version--

Here is an example of a perfectly valid UUID string but version 1:

  public static void main(final String[] args) {
    final UUID myUuid = UUID.fromString("61614667-d279-11e7-a5ac-f941ac8dfc39");
    System.out.println(myUuid.version()); // Prints 1, not 4 !
  }

To try out more v4 UUIDs use UUID.randomUUID() or online: https://www.uuidgenerator.net/version4

Note: UUID.randomUUID() of Java will work well see How good is Java's UUID.randomUUID?

Security note:

Static factory to retrieve a type 4 (pseudo randomly generated) UUID. The UUID is generated using a cryptographically strong pseudo random number generator

Gant answered 21/6, 2017 at 13:9 Comment(0)
E
1

There are several aspects:

  • Total UUID length
  • Characters used
  • Valid size of groups (between dashes)
  • Lower case or upper case
  • Valid version
  • Valid variant
  • Nil allowed

To have a code example, see the UUID validator implementation I recently added to Apache Commons Validator. It's not yet been merged, but you can vote for it here: https://github.com/apache/commons-validator/pull/68

Epanodos answered 7/1, 2022 at 9:22 Comment(2)
Excellent validator!Mantilla
Thanks, so much @fabiolimace! I also added a bean validation constraint to the Hibernate Validators. They reviewed it, but the merge takes time. Vote if you want to support it: github.com/hibernate/hibernate-validator/pull/1199Epanodos
U
0

Since no one has mentioned it yet (and I can't yet comment, which would be more appropriate), I thought I'd share the problems with the two UUIDs you posted.

aa4aaa2c-c6ca-d5f5-b8b2-0b5c78ee2cb7
              ^
b24dd64c-de6b-5bf6-6283-aa2167cc93a7
                   ^

Digit 13 contains the UUID version. Valid values for this digit are limited to the range of 0-5. These are:
0 - Nil: Only valid if the whole UUID is 0s.
1 - Time Based: UUID is derived from the current time and the MAC address of the machine creating the UUID.
2 - DCE security: Format is specified by OSF for Distributed Computing Environments.
3 - MD5 Namespace: Based on hash values generated by the MD5 algorithm.
4 - Random number: Otherwise almost totally random digits (see also below). Probably the best fit for yours.
5 - SHA1 Namespace: Similar to 3, based on hash values generated by the SHA1 algorithm.

Digit 17 contains the UUID variant. Validation of this one is trickier, as values between 0-14 (E) are legal but mostly indicate reserved variants. These are:
0-7: Reserved for backwards compatibility.
8-11(B): Current (DCE1.1, ISO/IEC 11578:1996)
12(C)-13(D): Reserved by Microsoft
E(14): Reserved for future use
F(15): Invalid

Like with the version number, 0 is always valid if the whole UUID is 0s.

I'm assuming whatever disqualified the second UUID wants you to give a variant that is current, because I don't see another reason that would make it invalid. Restricting to the current variant means the value needs to be in the range of 8-11 (8, 9, A, or B in hex).

Utile answered 17/4, 2024 at 19:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.