I want to create a cryptographically secure GUID (v4) in .NET.
.NET's Guid.NewGuid()
function is not cryptographically secure, but .NET does provide the System.Security.Cryptography.RNGCryptoServiceProvider
class.
I would like to be able to pass a random number function as a delegate to Guid.NewGuid
(or even pass some class that provides a generator interface) but it doesn't look as though that is possible with the default implementation.
Can I create a cryptographically secure GUID by using System.GUID
and System.Security.Cryptography.RNGCryptoServiceProvider
together?
Yes you can, Guid allows you to create a Guid using a byte array, and RNGCryptoServiceProvider can generate a random byte array, so you can use the output to feed a new Guid:
public Guid CreateCryptographicallySecureGuid()
{
using (var provider = new RNGCryptoServiceProvider())
{
var bytes = new byte[16];
provider.GetBytes(bytes);
return new Guid(bytes);
}
}
If anyone is interested here is the above sample code adjusted for .NET Core 1.0 (DNX)
public Guid CreateCryptographicallySecureGuid()
{
using (var provider = System.Security.Cryptography.RandomNumberGenerator.Create())
{
var bytes = new byte[16];
provider.GetBytes(bytes);
return new Guid(bytes);
}
}
https://tools.ietf.org/html/rfc4122 says there are a few bits that should be fixed in order to indicate that this GUID is a version-4 (random) one. Here is the code altered to set/unset these bits.
public Guid CreateCryptographicallySecureGuid()
{
using (var provider = new RNGCryptoServiceProvider())
{
var bytes = new byte[16];
provider.GetBytes(bytes);
bytes[8] = (byte)(bytes[8] & 0xBF | 0x80);
bytes[7] = (byte)(bytes[7] & 0x4F | 0x40);
return new Guid(bytes);
}
}
If you are using at least c# 7.2 and netcoreapp2.1 (or System.Memory
), this is the fastest/most efficient approach.
public static Guid CreateCryptographicallySecureGuid()
{
Span<byte> bytes = stackalloc byte[16];
RandomNumberGenerator.Fill(bytes);
return new Guid(bytes);
}
I created a benchmark comparing this to the accepted answer. I modified it to use a static implementation of RandomNumberGenerator
since GetBytes()
is thread safe. (although the only guarantee I see is that RNGCryptoServiceProvider
has a thread safe implementation...it's possible other implementations do not)
[MemoryDiagnoser]
public class Test
{
private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
[Benchmark]
public void Heap()
{
var bytes = new byte[16];
_rng.GetBytes(bytes);
new Guid(bytes);
}
[Benchmark]
public void Fill()
{
Span<byte> bytes = stackalloc byte[16];
RandomNumberGenerator.Fill(bytes);
new Guid(bytes);
}
}
| Method | Mean | Error | StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|------- |---------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
| Heap | 129.4 ns | 0.3074 ns | 0.2725 ns | 0.0093 | - | - | 40 B |
| Fill | 116.5 ns | 0.3440 ns | 0.2872 ns | - | - | - | - |
来源:https://stackoverflow.com/questions/37170388/create-a-cryptographically-secure-random-guid-in-net