sharp-chat/SharpChatCommon/RNG.cs

83 lines
2.4 KiB
C#

using System;
using System.Buffers;
using System.Security.Cryptography;
namespace SharpChat {
public static class RNG {
public const string CHARS = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
private static Random NormalRandom { get; } = new();
private static RandomNumberGenerator SecureRandom { get; } = RandomNumberGenerator.Create();
public static int Next() {
return NormalRandom.Next();
}
public static int Next(int max) {
return NormalRandom.Next(max);
}
public static int Next(int min, int max) {
return NormalRandom.Next(min, max);
}
public static void NextBytes(byte[] buffer) {
SecureRandom.GetBytes(buffer);
}
public static int SecureNext() {
return SecureNext(int.MaxValue);
}
public static int SecureNext(int max) {
return SecureNext(0, max);
}
public static int SecureNext(int min, int max) {
--max;
if(min == max)
return min;
uint umax = (uint)max - (uint)min;
uint num;
byte[] buffer = ArrayPool<byte>.Shared.Rent(4);
try {
SecureRandom.GetBytes(buffer);
num = BitConverter.ToUInt32(buffer);
if(umax != uint.MaxValue) {
++umax;
if((umax & (umax - 1)) != 0) {
uint limit = uint.MaxValue - (uint.MaxValue & umax) - 1;
while(num > limit) {
SecureRandom.GetBytes(buffer);
num = BitConverter.ToUInt32(buffer);
}
}
}
} finally {
ArrayPool<byte>.Shared.Return(buffer);
}
return (int)((num % umax) + min);
}
private static string RandomStringInternal(Func<int, int> next, int length) {
char[] str = new char[length];
for(int i = 0; i < length; ++i)
str[i] = CHARS[next(CHARS.Length)];
return new string(str);
}
public static string RandomString(int length) {
return RandomStringInternal(Next, length);
}
public static string SecureRandomString(int length) {
return RandomStringInternal(SecureNext, length);
}
}
}