4

I'm trying to figure out the best way to securely seed a rng in C#.

The class I am currently using is the Random class

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

After going through the documentation you can seed it using an Int32, however and I may be wrong in how i assume this, an Int32 would essentially have only 32 bits of entropy which is much less than the recommended 128 or 256 bits of entropy.

Does anybody know of a better C# RNG or how to property and securely seed it with 128 bits on entropy? I haven't been able to find anything

Thanks for all the help.

EDIT

I'm trying to securely generate random numbers that can repeatable across different machines. Basically I'm trying to find a CSRNG that can be seeded with a hash value or something similar and if I ran that piece of software on a different machine with that hash as the seed, it would produce the same numbers.

4
  • The random function you reference us bit secure no matter the seed. It is designed 5i be performant, not secure Jul 18, 2016 at 23:26
  • 4
    What @NeilSmithline means is is not and not us bit. Presumably typing on a mobile device. Similarly 5i --> to... :-)
    – Jedi
    Jul 19, 2016 at 4:22
  • Reading through your question I got a feeling you are trying to solve a different problem (maybe key management?). Could you please clarify what for you need to generated same secure random numbers on different machines?
    – bayo
    Jul 19, 2016 at 7:09
  • 1
    What are you using the generator for - why do you need randomness? Note that "true" randomness is generally actually useless (since it's not repeatable), hence seeding a pseudo random generator like you're doing, but both how you generate the seed and how you generate the "next" number are extremely important. Note that, very specifically, the Random class is not guaranteed to generate the same output on different .NET versions, which might be a problem for you. Jul 19, 2016 at 12:38

2 Answers 2

0

To a large degree, this depends on how much random output you need. I'm assuming quite a lot, since you're talking about already having 128 or 256 bytes of random data to seed it with, and you are correct that System.Random is not good enough for this.

I'm hesitant to recommend options, because this entire design pattern is fraught with danger. Small mistakes could leave you with a hopelessly broken system, regardless of how good the CSPRNG and how strong and long your seed is. This is probably one of the reasons you can't seed the RNGCryptoServiceProvider...To prevent people from breaking it with awful applications.

That said, if you have a system that requires it and you're confident it is securely designed and implemented, one approach you could take would be to build an AES based CSPRNG. The output of AES is random and unpredictable, so within reasonable constraints, you can securely use to generate random numbers, where the key (of 128, 192, or 256 bits) is effectively used as your seed value, you encrypt a counter, and the ciphertext is your random stream.

This is a fairly common construction, so there's quite a bit of information on how to build something like this, and of course C# supports AES so you have the primitives you need. Even if you get the implementation correct however, you have to be very very careful about how you design it to be used, because it ain't random if there's a scenario that allows an attacker to predict it, and anytime you have a controllable, re-usable seed value that is a scenario you have to protect against.

1
  • This is a good answer. Ill look in to using AES to generate random numbers. Thank you
    – CBaker
    Jul 19, 2016 at 14:22
0

To generate a secure random number in .Net you should use system.security.cryptography.rngcryptoserviceprovider instead of system.random

The documentation for it is here:

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

In case of link rot, here is the C# sample that Microsoft provide on that link. The random generation is done using the GetBytes method.

//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;
    }
}
5
  • 2
    To my understand, you can't seed that
    – CBaker
    Jul 18, 2016 at 17:02
  • @CBaker - what is it that you are trying to accomplish? If you are just looking for a CSPRNG in C#, I think that Mike has answered that. If you are looking for something else or in addition to a CSPRNG, can you edit your question to elaborate? Jul 18, 2016 at 22:11
  • @NeilSmithline Thanks for the comment. I updated the question a little bit. How I'm approaching it now is using the Random class that can be seeded with an Int32, but i wouldn't consider that secure due to the lack of entropy.
    – CBaker
    Jul 18, 2016 at 23:07
  • It would not be secure even if you could send it with more entropy. You seem to be under the misunderstanding that all PRNGs are equivalent. They are not. You need a random number generator specifically designed to be cryptographically secure, a CSPRNG.
    – Ben
    Jul 19, 2016 at 3:24
  • Using rngcryptoserviceprovider for anything other than seeding, keys or similar small amounts of data, seems like a terrible idea.
    – Thorham
    Jul 13, 2022 at 7:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .