/// <summary> /// Generate a namespace GUID (V3 or V5) with a given algorithm /// </summary> /// <param name="namespaceId">The namespace we're generating the GUID in</param> /// <param name="name">The name we're generating the GUID for</param> /// <param name="version">The version to generate (MD5 or SHA1)</param> /// <returns></returns> private static UUID GenerateNameBased(System.Guid namespaceId, string name, GuidVersion version) { if (version != GuidVersion.MD5 && version != GuidVersion.SHA1) { throw new ArgumentException("version", "Name based guids can only be version 3, or 5"); } if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name", "The name parameter cannot be empty or null"); } byte[] nameBytes = Encoding.UTF8.GetBytes(name); byte[] namespaceBytes = namespaceId.ToByteArray(); if (BitConverter.IsLittleEndian) { ToggleEndianess(namespaceBytes); } var hash = version == GuidVersion.MD5 ? HashProvider.GenerateMD5Hash(namespaceBytes, nameBytes) : HashProvider.GenerateSHA1Hash(namespaceBytes, nameBytes); if (BitConverter.IsLittleEndian) { ToggleEndianess(hash); } return(GenerateFromComponents( hash.Skip(Constants.TIMESTAMP_BYTE_INDEX).Take(Constants.TIME_BYTES_LENGTH).ToArray(), hash.Skip(Constants.CLOCK_SEQUENCE_BYTE_INDEX).Take(Constants.CLOCK_SEQUENCE_BYTES_LENGTH).ToArray(), hash.Skip(Constants.NODE_BYTE_INDEX).Take(Constants.NODE_BYTES_LENGTH).ToArray(), version, GuidVariant.RFC4122)); }
public static Guid Create(Guid @namespace, byte[] name, GuidVersion version) { var namespaceBytes = @namespace.ToBigEndianByteArray(); byte[] hash; using (var algorithm = version == GuidVersion.NameBasedMd5 ? MD5.Create() : SHA1.Create() as HashAlgorithm) { algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0); algorithm.TransformFinalBlock(name, 0, name.Length); hash = algorithm.Hash; } var guidBytes = new byte[16]; Array.Copy(hash, 0, guidBytes, 0, 16); GuidUtility.EndianSwap(guidBytes); //Variant RFC4122 guidBytes[8] = (byte)((guidBytes[8] & 0x3F) | 0x80);//big-endian octet 8 //Version guidBytes[7] = (byte)((guidBytes[7] & 0x0F) | ((int)version << 4));//big-endian octet 6 return(new Guid(guidBytes)); }
/// <summary> /// Creates a named, MD5-based (version 3) GUID. /// </summary> /// <param name="namespace">The GUID that defines the namespace.</param> /// <param name="name">The name within that namespace.</param> /// <param name="version">The version of GUID to create.</param> private static Guid CreateNamed(Guid @namespace, byte[] name, GuidVersion version) { var namespaceBytes = @namespace.ToBigEndianByteArray(); byte[] hash; #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms #pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms using (var algorithm = version == GuidVersion.NameBasedMd5 ? MD5.Create() : SHA1.Create() as HashAlgorithm) #pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms #pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms { algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0); algorithm.TransformFinalBlock(name, 0, name.Length); hash = algorithm.Hash; } var guidBytes = new byte[16]; Array.Copy(hash, 0, guidBytes, 0, 16); GuidUtility.EndianSwap(guidBytes); // Variant RFC4122 guidBytes[8] = (byte)((guidBytes[8] & 0x3F) | 0x80); // big-endian octet 8 // Version guidBytes[7] = (byte)((guidBytes[7] & 0x0F) | ((int)version << 4)); // big-endian octet 6 return(new Guid(guidBytes)); }
/// <summary> /// Create /// </summary> /// <param name="namespace"></param> /// <param name="name"></param> /// <param name="version"></param> /// <returns></returns> public static Guid Create(Guid @namespace, byte[] name, GuidVersion version) { switch (version) { //Creates a random (version 4) GUID. case GuidVersion.Random: return(CreateRandom()); //Creates a named, MD5-based (version 3) GUID. case GuidVersion.NameBasedMd5: return(NamedGuidProvider.Create(@namespace, name, GuidVersion.NameBasedMd5)); //Creates a named, SHA1-based (version 5) GUID. case GuidVersion.NameBasedSha1: return(NamedGuidProvider.Create(@namespace, name, GuidVersion.NameBasedSha1)); case GuidVersion.TimeBased: return(Create(CombStyle.NormalStyle)); //Creates a random (version 4) GUID. default: return(Guid.NewGuid()); } }
/// <summary> /// Generate a GUID from its components /// </summary> /// <param name="timeBytes">The time based component</param> /// <param name="clockSequenceBytes">The clock sequence component</param> /// <param name="nodeBytes">The node component</param> /// <param name="version">The GUID version</param> /// <param name="variant">The GUID variant</param> /// <returns></returns> private static UUID GenerateFromComponents(byte[] timeBytes, byte[] clockSequenceBytes, byte[] nodeBytes, GuidVersion version, GuidVariant variant) { var guidBytes = new byte[Constants.GUID_BYTES_LENGTH]; if (clockSequenceBytes == null) { throw new ArgumentException("Please specify the clock sequence bytes", "clockSequenceBytes"); } if (nodeBytes == null) { throw new ArgumentException("Please specify the node bytes", "nodeBytes"); } if (clockSequenceBytes.Length != Constants.CLOCK_SEQUENCE_BYTES_LENGTH) { throw new ArgumentException("The clock sequence bytes must be of length " + Constants.CLOCK_SEQUENCE_BYTES_LENGTH, "clockSequenceBytes"); } if (nodeBytes.Length != Constants.NODE_BYTES_LENGTH) { throw new ArgumentException("The node bytes must be of length " + Constants.NODE_BYTES_LENGTH, "nodeBytes"); } if (timeBytes.Length != Constants.TIME_BYTES_LENGTH) { throw new ArgumentException("The time bytes must be of length " + Constants.TIME_BYTES_LENGTH, "nodeBytes"); } //Copy over the different byte segments Array.Copy(timeBytes, 0, guidBytes, Constants.TIMESTAMP_BYTE_INDEX, Constants.TIME_BYTES_LENGTH); Array.Copy(clockSequenceBytes, 0, guidBytes, Constants.CLOCK_SEQUENCE_BYTE_INDEX, Constants.CLOCK_SEQUENCE_BYTES_LENGTH); Array.Copy(nodeBytes, 0, guidBytes, Constants.NODE_BYTE_INDEX, Constants.NODE_BYTES_LENGTH); //To put in the variant, take the 9th byte and perform an and operation using 0x3f, followed by an or operation with 0x80. //Put in the version int maskVariant = 0x3f; int shiftVariant = 0; switch (variant) { case GuidVariant.FutureReserved: maskVariant = 0x1F; shiftVariant = 0xE0; break; case GuidVariant.MicrosoftReserved: maskVariant = 0x1F; shiftVariant = 0xC0; break; case GuidVariant.NCSReserved: maskVariant = 0x0; shiftVariant = 0x0; break; case GuidVariant.RFC4122: maskVariant = 0x3f; shiftVariant = 0x80; break; default: maskVariant = 0x3f; shiftVariant = 0; break; } int maskVersion = 0x3f; int shiftVersion = 0x3f; switch (version) { case GuidVersion.DCE: maskVersion = 0x0f; shiftVersion = 0x20; break; case GuidVersion.MD5: maskVersion = 0x0f; shiftVersion = 0x30; break; case GuidVersion.Random: maskVersion = 0x0f; shiftVersion = 0x40; break; case GuidVersion.SHA1: maskVersion = 0x0f; shiftVersion = 0x50; break; case GuidVersion.Time: maskVersion = 0x0f; shiftVersion = 0x10; break; default: maskVersion = 0x3f; shiftVersion = 0; break; } guidBytes[Constants.VARIANT_BYTE_INDEX] &= (byte)maskVariant; guidBytes[Constants.VARIANT_BYTE_INDEX] |= (byte)shiftVariant; guidBytes[Constants.VERSION_BYTE_INDEX] &= (byte)maskVersion; guidBytes[Constants.VERSION_BYTE_INDEX] |= (byte)shiftVersion; return(new UUID(new System.Guid(guidBytes))); }
public GuidAttribute(GuidVersion version = (GuidVersion) ~0) { this.version = version; }