Как генерировать ДЛИННЫЙ гуид?

Я хотел бы генерировать длинный UUID - что-то как сеансовый ключ, используемый Gmail. Это должны быть по крайней мере 256 символов и не больше, чем 512. Это может содержать все алфавитно-цифровые символы и несколько специальных символов (те ниже функциональных клавиш на клавиатуре). Это уже было сделано или является там образцом там?

C++ или C#

Обновление: GUID недостаточно. Мы уже видели коллизии и потребность исправить это. 512 макс. на данный момент, потому что это будет препятствовать тому, чтобы мы изменили материал, который был уже поставлен.

Обновление 2: Для парней, которые настаивают о том, насколько уникальный GUID, если кто-то хочет предположить Ваш следующий идентификатор сессии, они не должны вычислять комбинации в течение следующего 1 триллиона лет. Все, что они должны сделать, использовать, ограничивают фактор времени, и они будут сделаны в течение многих часов.

14
задан Cœur 5 March 2017 в 14:11
поделиться

8 ответов

Согласно вашему обновлению2 вы правы в отношении Guids, предсказуемы, даже если msdn ссылается на это. вот метод, в котором для создания идентификатора используется мощный генератор случайных чисел.

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);
}

РЕДАКТИРОВАТЬ Я знаю, что существует некоторая предвзятость, потому что allowedCharCount не делится на 255 без остатка, вы можете избавиться от предвзятости, отбросив и получив новое случайное число, если оно попадет в нейтральную зону. от остатка.

РЕДАКТИРОВАТЬ2 - Уникальность этого параметра не гарантируется, вы можете использовать статический 64-битный (или выше, если необходимо) монотонный счетчик, закодировать его в base46 и сделать так, чтобы это были первые 4-5 символов идентификатора.

ОБНОВЛЕНИЕ - теперь уникальность гарантирована.

ОБНОВЛЕНИЕ 2: алгоритм стал медленнее, но устранено смещение.

РЕДАКТИРОВАТЬ: Я только что провел тест, я хотел сообщить вам, что ToBase64String может возвращать не буквенно-цифровые символы (например, 1 кодирует «AQAAAAAAAAA =» ), чтобы вы знали.

Новая версия:

Взяв из ответа Мэтта Дотсона на этой странице, если вас не так беспокоит пространство клавиш, вы можете сделать это таким образом, и он будет работать НАМНОГО быстрее.

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);
}
13
ответ дан 1 December 2019 в 05:55
поделиться
StringBuilder sb = new StringBuilder();
for (int i = 0; i < HOW_MUCH_YOU_WANT / 32; i++)
   sb.Append(Guid.NewGuid().ToString("N"));
return sb.ToString();

но за что?

10
ответ дан 1 December 2019 в 05:55
поделиться

Если ваши идентификаторы GUID сталкиваются, могу ли я спросить, как вы их генерируете?

Астрономически маловероятно, что ИДЕНТИФИКАТОРы GUID столкнутся так, как они основаны на:

  • 60 бит - метка времени во время генерации
  • 48 бит - идентификатор компьютера
  • 14 бит - уникальный идентификатор
  • 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));
}

Вы можете видеть, что он возвращает int, поэтому, если у вас более 2^32 «GUID» в хэш-версии,Вы на 100% будете иметь столкновение.

28
ответ дан 1 December 2019 в 05:55
поделиться

Проблема здесь , почему , а не как . Идентификатор сеанса больше , чем GUID, бесполезен, потому что он уже достаточно велик, чтобы предотвратить атаки методом грубой силы.

Если вас беспокоит предсказание GUID, не беспокойтесь. В отличие от более ранних последовательных GUID, GUID V4 криптографически безопасны на основе RC4. Единственный известный мне эксплойт зависит от наличия полного доступа к внутреннему состоянию процесса, генерирующего значения, поэтому он никуда не приведет, если все, что у вас есть, - это частичная последовательность GUID.

Если вы параноик, сгенерируйте GUID, хешируйте его чем-то вроде SHA-1 и используйте это значение. Однако это пустая трата времени. Если вас беспокоит захват сеанса, вам следует обратить внимание на SSL, а не на это.

8
ответ дан 1 December 2019 в 05:55
поделиться
byte[] random = new Byte[384];

//RNGCryptoServiceProvider is an implementation of a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random);
var sessionId = Convert.ToBase64String(random);

Вы можете заменить "/" и "=" из кодировки base64 на любые специальные символы, приемлемые для вас.

Кодировка base64 создает строку, которая на 4/3 больше, чем массив байтов (следовательно, 384 байта должны дать 512 символов).

Это дает на порядок больше значений, чем кодировка base16 (hex). 512^16 против 512^64

Также, если вы собираетесь использовать их в sql server, убедитесь, что отключена чувствительность к регистру.

3
ответ дан 1 December 2019 в 05:55
поделиться

Есть два действительно простых способа (C#):

1) Сгенерировать кучу гидов с помощью Guid.NewGuid().ToString("N"). каждый GUID будет длиной 32 символа, поэтому просто сгенерируйте 8 из них и объедините их, чтобы получить 256 символов.

2) Создайте постоянную строку (const string sChars = "abcdef") допустимых символов, которые вы хотели бы видеть в своем UID. Затем в цикле случайным образом выберите символы из этой строки, генерируя случайным образом число от 0 до длины строки допустимых символов (sChars), и объедините их в новую строку (используйте stringbuilder для повышения производительности, но и string тоже подойдет).

1
ответ дан 1 December 2019 в 05:55
поделиться

Вы можете попробовать Библиотеку Uuid boost. Она поддерживает множество генераторов, включая генератор случайных чисел, который может удовлетворить ваши потребности.

1
ответ дан 1 December 2019 в 05:55
поделиться

Я бы использовал какой-то хеш std :: time (), вероятно, sha512. ex (с использованием crypto ++ для кодировки sha hash + base64).

#include <iostream>
#include <sstream>
#include <ctime>
#include <crypto++/sha.h>
#include <crypto++/base64.h>

int main() {
    std::string digest;
    std::stringstream ss("");
    ss << std::time(NULL);

    // borrowed from http://www.cryptopp.com/fom-serve/cache/50.html
    CryptoPP::SHA512 hash;
    CryptoPP::StringSource foo(ss.str(), true,
        new CryptoPP::HashFilter(hash,
           new CryptoPP::Base64Encoder(
               new CryptoPP::StringSink(digest))));
    std::cout << digest << std::endl;

    return 0;
}
0
ответ дан 1 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: