I needed a way of creating a unique ID for users of a site, which would be visible to the user (in fact, they would need to use this ID as their login since the client did not want users to have to create a username and password).
I needed a way of creating a unique ID for users of a site, which would be visible to the user (in fact, they would need to use this ID as their login since the client did not want users to have to create a username and password). The main requirement is that it was non-guessable - that is, your chances of happening across or working out an ID which is in use and therefore being able to use this person's account are statistically small.
My first thought was to use a standard GUID - 32 characters, 16 possibilities for each character = 1632 possible IDs. Does the trick.
However the results are not particularly pretty. 36 characters (including the hyphens!) makes for a long URL. Trimming this down destroys the uniqueness of the GUID. Was there a way of preserving the uniqueness of the GUID while creating a nicer ID for the user?
Thanks to a large dollop of inspiration from trusty old Stack Overflow, I came to this:
Let's break that down:
First of all, we convert the new GUID into a base 64 string. This is where the real "magic" happens. This conversion keeps all of the bytes of the GUID, but increases the number of possible characters so that we can decrease the total number of characters. In order to encode 128 bits using base 16, we required 32 characters (128 / log2 16). But to encode 128 bits using base 64, we only need 22 characters (128 / log2 64).
Secondly, since every conversion will add 2 "padding characters" (==), we can just strip them away.
Finally, we stop .NET replacing the + with a space. In base 64, we have upper- and lower-case characters, 0-10 and two other characters - in the .NET implementation, these are + and /. However, when encoding for the web, it will handily replace the + with a space for you. We don't really want this, so I've just replaced it with a good old exclamation mark instead.
Here's one I made earlier: 72BB300F-161B-AF47-96B5-4CF0EB30CF25 becomes the much more lovely-looking crswDxYbr0eWtUzw6zDPJQ.
And there we go - your GUID, compressed to a little over 60% of its original size, without losing any of its uniqueness! Of course, there are a couple of issues with this approach.
One of them is the more predictable nature (relatively) of GUIDs compared to using something like the RNGCryptoServiceProvider. Another is the fact that it's still 22 characters long - not really what you'd call memorable. And finally, there's always the chance that your short GUID will happen to contain a string of characters that might offend!
So there is plenty of room for improvement - but given the time frame, I was pretty happy with the result.