Disclaimer

Any opinions expressed here are my own and not necessarily those of my employer (I'm self-employed).

Jul 29, 2012

Generating secure Guids

Guids are used extensively throughout Microsoft systems and developers tend to turn to Guid.NewGuid() whenever they need to create a value to uniquely identify something. Guids might also be used as keys or identifiers in security critical operations — under the assumption that they are hard to guess for an attacker. I've been looking around the Internet to see if I could find some guidance on Guid security along with details on how they are generated in the .NET framework. I couldn't find much information, but I did find that Eric Lippert from the C# team recently raised some concerns about the Guids on his blog. So I started digging around to see what more I could find out.

First of all a quick background. Microsoft's Guid is their implementation of the Universally Unique IDentifier (UUID) outlined in RFC 4122. UUIDs are 128 bits, and the Guid class generates version 4 UUIDs, meaning that all bits except those defining the version and variant of the UUID are "random." Please note that 4 bits are used for the version number, and two bits are used for the variant — so it's not a 128 bit random number, it's a 122 bit random number.

I looked into how these Guids are created in the .NET framework. Turns out Guid.NewGuid() simply calls the CoCreateGuid  function on the native ole32.dll, which in turn calls the RPC function UuidCreate. And from its remarks:
The UuidCreate function generates a UUID that cannot be traced to the ethernet address of the computer on which it was generated. It also cannot be associated with other UUIDs created on the same computer. 
Some care has been taken when generating these Guids, but the documentation is far from fullfilling. It's still unclear how easy they are to predict. So, assuming that we cannot trust Guids to be all that "secure", what to do? I've looked around for code that generates a Guid based on the output of a cryptographically strong RNG but couldn't find a good example — so I wrote my own generator that uses the RngCryptoServiceProvider. That way, we know where the bits are coming from. Since it generates proper Guid instances it should be fairly easy to plug it into existing code, e.g. replacing Guid.NewGuid() with SecureGuid.NewGuid(). Also remember to look out for Guids created by constructor: new Guid().

The code

Here's what the code could look like if you wanted to generate a GUID using random bytes from the frameworks's cryptograpically strong RNG. Note the first four bits of the time_hi_and_ver variable is set to version number four, and the first two bits of byte number eight is set according to the variant. Have a look at  RFC 4122  for more details. Apart from that, the code should be straightforward to understand.

using System;
using System.Security.Cryptography;

namespace SecureGuidDemo
{
    class SecureGuid
    {

        public static Guid NewGuid()
        {
            byte[] bytes = { 0x00, 0x00, 0x00, 0x00,
                               0x00, 0x00, 0x00, 0x00,
                               0x00, 0x00, 0x00, 0x00,
                               0x00, 0x00, 0x00, 0x00 };

            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(bytes);
                
            }
            var time = BitConverter.ToUInt32(bytes,0);
            var time_mid = BitConverter.ToUInt16(bytes,4);
            var  time_hi_and_ver = BitConverter.ToUInt16(bytes,6);
            time_hi_and_ver = (ushort)((time_hi_and_ver | 0x4000) & 0x4FFF);
            
            bytes[8] = (byte)((bytes[8] | 0x80) & 0xBF);
            
            return new Guid(time,time_mid,time_hi_and_ver,
                bytes[8],bytes[9],bytes[10],bytes[11],bytes[12],bytes[13],
                bytes[14],bytes[15]);
        }
    }
}

You might look at the code and find it funny that I used the constructor that takes an int, short, short, and byte's. The reason is that I found a bug when creating Guids based on byte arrays. The above code does not trigger the bug, so it should work now and should also work after the bug is fixed (if they decide to do so). I'm in the process of verifying the bug with Microsoft, I'll probably put something up on my blog about it when that's settled.

2 comments:

  1. This is awesome!! really helpful for me. Thanks for sharing with us. Following links also helped me to complete my task.

    http://msdn.microsoft.com/en-IN/library/system.guid(v=vs.71).aspx
    http://www.mindstick.com/Articles/93446478-8ec4-4f1d-b87f-8248e0f7d6ad/?GUID%20in%20NET

    ReplyDelete
  2. how can i use this sample for 32 bit GUID

    ReplyDelete

Copyright notice

© André N. Klingsheim and www.dotnetnoob.com, 2009-2013. Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and/or owner is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to André N. Klingsheim and www.dotnetnoob.com with appropriate and specific direction to the original content.

Read other popular posts