Comment générer un long guide?

Je souhaite générer un long UUID – quelque chose comme la clé de session utilisée par gmail. Il doit contenir au moins 256 caractères et pas plus de 512. Il peut contenir tous les caractères alphanumériques et quelques caractères spéciaux (ceux situés sous les touches de fonction du clavier). Cela a-t-il déjà été fait ou y a-t-il un échantillon?

C ++ ou C #

Mise à jour: Un GUID n’est pas suffisant. Nous avons déjà été témoins de collisions et nous devons y remédier. 512 est le maximum à partir de maintenant, car il nous empêchera de modifier les éléments déjà livrés.

Mise à jour 2: Pour les gars qui insistent sur le caractère unique du GUID, si quelqu’un veut deviner votre ID de session, il n’a pas à calculer les combinaisons pour les 1 billion de dollars à venir. Tout ce qu’ils ont à faire est d’utiliser le facteur temps et ils le seront en quelques heures.

Selon votre mise à jour2, vous êtes correct sur les Guids sont prédicables même les références msdn qui. Voici une méthode qui utilise un générateur de nombres aléatoires extrêmement puissant pour créer l’ID.

static long counter; //store and load the counter from persistent storage every time the program loads or closes. public static ssortingng CreateRandomSsortingng(int length) { long count = System.Threading.Interlocked.Increment(ref counter); int PasswordLength = length; Ssortingng _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.ToBase64Ssortingng(buf) + new ssortingng(chars); } 

EDIT Je sais qu’il ya un biais parce que allowedCharCount n’est pas divisible par 255, vous pouvez vous débarrasser du biais en jetant un nouveau nombre au hasard, si ce nombre se retrouve dans le no-mans-land du rest.

EDIT2 – Ce n’est pas garanti d’être unique, vous pouvez tenir un compteur monotone statique de 64 bits (ou supérieur si nécessaire) le coder en base46 et avoir les 4 ou 5 premiers caractères de l’id.

MISE À JOUR – Maintenant garanti d’être unique

MISE À JOUR 2: L’algorithme est maintenant plus lent, mais la polarisation est supprimée.

EDIT: Je viens de faire un test, je voulais vous faire savoir que ToBase64Ssortingng peut renvoyer des caractères non alphabétiques (comme 1 code pour "AQAAAAAAAAA=" ) juste pour que vous en soyez conscient.

Nouvelle version:

En prenant la réponse de Matt Dotson sur cette page, si vous n’êtes pas si inquiet à propos de l’espace de clé, vous pouvez le faire de cette façon et cela fonctionnera BEAUCOUP plus rapidement.

 public static ssortingng CreateRandomSsortingng(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.ToBase64Ssortingng(buf) + Convert.ToBase64Ssortingng(randomBytes); } 

Si vos GUID entrent en collision, puis-je vous demander comment vous les générez?

Il est astronomiquement improbable que des GUID entrent en collision car ils sont basés sur:

  • 60 bits – horodatage pendant la génération
  • 48 bits – identifiant d’ordinateur
  • 14 bits – ID unique
  • 6 bits sont fixés

Vous devez exécuter la génération de GUID sur la même machine environ 50 fois au même instant pour avoir 50% de chances de collision. Notez que cet instant est mesuré en nanosecondes.

Mettre à jour:

Selon votre commentaire “mettre les GUID dans une table de hachage” … la méthode GetHashCode() est ce qui cause la collision, pas les GUID:

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

Vous pouvez voir qu'il renvoie un int , donc si vous avez plus de 2 ^ 32 "GUID" dans la table de hachage, vous allez avoir une collision à 100%.

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

Mais pour quoi?

Le problème ici est pourquoi , pas comment . Un identifiant de session plus gros qu’un GUID est inutile, car il est déjà assez gros pour contrecarrer les attaques par force brute.

Si vous êtes préoccupé par la prédiction des GUID, ne le soyez pas. Contrairement aux précédents GUID séquentiels, les GUID V4 sont sécurisés de manière cryptographique, sur la base de RC4. Le seul exploit que je connaisse dépend de l’access complet à l’état interne du processus qui génère les valeurs. Il ne peut donc vous mener nulle part si vous ne disposez que d’une séquence partielle de GUID.

Si vous êtes paranoïaque, générez un GUID, hachez-le avec quelque chose comme SHA-1 et utilisez cette valeur. Cependant, c’est une perte de temps. Si vous êtes préoccupé par le détournement de session, vous devriez utiliser SSL, pas cela.

 byte[] random = new Byte[384]; //RNGCryptoServiceProvider is an implementation of a random number generator. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(random); var sessionId = Convert.ToBase64Ssortingng(random); 

Vous pouvez remplacer les “/” et “=” du codage base64 par tous les caractères spéciaux acceptables pour vous.

L’encodage Base64 crée une chaîne 4/3 plus grande que le tableau d’octets (par conséquent, les 384 octets devraient vous donner 512 caractères).

Cela devrait vous donner des ordres de magnatude plus de valeurs qu’un guid encodé en base16 (hex). 512 ^ 16 vs 512 ^ 64

De plus, si vous les mettez dans un serveur SQL, veillez à désactiver l’insensibilité à la casse.

Il y a deux manières très faciles (C #):

1) Générez un groupe de guides à l’aide de Guid.NewGuid (). ToSsortingng (“N”). chaque GUID sera composé de 32 caractères, il vous suffit donc d’en générer 8 et de les concaténer pour obtenir 256 caractères.

2) Créez une chaîne constante (chaîne constante sChars = “abcdef”) de caractères acceptables que vous souhaitez dans votre UID. Ensuite, dans une boucle, sélectionnez de manière aléatoire des caractères dans cette chaîne en générant de manière aléatoire un nombre compris entre 0 et la longueur de la chaîne de caractères acceptables (sChars), puis concaténez-les dans une nouvelle chaîne (utilisez ssortingngbuilder pour la rendre plus performante, mais chaîne travailler aussi).

Vous voudrez peut-être consulter la bibliothèque Uuid de boost. Il prend en charge une variété de générateurs, y compris un générateur aléatoire qui pourrait répondre à vos besoins.

J’utiliserais une sorte de hash de std :: time () probablement sha512. ex (en utilisant crypto ++ pour le codage sha hash + base64).

 #include  #include  #include  #include  #include  int main() { std::ssortingng digest; std::ssortingngstream 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; } 

https://github.com/bigfatsea/SUID Identificateur unique simple

Bien que ce soit en Java, mais peut être facilement porté dans un autre langage. Vous pouvez vous attendre à ce que des identifiants en double sur la même instance se trouvent 136 ans plus tard, ce qui est suffisant pour les projets de taille petite à moyenne

Exemple:

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