Подтвердить что ты не робот

Как создать LONG guid?

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

С++ или С#

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

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

4b9b3361

Ответ 1

В соответствии с вашим обновлением2 вы правы в Гидах, которые могут быть использованы даже для ссылок 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);
}

EDIT Я знаю, что есть некоторая смещение, потому что allowedCharCount не равномерно делится на 255, вы можете избавиться от смещения, отбрасывающего и получающего новое случайное число, если оно приземлится в безмане остаток.

EDIT2 - это не гарантирует уникальность, вы можете хранить статический 64-битный (или более высокий, если необходимо) монотонный счетчик, закодировать его на base46 и иметь это первые 4-5 символов идентификатора.

UPDATE - теперь гарантировано быть уникальным

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

EDIT: я просто проверил тест, я хотел сообщить вам, что ToBase64String может возвращать не буквенно-цифровые символы (например, 1 кодировать до "AQAAAAAAAAA="), чтобы вы знали.

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

Отказываясь от Matt Dotson answer на этой странице, если вы так не волнуетесь о пространстве ключей, вы можете сделать это таким образом, и он будет работать намного быстрее.

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

Ответ 2

Если ваши 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% столкновением.

Ответ 3

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

но зачем?

Ответ 4

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

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

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

Ответ 5

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 символов).

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

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

Ответ 6

Есть два очень простых способа (С#):

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

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

Ответ 7

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

Ответ 8

Я бы использовал какой-то хэш 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;
}

Ответ 9

https://github.com/bigfatsea/SUID Простой уникальный идентификатор

Хотя это в Java, но может быть легко перенесен на любой другой язык. Вы можете ожидать дублирования идентификаторов на одном экземпляре 136 лет спустя, что достаточно хорошо для средних проектов.

Пример:

long id = SUID.id().get();