Elz*_*lzo 9 c# random cryptography
我必须在给定范围内为生成密码的程序生成一个统一的,安全的随机整数.现在我用这个:
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] rand = new byte[4];
rng.GetBytes(rand);
int i = BitConverter.ToUInt16(rand, 0);
int result = i%max; //max is the range's upper bound (the lower is 0)
Run Code Online (Sandbox Code Playgroud)
这种方法是否可以安全地用于加密目的?如果没有,我该怎么办?
Sch*_*ltz 13
接受的答案中有两个问题。
using System;
using System.Security.Cryptography;
namespace CovidMassTesting.Helpers
{
/// <summary>
/// Secure random generator
///
/// <https://stackoverflow.com/questions/42426420/how-to-generate-a-cryptographically-secure-random-integer-within-a-range>
///
/// </summary>
public class RandomGenerator : IDisposable
{
private readonly RNGCryptoServiceProvider csp;
/// <summary>
/// Constructor
/// </summary>
public RandomGenerator()
{
csp = new RNGCryptoServiceProvider();
}
/// <summary>
/// Get random value
/// </summary>
/// <param name="minValue"></param>
/// <param name="maxExclusiveValue"></param>
/// <returns></returns>
public int Next(int minValue, int maxExclusiveValue)
{
if (minValue == maxExclusiveValue)
return minValue;
if (minValue > maxExclusiveValue)
{
throw new ArgumentOutOfRangeException($"{nameof(minValue)} must be lower than {nameof(maxExclusiveValue)}");
}
var diff = (long)maxExclusiveValue - minValue;
var upperBound = uint.MaxValue / diff * diff;
uint ui;
do
{
ui = GetRandomUInt();
} while (ui >= upperBound);
return (int)(minValue + (ui % diff));
}
private uint GetRandomUInt()
{
var randomBytes = GenerateRandomBytes(sizeof(uint));
return BitConverter.ToUInt32(randomBytes, 0);
}
private byte[] GenerateRandomBytes(int bytesNumber)
{
var buffer = new byte[bytesNumber];
csp.GetBytes(buffer);
return buffer;
}
private bool _disposed;
/// <summary>
/// Public implementation of Dispose pattern callable by consumers.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Protected implementation of Dispose pattern.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
csp?.Dispose();
}
_disposed = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
/// <summary>
/// Generates a random password,
/// respecting the given strength requirements.
/// </summary>
/// <param name="opts">A valid PasswordOptions object
/// containing the password strength requirements.</param>
/// <returns>A random password</returns>
public static string GenerateRandomPassword(PasswordOptions opts = null)
{
if (opts == null) opts = new PasswordOptions()
{
RequiredLength = 10,
RequiredUniqueChars = 4,
RequireDigit = true,
RequireLowercase = true,
RequireNonAlphanumeric = true,
RequireUppercase = true
};
string[] randomChars = new[] {
"ABCDEFGHJKLMNOPQRSTUVWXYZ", // Uppercase
"abcdefghijkmnopqrstuvwxyz", // Lowercase
"0123456789", // Digits
"!@$?_-" // Non-alphanumeric
};
using RandomGenerator rand = new RandomGenerator();
List<char> chars = new List<char>();
if (opts.RequireUppercase)
chars.Insert(rand.Next(0, chars.Count),
randomChars[0][rand.Next(0, randomChars[0].Length)]);
if (opts.RequireLowercase)
chars.Insert(rand.Next(0, chars.Count),
randomChars[1][rand.Next(0, randomChars[1].Length)]);
if (opts.RequireDigit)
chars.Insert(rand.Next(0, chars.Count),
randomChars[2][rand.Next(0, randomChars[2].Length)]);
if (opts.RequireNonAlphanumeric)
chars.Insert(rand.Next(0, chars.Count),
randomChars[3][rand.Next(0, randomChars[3].Length)]);
for (int i = chars.Count; i < opts.RequiredLength
|| chars.Distinct().Count() < opts.RequiredUniqueChars; i++)
{
string rcs = randomChars[rand.Next(0, randomChars.Length)];
chars.Insert(rand.Next(0, chars.Count),
rcs[rand.Next(0, rcs.Length)]);
}
return new string(chars.ToArray());
}
Run Code Online (Sandbox Code Playgroud)
jws*_*jws 12
在 .NET 6 中,RNGCryptoServiceProvider之前答案中使用的内容现已过时。
对于加密随机数,只需使用RandomNumberGenerator静态方法,例如:
var byteArray = RandomNumberGenerator.GetBytes(24);
Run Code Online (Sandbox Code Playgroud)
您可以查看来自https://gist.github.com/1017834的 CryptoRandom类,这是Stephen Toub和Shawn Farkas的原始版本.在这个类中,他们实现了几个似乎以加密方式保护的随机生成器.
我在我的项目中使用了以下版本进行随机int生成.
public class RandomGenerator
{
readonly RNGCryptoServiceProvider csp;
public RandomGenerator()
{
csp = new RNGCryptoServiceProvider();
}
public int Next(int minValue, int maxExclusiveValue)
{
if (minValue >= maxExclusiveValue)
throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue");
long diff = (long)maxExclusiveValue - minValue;
long upperBound = uint.MaxValue / diff * diff;
uint ui;
do
{
ui = GetRandomUInt();
} while (ui >= upperBound);
return (int)(minValue + (ui % diff));
}
private uint GetRandomUInt()
{
var randomBytes = GenerateRandomBytes(sizeof(uint));
return BitConverter.ToUInt32(randomBytes, 0);
}
private byte[] GenerateRandomBytes(int bytesNumber)
{
byte[] buffer = new byte[bytesNumber];
csp.GetBytes(buffer);
return buffer;
}
}
Run Code Online (Sandbox Code Playgroud)
从你的代码中我可以看到,你想从一个区间中获取一个随机整数。
.NET 中包含一个新的加密随机数生成器(自 Core 3.0、Core 3.1、.NET 5、.NET 6、.NET 7 RC 1 和 .NET Standard 2.1 版本起)。
正如jws 提到的,以前使用的类 RNGCryptoServiceProvider 已被弃用。
您可以使用这个辅助方法。它还可以轻松替换不安全的 System.Random 的 .Next 方法:
/// <summary>
/// Generate a secure random number
/// </summary>
/// <param name="fromInclusive">Random number interval (min, including this number)</param>
/// <param name="toExclusive">Random number interval (max, excluding this number)</param>
/// <returns></returns>
private int RandomNumber(int fromInclusive, int toExclusive)
=> System.Security.Cryptography.RandomNumberGenerator.GetInt32(fromInclusive, toExclusive);
Run Code Online (Sandbox Code Playgroud)
要模拟掷骰子,请使用它
var getNumber = RandomNumber(1, 7); // including 1, excluding 7 => 1 .. 6
Run Code Online (Sandbox Code Playgroud)
如果您更喜欢使用 .Next() 的“旧方式”,您可以创建一个像这样的类(请注意,不是种子,而是 fromInclusive 和 toExclusive 参数):
public class SecureRandom
{
private int fromInc, toExcl;
public SecureRandom(int toExclusive = 2) => Init(0, toExclusive);
public SecureRandom(int fromInclusive, int toExclusive)
=> Init(fromInclusive, toExclusive);
private void Init(int fromInclusive, int toExclusive)
{
fromInc = fromInclusive; toExcl = toExclusive;
}
public int Next() => RandomNumber(fromInc, toExcl);
public static int RandomNumber(int fromInclusive, int toExclusive)
=> System.Security.Cryptography.RandomNumberGenerator.GetInt32(fromInclusive, toExclusive);
}
Run Code Online (Sandbox Code Playgroud)
例子:
// always the same interval in a loop:
var rnd = new SecureRandom(1, 7);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(rnd.Next()); // roll the dice 100 times
}
// alternative usage (without creating an instance):
Console.WriteLine(SecureRandom.RandomNumber(1, 7));
Run Code Online (Sandbox Code Playgroud)
笔记:
此版本不再需要从加密类获取实例 - 您只需调用它即可获取下一个随机数。
还有一个重载,GetInt32(...)它采用一个参数作为最大独占值,从最小值 0 开始。如果您需要,请随时更新代码并为静态函数创建另一个重载方法RandomNumber。
| 归档时间: |
|
| 查看次数: |
5586 次 |
| 最近记录: |