anand
anand

Reputation: 1579

Generating Unique number through Cryptography

I am using Visual Studio 2013, iis-8.5, .net 4.5.1
In my project, i want to create 8 digit unique number which should be separated by a 'hypen' in the middle and with prefix "MNOP-". The generated 8 digit should inherit the Cryptography class.
My code

var bytes = new byte[4];
var rng = RandomNumberGenerator.Create();
rng.GetBytes(bytes);
int random = BitConverter.ToInt32(bytes, 0) % 100000000;
var data = "ABCD-" + random.ToString("####-####");

I created 10000 value by 'for loop', but some 'random variable' return negative value
Thanks in advance.

Upvotes: 2

Views: 337

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 94058

There are three things you can do:

  1. generate a random value (decimal digit by decimal digit) and check if you created it before, then store it into a list of pre-generated numbers;
  2. create a 400 to 800 MB table and shuffle it, then store it on disk and use an offset into the table;
  3. create a key and use it for a cipher (a PRP) that uses the exact same output as the input, and use a counter, basically implementing Format Preserving Encryption.

You should not just use a random number generator as the chance of collisions quickly increases with the amount of numbers generated. This is because of the Birthday problem.

This also means that solution 1) is not fit if you want to generate a lot of numbers, as it may stall. Imagine that you've got only one available number left, you'd have a 400 MB table and it is trying for that one 4 byte entry that's left. The other options require you to store a table and an offset or a key and an counter respectively.


Your current generation method is unbalanced as it generates lower numbers more easily than positive numbers. Furthermore, you should reset the most significant bit because ToInt32 returns the signed, two complement value, and % is the remainder operator, not the modulus operator.


OK, for this time only, some C# code, to celebrate my bronze badge for the platform:

namespace StackOverflow
{
    class RandomIDGenerator
    {
        private const string FORMAT = "ABCD-####-####";
        private const string TEST_FORMAT = "ABCD-###";


        private RandomNumberGenerator rng = RandomNumberGenerator.Create();
        private byte[] b = new byte[1];
        private SortedSet<string> previousIDs = new SortedSet<string>();

        private char GenerateRandomDigit()
        {
            int x;
            do
            {
                rng.GetBytes(b);
                x = b[0] & 0xFF;
            } while (x >= 250);
            int y = x % 10;
            return (char) ('0' + y);
        }

        private String GenerateRandomID()
        {
            StringBuilder sb = new StringBuilder(TEST_FORMAT);
            for (int i = 0; i < sb.Length; i++)
            {
                if (sb[i] == '#')
                {
                    sb[i] = GenerateRandomDigit();
                }
            }
            return sb.ToString();
        }

        public String GenerateUniqueRandomID()
        {
            string id;
            do
            {
                id = GenerateRandomID();
            }
            while (previousIDs.Contains(id));
            previousIDs.Add(id);
            return id;
        }

        public static void Main(String[] args)
        {
            RandomIDGenerator gen = new RandomIDGenerator();
            for (int i = 0; i < 500; i++)
            {
                Console.WriteLine(gen.GenerateUniqueRandomID());
            }

            Console.WriteLine("Put breakpoint here...");

            foreach (string id in gen.previousIDs)
            {
                Console.WriteLine(id);
            }

            Console.WriteLine(gen.previousIDs.Count);
            Console.WriteLine("Put breakpoint here...");
        }
    }
}

Upvotes: 2

Related Questions