3

I need to generate strings that have an extremely high probability of being unique on all machines that they're generated on, and be different every time the code is run as well. The probability of being unique doesn't have to be 100 percent, and this is not security related, only the uniqueness matters (use case is seeding large state non-crypto PRNGs).

My current idea is to SHA512 hash the network adapter info, including adapter statistics, the computer name, process ID, computer up time in ticks and UTC current time in ticks, and convert this to a 64 character base 64 Unicode string.

Seems sound, but are there any better, as in .net functions for example, ways to do this?

Working code:

using System;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Text;

static class UniqueString
{
    private static SHA512 sha = SHA512.Create();

    public static string Gen()
    {
        NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
        StringBuilder uniqueString = new StringBuilder();

        foreach (NetworkInterface adapter in adapters)
        {
            IPInterfaceStatistics stats = adapter.GetIPStatistics();

            uniqueString.AppendFormat("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} ",
                adapter.Description,
                adapter.Id,
                adapter.Name,
                adapter.Speed,
                adapter.GetPhysicalAddress(),
                adapter.NetworkInterfaceType,

                stats.BytesReceived,
                stats.BytesSent,
                stats.IncomingPacketsDiscarded,
                stats.IncomingPacketsWithErrors,
                stats.IncomingUnknownProtocolPackets,
                stats.NonUnicastPacketsReceived,
                stats.NonUnicastPacketsSent,
                stats.OutgoingPacketsDiscarded,
                stats.OutgoingPacketsWithErrors,
                stats.OutputQueueLength,
                stats.UnicastPacketsReceived,
                stats.UnicastPacketsSent);
        }

        uniqueString.AppendFormat("{0} {1} {2} {3}",
            Environment.MachineName,
            Process.GetCurrentProcess().Id,
            Environment.TickCount.ToString(),
            DateTime.UtcNow.Ticks);

        return Convert.ToBase64String(sha.ComputeHash(Encoding.Unicode.GetBytes(uniqueString.ToString())), 0, 48);
    }
}
Thorham
  • 447
  • 3
  • 11
  • 15
    `Guid.NewGuid()`? – Dave Jun 14 '18 at 22:39
  • Thought about that, but what's the probability of this being unique to the machine? – Thorham Jun 14 '18 at 22:40
  • 2
    Extremely high. – Sach Jun 14 '18 at 22:41
  • https://stackoverflow.com/questions/1705008/simple-proof-that-guid-is-not-unique – Sach Jun 14 '18 at 22:42
  • I imagine you need to re-use this value over multiple executions, otherwise you could just use `Guid.NewGuid()`. You need to generate something in the quintillions of GUIDs per second for there to be a risk of a collision in your lifetime, or something ludicrous like that. – Eric Sondergard Jun 14 '18 at 22:42
  • 3
    Here is a great answer about GUIDs and the chance of a clash https://stackoverflow.com/a/2977648/6915929 – Dave Jun 14 '18 at 22:43
  • `Guid.NewGuid()` will be unique even on a "single" machine if ran multiple times. – Jan Paolo Go Jun 14 '18 at 22:53
  • To be clear on this: The uniqueness refers to not being the same on different computers as well. – Thorham Jun 14 '18 at 22:53
  • 2
    Do not use GUIDs for anything other than generating a unique identifier. Guids are not guaranteed to be a good source of randomness. **If you need a good source of randomness then use a class specifically designed to solve that problem** rather than using a Guid as a proxy for solving that problem! – Eric Lippert Jun 14 '18 at 22:54
  • This is similar to generating a secure GUID technique: https://stackoverflow.com/questions/37170388/create-a-cryptographically-secure-random-guid-in-net – Panos Roditakis Mar 04 '21 at 18:38

1 Answers1

11

I need to generate strings that have an extremely high probability of being unique on all machines that they're generated on, and be different every time the code is run as well.

Let me start with a warning:

People will immediately tell you to use a GUID, which is, as the name suggests, a globally unique identifier. Type four guids are generated randomly.

However, I would push back on using a GUID as a source of randomness. GUIDs guarantee uniqueness and that is all that they are documented as guaranteeing. In practice, yes, a type four GUID is effectively a random 122 bit number generated by a non-crypto-strength PRNG. If you use a GUID as your random string, you will be fine. But I would not personally use a GUID off-label; I use them to generate a unique identifier, no more, no less. There are better ways to solve your problem.

For more on the uses and abuses of GUIDs, see https://ericlippert.com/tag/guids/

Seems sound, but are there any better, as in .net functions for example, ways to do this?

The correct way to do this is to use RNGCryptoServiceProvider to generate as many crypto-strength random bits as you need to feel comfortable that your identifier is unique, and then use that as your seed.

Your system seems plausible, but why on earth would you implement it yourself, when experts who work for Microsoft have already created a system that seeds a crypto-strength random number generator with plenty of entropy? Don't re-invent the wheel here.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Just want to commend the high-effort answer here, it does more than just answer the question, it addresses the "question behind the question" of "how do I generate guaranteed to be truly unique across the universe in .NET" – Eric Sondergard Jun 14 '18 at 22:59
  • @Eric Lippert - The reason I implemented something myself is because I don't want do depend on potentially depleteable entropy pools. If you don't have to use this, don't use it, but perhaps this concern is unfounded. – Thorham Jun 14 '18 at 23:03
  • 7
    @Thorham: RNGCryptoServiceProvider's output is **not distinguishable by any known statistical test from a genuinely random source of bits**. If you think you can do a better job of finding entropy than **crypto experts who work on internals of Windows** then you go right ahead, but the fact that you are asking this question of strangers on the internet maybe tells me that you are not better at it than those experts. Use their work. It's high quality. – Eric Lippert Jun 14 '18 at 23:06
  • @Eric Lippert - I'm certainly no crypto expert (far from it), and my intention wasn't to write something that has crypto level strength (it's not required at all for the use case). I've just read something about depletable entropy pools on other systems, and since I want the code to be usable with Mono as well as .Net I thought it was a good idea to write it myself so that it doesn't depend on any system specific things. – Thorham Jun 14 '18 at 23:13
  • @Thorham: Mono has supported RNGCryptoServiceProvider for over ten years. – Eric Lippert Jun 14 '18 at 23:15
  • @Eric Lippert - Yes, I know it's available, but my concerns are related to entropy pools being potentially depletable on some systems (Linux for example). Seeing how I don't need crypto strength, it seemed like a good idea to implement something myself rather than using a potentially limited recource while it's not needed. – Thorham Jun 14 '18 at 23:21