2 つのパスワードを非常に迅速に生成すると、それらは同じティックで生成されます。
人間が読めるランダムなパスワードを生成したいだけの場合は、こちらをご覧ください。Random
がこの目的に適さない理由と、より適切な方法を知りたい場合は、読み進めてください。
最も簡単な方法は、デフォルトのコンストラクターを使用するRandom()
ことです。これにより、シード処理が行われます。
documentationを確認した後、デフォルトのコンストラクターは時間ベースのシードを使用するため、その使用で同じ問題が発生します。とにかく、このRandom
クラスは予測可能すぎて、安全なパスワード生成に使用できません。
もう少し強さを求めるなら、これでいいでしょう。
using System.Security.Cryptography;
static string GetPassword(int length = 13)
{
var rng = new RNGCryptoServiceProvider();
var buffer = new byte[length * sizeof(char)];
rng.GetNonZeroBytes(buffer);
return new string(Encoding.Unicode.GetChars(buffer));
}
ただし、人間が生成したパスワードを読み、記憶し、入力できるようにしたい場合は、可能な文字の範囲をもう少し制限する必要があります。
この部分を更新して、詳細で最新の偏りのない回答を提供しました。
出力を特定の文字セットに制限したい場合は、次のようにすることができます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
/// <summary>
/// Get a random password.
/// </summary>
/// <param name="valid">A list of valid password chars.</param>
/// <param name="length">The length of the password.</returns>
/// <returns>A random password.</returns>
public static string GetPassword(IList<char> valid, int length = 13)
{
return new string(GetRandomSelection(valid, length).ToArray());
}
/// <summary>
/// Gets a random selection from <paramref name="valid"/>.
/// </summary>
/// <typeparam name="T">The item type.</typeparam>
/// <param name="valid">List of valid possibilities.</param>
/// <param name="length">The length of the result sequence.</param>
/// <returns>A random sequence</returns>
private static IEnumerable<T> GetRandomSelection<T>(
IList<T> valid,
int length)
{
// The largest multiple of valid.Count less than ulong.MaxValue.
// This upper limit prevents bias in the results.
var max = ulong.MaxValue - (ulong.MaxValue % (ulong)valid.Count);
// A finite sequence of random ulongs.
var ulongs = RandomUInt64Sequence(max, length).Take(length);
// A sequence of indecies.
var indecies = ulongs.Select((u => (int)(u % (ulong)valid.Count)));
return indecies.Select(i => valid[i]);
}
/// <summary>
/// An infinite sequence of random <see cref="ulong"/>s.
/// </summary>
/// <param name="max">
/// The maximum inclusive <see cref="ulong"/> to return.
/// </param>
/// <param name="poolSize">
/// The size, in <see cref="ulong"/>s, of the pool used to
/// optimize <see cref="RNGCryptoServiceProvider"/> calls.
/// </param>
/// <returns>A random <see cref="ulong"/> sequence.</returns>
private static IEnumerable<ulong RandomUInt64Sequence(
ulong max = UInt64.MaxValue,
int poolSize = 100)
{
var rng = new RNGCryptoServiceProvider();
var pool = new byte[poolSize * sizeof(ulong)];
while (true)
{
rng.GetBytes(pool);
for (var i = 0; i < poolSize; i++)
{
var candidate = BitConvertor.ToUInt64(pool, i * sizeof(ulong));
if (candidate > max)
{
continue;
}
yield return candidate;
}
}
}
このコードは次のように使用できます。最初char
に、パスワードに含まれる有効な a のセットが必要です。
var validChars = new[] { 'A', 'B', 'C' };
説明のために 3 つchar
の s だけを含めましたが、実際にはもっと多くchar
の s を含める必要があります。次に、8 秒間のランダムなパスワードを生成するには、次のchar
呼び出しを行います。
var randomPassword = GetPassword(validChars, 8);
実際には、パスワードを少なくとも 13 秒にしたいでしょうchar
。