Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中创建加密安全的随机GUID_C#_.net_Security_Guid - Fatal编程技术网

C# 在.NET中创建加密安全的随机GUID

C# 在.NET中创建加密安全的随机GUID,c#,.net,security,guid,C#,.net,Security,Guid,我想在.NET中创建一个加密安全的GUID(v4) .NET的Guid.NewGuid()函数在加密方面不安全,但.NET确实提供了System.Security.Cryptography.RNGCryptoServiceProvider类 我希望能够将一个随机数函数作为委托传递给Guid.NewGuid(或者甚至传递一些提供生成器接口的类),但在默认实现中,这似乎是不可能的 我可以一起使用System.GUID和System.Security.Cryptography.RNGCryptoSer

我想在.NET中创建一个加密安全的GUID(v4)

.NET的
Guid.NewGuid()
函数在加密方面不安全,但.NET确实提供了
System.Security.Cryptography.RNGCryptoServiceProvider

我希望能够将一个随机数函数作为委托传递给
Guid.NewGuid
(或者甚至传递一些提供生成器接口的类),但在默认实现中,这似乎是不可能的

我可以一起使用
System.GUID
System.Security.Cryptography.RNGCryptoServiceProvider
创建加密安全的GUID吗?

可以,允许您使用字节数组创建GUID,并可以生成随机字节数组,因此您可以使用输出来提供新的GUID:

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

        return new Guid(bytes);
    }
}

请阅读以下Brad M的答案:

如果有人对此感兴趣,以上示例代码是否针对.NET Core 1.0(DNX)进行了调整

表示应该固定一些位,以指示此GUID是版本4(随机)GUID。这是更改为设置/取消设置这些位的代码

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

如果您至少使用c#7.2和netcoreapp2.1(或
System.Memory
),这是最快/最有效的方法

公共静态Guid CreateCryptographicalySecureGUID()
{
Span字节=stackalloc字节[16];
RandomNumberGenerator.Fill(字节);
返回新的Guid(字节);
}
我创建了一个基准,将其与公认的答案进行比较。我对它进行了修改,使用了
RandomNumberGenerator
的静态实现,因为
GetBytes()
是线程安全的。(虽然我看到的唯一保证是
RNGCryptoServiceProvider
有线程安全的实现……但其他实现可能没有)

[MemoryDiagnoser]
公开课考试
{
私有静态只读RandomNumberGenerator\u rng=RandomNumberGenerator.Create();
[基准]
公共空堆()
{
var字节=新字节[16];
_rng.GetBytes(字节);
新Guid(字节);
}
[基准]
填空
{
Span字节=stackalloc字节[16];
RandomNumberGenerator.Fill(字节);
新Guid(字节);
}
}
2020年修订版 我发现@rlamoni's很棒。只需在其逐位操作中稍作修改,即可正确反映GUID版本4的标识位,从而兼顾大端和小端体系结构

更具体地说,我的回答中的更正:

  • 修改后的字节应为第7和第9个
  • 按位和操作数已更正
  • 更新 正如用户指出的,Guid无效。我想是因为他的装置和我的不同

    这促使我进一步加强我的回答。除了我在最初的回答中指出的两个更正之外,我的回答还有以下几点改进:

  • 说明了当前计算机体系结构的重要性
  • 添加了自解释常量和变量标识符,而不是常量文本
  • 使用了不需要大括号的语句
  • 使用指令添加了一些注释和必需的
  • 在线验证器 要检查生成的GUID的有效性,请执行以下操作:

    工具书类
    • RFC4122版本的
    • ,一个被低估的GUID库
    • 指南
    • Cryptosys
      Uuid.cs
      C#
    这部电影太棒了。但是我想为.NET5.0优化它,它不需要RNG加密提供程序。下面是我对.NET 5.0的修改版本

    使用系统;
    使用System.Security.Cryptography;
    ///生成加密安全的随机Guid。
    ///
    ///特征
    ///-变体:RFC 4122
    ///-版本:4
    ///RFC
    ///     https://tools.ietf.org/html/rfc4122#section-4.1.3
    ///堆栈溢出
    ///     https://stackoverflow.com/a/59437504/10830091
    静态Guid CreateCryptographicalySecureRandomRFC4122GUID()
    {
    //字节索引
    int versionByteIndex=BitConverter.IsLittleEndian?7:6;
    const int variantByteIndex=8;
    //'Version 4'的版本掩码和移位`
    const int versionMask=0x0F;
    const int versionShift=0x40;
    //RFC 4122的变体掩码和移位`
    常数int variantMask=0x3F;
    常量整型变量移位=0x80;
    //获取加密强随机值的字节
    var字节=新字节[16];
    RandomNumberGenerator.Fill(字节);
    //设置版本位——第6或第7字节,分别根据尾数、大尾数或小尾数设置
    字节[versionByteIndex]=(字节)(字节[versionByteIndex]&版本任务|版本移位);
    //设置变量位——第9字节
    字节[variantByteIndex]=(字节)(字节[variantByteIndex]和variantMask | variantShift);
    //从修改的随机字节初始化Guid
    返回新的Guid(字节);
    }
    
    等等,真的这么简单吗?我认为有一个GUID标准——前几个字节不是定义了使用的版本吗,而最后几个字节定义了其他东西吗?我认为GUID不仅仅是随机字节,因此问题就来了。加密安全GUID和标准化GUID之间有区别,如果希望GUID避免冲突,请使用GUID.NewGuid,否则请使用它。任何标准化的Guid在加密方面都是不安全的,因为正如您正确地说的,有规则生成它们,那么它的强度将非常低(如果您知道16个字节中的8个是如何生成的,您只需要强制执行这8个字节…)嗯,冲突规则是为了避免机器之间的冲突,如果我没记错的话,它认为在同一台机器上,这些guid之间发生冲突的几率要比标准化guid小得多,获得副本的几率在2^128之间,因此我们的太阳在我们脸上爆炸的可能性比标准化guid大得多
    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);
        }
    }
    
    | 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 |           - |           - |           - |                   - |
    
    using System;
    using System.Security.Cryptography;
    
    /// Generates a cryptographically secure random Guid.
    ///
    /// Characteristics
    ///     - Variant: RFC 4122
    ///     - Version: 4
    /// RFC
    ///     https://tools.ietf.org/html/rfc4122#section-4.1.3
    /// Stackoverflow
    ///     https://stackoverflow.com/a/59437504/10830091
    static Guid CreateCryptographicallySecureRandomRFC4122Guid()
    {
        using var cryptoProvider = new RNGCryptoServiceProvider();
    
        // byte indices
        int versionByteIndex = BitConverter.IsLittleEndian ? 7 : 6;
        const int variantByteIndex = 8;
    
        // version mask & shift for `Version 4`
        const int versionMask = 0x0F;
        const int versionShift = 0x40;
    
        // variant mask & shift for `RFC 4122`
        const int variantMask = 0x3F;
        const int variantShift = 0x80;
    
        // get bytes of cryptographically-strong random values
        var bytes = new byte[16];
        cryptoProvider.GetBytes(bytes);
    
        // Set version bits -- 6th or 7th byte according to Endianness, big or little Endian respectively
        bytes[versionByteIndex] = (byte)(bytes[versionByteIndex] & versionMask | versionShift);
    
        // Set variant bits -- 9th byte
        bytes[variantByteIndex] = (byte)(bytes[variantByteIndex] & variantMask | variantShift);
    
        // Initialize Guid from the modified random bytes
        return new Guid(bytes);
    }