C# 生成与计算机唯一相关的字符串

3
我需要生成一些字符串,这些字符串在生成的所有机器上都有极高的唯一性概率,并且每次运行代码时都不同。唯一性的概率不必达到100%,这与安全无关,只有唯一性很重要(用例是种子大状态非加密PRNG)。
我的当前想法是SHA512哈希网络适配器信息,包括适配器统计信息、计算机名称、进程ID、计算机正常运行时间和UTC当前时间的刻度,并将其转换为64个字符的基于64的Unicode字符串。
看起来很合理,但是否有更好的方法,例如使用.NET函数?
工作代码:
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);
    }
}

15
Guid.NewGuid() 是一个在.NET开发中的方法,用于生成唯一标识符(GUID)。 - Dave
2
极高。 - Sach
3
这里有一个关于GUID和冲突概率的很好的答案:https://dev59.com/aHA85IYBdhLWcg3wBO3h#2977648 - Dave
2
不要将GUID用于除生成唯一标识符之外的任何其他用途。 GUID不能保证是良好的随机源。如果您需要一个良好的随机源,则应使用专门设计解决该问题的类,而不是使用GUID作为代理来解决该问题! - Eric Lippert
这类似于生成一个安全的 GUID 技术:https://dev59.com/p1oU5IYBdhLWcg3wu4ni - Panos Roditakis
显示剩余5条评论
1个回答

11
我需要生成一些字符串,在所有生成它们的机器上具有极高的独特性概率,并且每次运行代码时都要不同。请注意:人们会立即建议您使用GUID,这是全局唯一标识符,类型四的GUID是随机生成的。然而,我不推荐使用GUID作为随机源。GUID保证唯一性,这就是所有记录在案的保证。实际上,是的,类型四的GUID是由非加密强度PRNG生成的随机122位数。如果您将GUID用作随机字符串,则没问题。但我个人不会将GUID用于其他目的;我使用它们来生成唯一标识符,仅此而已。有更好的方法来解决您的问题。关于GUID的用途和滥用,请参见https://ericlippert.com/tag/guids/ 正确的做法是使用RNGCryptoServiceProvider生成尽可能多的加密强度的随机比特数,以便您感到舒适,您的标识符是唯一的,然后将其用作种子。
你的系统看起来很可行,但为什么要自己实现它,当微软的专家已经创建了一个用大量熵种子加密强度随机数生成器的系统?不要重复造轮子。

1
只想赞扬这里高度努力的回答,它不仅回答了问题,还解决了“问题背后的问题”,即“如何在.NET中生成保证真正独一无二的值”。 - Eric Sondergard
@Eric Lippert - 我之所以自己实现这个功能,是因为我不想依赖可能会枯竭的熵池。如果你不必使用它,请不要使用它,但也许这种担忧是没有根据的。 - Thorham
7
@Thorham说: RNGCryptoServiceProvider的输出结果与真正的随机比特源经过任何已知的统计测试都是无法区分的。如果你认为你能够比 Windows 内部的加密专家更好地获取熵,那么你可以自己进行尝试,但是你把这个问题问陌生人的事实可能告诉我你并不比这些专家更擅长。使用他们的工作,它们具有高质量。 - Eric Lippert
@Eric Lippert - 我绝对不是加密专家(离那还很远),我的意图也不是编写具有加密级别强度的东西(这在使用案例中根本不需要)。我只是在其他系统上读到了一些关于可耗尽熵池的内容,由于我希望代码能够在Mono和.Net上使用,所以我认为自己编写它是一个好主意,这样它就不依赖于任何特定于系统的东西。 - Thorham
@Thorham:Mono已经支持RNGCryptoServiceProvider超过十年了。 - Eric Lippert
@Eric Lippert - 是的,我知道它是可用的,但我的担忧与熵池在某些系统上(例如Linux)可能会被耗尽有关。考虑到我不需要加密强度,实现自己的东西似乎是一个好主意,而不是在不需要时使用潜在受限资源。 - Thorham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接