web-dev-qa-db-ja.com

.NETで暗号的に安全なランダムGUID=を作成する

.NETで暗号的に安全なGUID(v4)を作成したい。

.NETのGuid.NewGuid()関数は暗号的に安全ではありませんが、.NETはSystem.Security.Cryptography.RNGCryptoServiceProviderクラスを提供しています。

乱数関数をGuid.NewGuidへのデリゲートとして渡す(またはジェネレーターインターフェイスを提供するクラスを渡す)ことができるようにしたいのですが、デフォルトの実装ではそれが可能であるようには見えません。

System.GUIDSystem.Security.Cryptography.RNGCryptoServiceProviderを一緒に使用して、暗号的に安全なGUID=を作成できますか?

28
jedd.ahyoung

はい、できます Guid ではバイト配列を使用してGuidを作成できます RNGCryptoServiceProvider ではランダムなバイト配列を生成できるため、出力を使用して新しいGuidをフィードできます:

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

        return new Guid(bytes);
    }
}
39
Gusman

誰かがここに興味があるなら、上記のサンプルコードを.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);
    }
}
14
Kane

https://tools.ietf.org/html/rfc4122 は、これがGUIDがバージョンであることを示すために修正する必要があるいくつかのビットがあると言います- 4(ランダム)1.これらのビットを設定/設定解除するために変更されたコードは次のとおりです。

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

少なくともc#7.2とnetcoreapp2.1(または_System.Memory_)を使用している場合、これが最速/最も効率的なアプローチです。

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

これを受け入れられた回答と比較するベンチマークを作成しました。 GetBytes()はスレッドセーフであるため、RandomNumberGeneratorの静的実装を使用するように変更しました。 (私が見る唯一の保証は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 |           - |           - |           - |                   - |
_
4
Brad M