Подтвердить что ты не робот

Создайте криптографически безопасный случайный GUID в .NET.

Я хочу создать криптографически безопасный GUID (v4) в .NET.

Функция .NET Guid.NewGuid() не является криптографически безопасной, но .NET предоставляет класс System.Security.Cryptography.RNGCryptoServiceProvider.

Я хотел бы иметь возможность передавать функцию случайного числа в качестве делегата в Guid.NewGuid (или даже передавать некоторый класс, предоставляющий интерфейс генератора), но это не выглядит так, как это возможно при реализации по умолчанию.

Можно ли создать криптографически безопасный GUID с помощью System.GUID и System.Security.Cryptography.RNGCryptoServiceProvider вместе?

4b9b3361

Ответ 1

Да, вы можете, Guid, вы можете создать Guid с использованием массива байтов и RNGCryptoServiceProvider может генерировать случайный массив байтов, поэтому вы можете использовать вывод для подачи нового руководства:

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

        return new Guid(bytes);
    }
}

Ответ 2

Если вам интересен приведенный выше примерный код, скорректированный для .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);
    }
}

Ответ 3

https://tools.ietf.org/html/rfc4122 говорит, что есть несколько битов, которые должны быть исправлены, чтобы указать, что этот GUID является версией 4 (случайной). Вот код, измененный для установки/сброса этих битов.

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

Если вы используете как минимум С# 7.2 и netcoreapp2.1 (или System.Memory), это самый быстрый/самый эффективный подход.

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

Я создал тест, сравнивая это с принятым ответом. Я изменил его, чтобы использовать статическую реализацию RandomNumberGenerator так как GetBytes() является потокобезопасным. (хотя единственная гарантия, которую я вижу, заключается в том, что RNGCryptoServiceProvider имеет поточно- RNGCryptoServiceProvider реализацию... возможно, другие реализации этого не делают)

[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 |           - |           - |           - |                   - |