如何生成LONG guid?

Ron*_*Ron 14 c# c++ algorithm

我想生成一个很长的UUID - 类似于gmail使用的会话密钥.它应至少为256个字符且不超过512个字符.它可以包含所有字母数字字符和一些特殊字符(键盘上功能键下方的字符).这已经完成了还是有样品?

C++或C#

更新:GUID是不够的.我们已经看到了碰撞,需要解决这个问题.512是迄今为止的最大值,因为它会阻止我们更改已经发货的东西.

更新2:对于坚持GUID独特性的人,如果有人想猜测你的下一个会话ID,他们就不必计算下一个万亿年的组合.他们所要做的只是限制时间因素,它们将在数小时内完成.

Joh*_*sch 28

如果您的GUID发生碰撞,请问您是如何生成它们的?

GUID会因为基于以下原因而发生碰撞,这在天文学上是不可能的:

  • 60位 - 生成期间的时间戳
  • 48位 - 计算机标识符
  • 14位 - 唯一ID
  • 6位是固定的

您必须在同一台机器上运行GUID生成约50次,以便有50%的碰撞几率.请注意,瞬间测量到纳秒.

更新:

根据您的评论"将GUID放入哈希表"...该GetHashCode()方法是导致冲突的原因,而不是GUID:

public override int GetHashCode()
{
    return ((this._a ^ ((this._b << 0x10) | ((ushort) this._c))) ^ ((this._f << 0x18) | this._k));
}
Run Code Online (Sandbox Code Playgroud)

你可以看到它返回一个int,所以如果哈希表中有超过2 ^ 32个"GUID",那么你将100%发生冲突.

  • +1可以很好地了解哈希表. (4认同)
  • @Ron:你总是可以让SQL给你GUID. (3认同)

Sco*_*ain 13

根据你的更新2你是正确的Guids是可预测的甚至msdn引用.这是一种使用强大的随机数生成器来创建ID的方法.

static long counter; //store and load the counter from persistent storage every time the program loads or closes.

public static string CreateRandomString(int length)
{
    long count = System.Threading.Interlocked.Increment(ref counter);
    int PasswordLength = length;
    String _allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789";
    Byte[] randomBytes = new Byte[PasswordLength];
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    rng.GetBytes(randomBytes);
    char[] chars = new char[PasswordLength];
    int allowedCharCount = _allowedChars.Length;
    for (int i = 0; i < PasswordLength; i++)
    {
        while(randomBytes[i] > byte.MaxValue - (byte.MaxValue % allowedCharCount))
        {
            byte[] tmp = new byte[1];
            rng.GetBytes(tmp);
            randomBytes[i] = tmp[0];
        }
        chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
    }
    byte[] buf = new byte[8];
    buf[0] = (byte) count;
    buf[1] = (byte) (count >> 8);
    buf[2] = (byte) (count >> 16);
    buf[3] = (byte) (count >> 24);
    buf[4] = (byte) (count >> 32);
    buf[5] = (byte) (count >> 40);
    buf[6] = (byte) (count >> 48);
    buf[7] = (byte) (count >> 56);
    return Convert.ToBase64String(buf) + new string(chars);
}
Run Code Online (Sandbox Code Playgroud)

编辑我知道有一些allowedCharCount偏见,因为不能被255整除,你可以摆脱偏离丢弃并获得一个新的随机数,如果它落在剩余的无人区.

EDIT2 - 这不保证是唯一的,您可以保持静态64位(或更高,如果需要)单调计数器将其编码为base46并且具有id的前4-5个字符.

更新 - 现在保证是独一无二的

更新2:算法现在更慢但删除了偏差.

编辑:我刚刚运行了一个测试,我想让你知道ToBase64String可以返回非字母数字字符(例如1个编码"AQAAAAAAAAA="),这样你就知道了.

新版本:

根据Matt Dotson在本页的回答,如果你不是那么担心键空间,你可以这样做,它会更快地运行.

public static string CreateRandomString(int length)
{
    length -= 12; //12 digits are the counter
    if (length <= 0)
        throw new ArgumentOutOfRangeException("length");
    long count = System.Threading.Interlocked.Increment(ref counter);
    Byte[] randomBytes = new Byte[length * 3 / 4];
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    rng.GetBytes(randomBytes);

    byte[] buf = new byte[8];
    buf[0] = (byte)count;
    buf[1] = (byte)(count >> 8);
    buf[2] = (byte)(count >> 16);
    buf[3] = (byte)(count >> 24);
    buf[4] = (byte)(count >> 32);
    buf[5] = (byte)(count >> 40);
    buf[6] = (byte)(count >> 48);
    buf[7] = (byte)(count >> 56);
    return Convert.ToBase64String(buf) + Convert.ToBase64String(randomBytes);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果他每天24小时,每年356天产生11,574个新的每秒钟身份(每天10亿),它将需要5050万年才能完成.我认为64位会好的. (4认同)

And*_*rey 10

StringBuilder sb = new StringBuilder();
for (int i = 0; i < HOW_MUCH_YOU_WANT / 32; i++)
   sb.Append(Guid.NewGuid().ToString("N"));
return sb.ToString();
Run Code Online (Sandbox Code Playgroud)

但是为了什么?


Ste*_*dit 8

这里的问题是为什么,而不是如何.会话ID 大于 GUID是没用的,因为它已经足够大,可以阻止暴力攻击.

如果您担心预测GUID,请不要.与早期的顺序GUID不同,V4 GUID基于RC4是加密安全的.我所知道的唯一漏洞取决于对生成值的进程的内部状态的完全访问权限,因此如果你拥有的是GUID的部分序列,它就无法到达任何地方.

如果您是偏执狂,请生成GUID,使用SHA-1等方法对其进行哈希处理,然后使用该值.但是,这是浪费时间.如果你担心会话劫持,你应该看看SSL,而不是这个.