Я хотел бы генерировать длинный UUID - что-то как сеансовый ключ, используемый Gmail. Это должны быть по крайней мере 256 символов и не больше, чем 512. Это может содержать все алфавитно-цифровые символы и несколько специальных символов (те ниже функциональных клавиш на клавиатуре). Это уже было сделано или является там образцом там?
C++ или C#
Обновление: GUID недостаточно. Мы уже видели коллизии и потребность исправить это. 512 макс. на данный момент, потому что это будет препятствовать тому, чтобы мы изменили материал, который был уже поставлен.
Обновление 2: Для парней, которые настаивают о том, насколько уникальный GUID, если кто-то хочет предположить Ваш следующий идентификатор сессии, они не должны вычислять комбинации в течение следующего 1 триллиона лет. Все, что они должны сделать, использовать, ограничивают фактор времени, и они будут сделаны в течение многих часов.
Согласно вашему обновлению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);
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < HOW_MUCH_YOU_WANT / 32; i++)
sb.Append(Guid.NewGuid().ToString("N"));
return sb.ToString();
но за что?
Если ваши идентификаторы GUID сталкиваются, могу ли я спросить, как вы их генерируете?
Астрономически маловероятно, что ИДЕНТИФИКАТОРы GUID столкнутся так, как они основаны на:
Вам придется запустить генерацию 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% будете иметь столкновение.
Проблема здесь , почему , а не как . Идентификатор сеанса больше , чем GUID, бесполезен, потому что он уже достаточно велик, чтобы предотвратить атаки методом грубой силы.
Если вас беспокоит предсказание GUID, не беспокойтесь. В отличие от более ранних последовательных GUID, GUID V4 криптографически безопасны на основе RC4. Единственный известный мне эксплойт зависит от наличия полного доступа к внутреннему состоянию процесса, генерирующего значения, поэтому он никуда не приведет, если все, что у вас есть, - это частичная последовательность GUID.
Если вы параноик, сгенерируйте GUID, хешируйте его чем-то вроде SHA-1 и используйте это значение. Однако это пустая трата времени. Если вас беспокоит захват сеанса, вам следует обратить внимание на SSL, а не на это.
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, убедитесь, что отключена чувствительность к регистру.
Есть два действительно простых способа (C#):
1) Сгенерировать кучу гидов с помощью Guid.NewGuid().ToString("N"). каждый GUID будет длиной 32 символа, поэтому просто сгенерируйте 8 из них и объедините их, чтобы получить 256 символов.
2) Создайте постоянную строку (const string sChars = "abcdef") допустимых символов, которые вы хотели бы видеть в своем UID. Затем в цикле случайным образом выберите символы из этой строки, генерируя случайным образом число от 0 до длины строки допустимых символов (sChars), и объедините их в новую строку (используйте stringbuilder для повышения производительности, но и string тоже подойдет).
Вы можете попробовать Библиотеку Uuid boost. Она поддерживает множество генераторов, включая генератор случайных чисел, который может удовлетворить ваши потребности.
Я бы использовал какой-то хеш 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;
}