web-dev-qa-db-ja.com

C#乱数ジェネレータを安全にシードする

C#でRNGを安全にシードするための最良の方法を見つけようとしています。

私が現在使用しているクラスはRandomクラスです

https://msdn.Microsoft.com/en-us/library/system.random(v = vs.110).aspx#Same

ドキュメントを調べた後、Int32を使用してシードすることができますが、これを想定する方法が間違っている可能性があります。Int32は、推奨されるエントロピーの128ビットまたは256ビットよりもはるかに少ない32ビットのエントロピーしかありません。

誰かがより良いC#RNGを知っているか、エントロピーの128ビットでそれをプロパティして安全にシードする方法を知っていますか?何も見つかりませんでした

助けてくれてありがとう。

編集

私は、さまざまなマシンで繰り返し使用できる乱数を安全に生成しようとしています。基本的に私は、ハッシュ値またはそれに似たものをシードできるCSRNGを見つけようとしています。そのソフトウェアをそのハッシュをシードとして別のマシンで実行すると、同じ数値が生成されます。

4
CBaker

大部分は、これは必要なランダム出力の量に依存します。すでに128バイトまたは256バイトのランダムデータがシードされているとおっしゃっていますが、System.Randomでは十分ではないので、かなり多くのことを想定しています。

このデザインパターン全体が危険に満ちているので、オプションを勧めるのをためらっています。 CSPRNGがどれほど優れていて、シードの強度と長さがどれほど長くても、小さな間違いによってシステムが絶望的に​​壊れる可能性があります。これはおそらくあなたがRNGCryptoServiceProviderをシードする理由の1つですできませんひどいアプリケーションでそれを壊すのを防ぐためです。

そうは言っても、それを必要とするシステムがあり、それが安全に設計および実装されていると確信している場合、1つのアプローチとして、AESベースのCSPRNGを構築することができます。 AESの出力はランダムで予測不可能であるため、妥当な制約内で安全に使用して乱数を生成できます。ここで、キー(128、192、または256ビット)がシード値として効果的に使用され、カウンターを暗号化します。暗号文はランダムストリームです。

これはかなり一般的な構造なので、このようなものを構築する方法についてはかなりの情報があります。もちろん、C#はAESをサポートしているため、必要なプリミティブを用意できます。ただし、実装が正しくても、攻撃者がそれを予測できるシナリオがあり、いつでも制御可能である場合、それはランダムではないので、使用方法を設計する方法について非常に注意深くする必要があります。保護する必要があるシナリオである再利用可能なシード値。

0
Xander

.Netで安全な乱数を生成するには、system.security.cryptography.rngcryptoserviceproviderではなくsystem.randomを使用する必要があります

そのドキュメントはここにあります:

https://msdn.Microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider(v = vs.110).aspx

Link rotの場合、Microsoftがそのリンクで提供するC#サンプルを次に示します。ランダム生成はGetBytesメソッドを使用して行われます。

//The following sample uses the Cryptography class to simulate the roll of a dice.

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

class RNGCSP
{
    private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
    // Main method.
    public static void Main()
    {
        const int totalRolls = 25000;
        int[] results = new int[6];

        // Roll the dice 25000 times and display
        // the results to the console.
        for (int x = 0; x < totalRolls; x++)
        {
            byte roll = RollDice((byte)results.Length);
            results[roll - 1]++;
        }
        for (int i = 0; i < results.Length; ++i)
        {
            Console.WriteLine("{0}: {1} ({2:p1})", i + 1, results[i], (double)results[i] / (double)totalRolls);
        }
        rngCsp.Dispose();
        Console.ReadLine();
    }

    // This method simulates a roll of the dice. The input parameter is the
    // number of sides of the dice.

    public static byte RollDice(byte numberSides)
    {
        if (numberSides <= 0)
            throw new ArgumentOutOfRangeException("numberSides");

        // Create a byte array to hold the random value.
        byte[] randomNumber = new byte[1];
        do
        {
            // Fill the array with a random value.
            rngCsp.GetBytes(randomNumber);
        }
        while (!IsFairRoll(randomNumber[0], numberSides));
        // Return the random number mod the number
        // of sides.  The possible values are zero-
        // based, so we add one.
        return (byte)((randomNumber[0] % numberSides) + 1);
    }

    private static bool IsFairRoll(byte roll, byte numSides)
    {
        // There are MaxValue / numSides full sets of numbers that can come up
        // in a single byte.  For instance, if we have a 6 sided die, there are
        // 42 full sets of 1-6 that come up.  The 43rd set is incomplete.
        int fullSetsOfValues = Byte.MaxValue / numSides;

        // If the roll is within this range of fair values, then we let it continue.
        // In the 6 sided die case, a roll between 0 and 251 is allowed.  (We use
        // < rather than <= since the = portion allows through an extra 0 value).
        // 252 through 255 would provide an extra 0, 1, 2, 3 so they are not fair
        // to use.
        return roll < numSides * fullSetsOfValues;
    }
}
0
Mike Goodwin