jed*_*ung 24 .net c# security guid
我想在.NET中创建一个加密安全的GUID(v4).
.NET的Guid.NewGuid()
功能不是加密安全的,但.NET确实提供了System.Security.Cryptography.RNGCryptoServiceProvider
类.
我希望能够将随机数函数作为委托Guid.NewGuid
传递给(或者甚至传递一些提供生成器接口的类),但它看起来并不像默认实现那样.
我可以创建通过使用密码安全GUID System.GUID
和System.Security.Cryptography.RNGCryptoServiceProvider
在一起?
Gus*_*man 40
是的,Guid允许您使用字节数组创建Guid,而RNGCryptoServiceProvider可以生成随机字节数组,因此您可以使用输出来提供新的Guid:
public Guid CreateCryptographicallySecureGuid()
{
using (var provider = new RNGCryptoServiceProvider())
{
var bytes = new byte[16];
provider.GetBytes(bytes);
return new Guid(bytes);
}
}
Run Code Online (Sandbox Code Playgroud)
Kan*_*ane 14
如果有人对此感兴趣,请参阅上面针对.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);
}
}
Run Code Online (Sandbox Code Playgroud)
我发现@rlamoni 的回答很棒。只需要在其按位运算中稍作修改即可正确反映 GUID 版本 4 识别位,以解决 Big Endian 和 Little Endian 架构。
更具体地说明我的答案中的更正:
正如用户Benrobot 所指出的,Guid 是无效的。我想是因为他的设备Endianness与我的不同。
这促使我进一步加强我的回答。除了我在上面的原始答案中指出的两个更正之外,这里还有一些我的答案的改进:
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
/// /sf/answers/4160625311/
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);
}
Run Code Online (Sandbox Code Playgroud)
要检查生成的 GUID 的有效性:
om-ha 的回答非常棒。但我想针对 .NET 5.0 对其进行优化,因为它不需要 RNG 加密提供程序。我对.NET 5.0的修改版本如下:
using System;
using System.Security.Cryptography;
/// Generates a cryptographically secure random Guid.
///
/// Characteristics
/// - GUID Variant: RFC 4122
/// - GUID Version: 4
/// - .NET 5
/// RFC
/// https://tools.ietf.org/html/rfc4122#section-4.1.3
/// Stackoverflow
/// https://stackoverflow.com/a/59437504/10830091
static Guid CreateCryptographicallySecureRandomRFC4122Guid()
{
// 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];
RandomNumberGenerator.Fill(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 -- 8th byte
bytes[variantByteIndex] = (byte)(bytes[variantByteIndex] & variantMask | variantShift);
// Initialize Guid from the modified random bytes
return new Guid(bytes);
}
Run Code Online (Sandbox Code Playgroud)
此处编辑使用RandomNumberGenerator
(文档),Fill
方法执行以下操作:
用加密的强随机字节填充跨度
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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您至少使用c#7.2和netcoreapp2.1(或System.Memory
),则这是最快/最有效的方法。
public static Guid CreateCryptographicallySecureGuid()
{
Span<byte> bytes = stackalloc byte[16];
RandomNumberGenerator.Fill(bytes);
return new Guid(bytes);
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个基准,将其与接受的答案进行比较。我修改了它以使用静态实现,RandomNumberGenerator
因为它GetBytes()
是线程安全的。(尽管我看到的唯一保证是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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 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 | - | - | - | - |
Run Code Online (Sandbox Code Playgroud)