webentwicklung-frage-antwort-db.com.de

Erstellen Sie eine kryptografisch sichere Zufallsauswahl GUID in .NET

Ich möchte ein kryptografisch sicheres GUID (v4) in .NET erstellen.

Die Guid.NewGuid()-Funktion von .NET ist nicht kryptographisch sicher, aber .NET stellt die System.Security.Cryptography.RNGCryptoServiceProvider-Klasse bereit.

Ich möchte gerne eine Zufallszahlenfunktion als Delegat an Guid.NewGuid übergeben (oder sogar eine Klasse übergeben, die eine Generatorschnittstelle bereitstellt), aber es sieht nicht so aus, als wäre dies mit der Standardimplementierung möglich.

Kann ich ein kryptografisch sicheres GUID erstellen, indem Sie System.GUID und System.Security.Cryptography.RNGCryptoServiceProvider zusammen verwenden?

20
jedd.ahyoung

Ja, Sie können mit Guid eine Guid mit einem Byte-Array erstellen, und RNGCryptoServiceProvider kann ein zufälliges Byte-Array generieren, sodass Sie die Ausgabe verwenden können, um eine neue Guid zu füttern:

public Guid CreateCryptographicallySecureGuid() 
{
    using (var provider = new RNGCryptoServiceProvider()) 
    {
        var bytes = new byte[16];
        provider.GetBytes(bytes);

        return new Guid(bytes);
    }
}
31
Gusman

Wenn jemand interessiert ist, ist der obige Beispielcode für .NET Core 1.0 (DNX) angepasst.

public Guid CreateCryptographicallySecureGuid()
{
    using (var provider = System.Security.Cryptography.RandomNumberGenerator.Create())
    {
        var bytes = new byte[16];
        provider.GetBytes(bytes);

        return new Guid(bytes);
    }
}
13
Kane

https://tools.ietf.org/html/rfc4122 sagt, es gibt ein paar Bits, die korrigiert werden sollten, um anzuzeigen, dass es sich bei GUID um eine Version 4 (zufällig) handelt. Hier ist der Code geändert, um diese Bits zu setzen/zu setzen.

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);
    }
}
4
rlamoni

Wenn Sie mindestens c # 7.2 und netcoreapp2.1 (oder System.Memory) verwenden, ist dies der schnellste/effizienteste Ansatz.

public static Guid CreateCryptographicallySecureGuid()
{
    Span<byte> bytes = stackalloc byte[16];
    RandomNumberGenerator.Fill(bytes);
    return new Guid(bytes);
}

Ich habe einen Benchmark erstellt, der dies mit der akzeptierten Antwort vergleicht. Ich habe es geändert, um eine statische Implementierung von RandomNumberGenerator zu verwenden, da GetBytes() threadsicher ist. (obwohl die einzige Garantie, die ich sehe, ist, dass RNGCryptoServiceProvider eine Thread-sichere Implementierung hat ... es ist möglich, dass andere Implementierungen dies nicht tun)

[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 |           - |           - |           - |                   - |
1
Brad M