Как создать LONG guid?
Я хотел бы создать длинный UUID - что-то вроде ключа сеанса, используемого gmail. Он должен быть не менее 256 символов и не более 512. Он может содержать все буквенно-цифровые символы и несколько специальных символов (те, которые находятся под функциональными клавишами на клавиатуре). Это уже сделано или есть образец?
С++ или С#
Обновление. Недостаточно GUID. Мы уже видели столкновения и должны исправить это. 512 - это максимальная величина, потому что это не позволит нам изменить материал, который уже был отправлен.
Обновление 2: для парней, которые настаивают на том, насколько уникален GUID, если кто-то хочет угадать ваш следующий идентификатор сеанса, им не нужно вычислять комбинации в течение следующих 1 триллиона лет. Все, что им нужно сделать, это использовать ограничение времени, и они будут выполняться через несколько часов.
Ответы
Ответ 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();