web-dev-qa-db-fra.com

Génération de l’UUID v5. Quel est le nom et l'espace de noms?

J'ai lu la page man, mais je ne comprends pas ce que sont name et namespace.

Pour les UUID de version 3 et de version 5, l'espace de nom et le nom des arguments de ligne de commande supplémentaires doivent être indiqués. L'espace de nom est un UUID sous forme de chaîne ou un identifiant pour les UUID d'espace de nom prédéfinis en interne (connus actuellement sous les noms "ns: DNS", "ns: URL", "ns: OID" et "ns: X500"). Le nom est une chaîne de longueur arbitraire.

L'espace de nom:

L’espace de nom est soit un UUID sous forme de chaîne, soit un

Est-ce que cela signifie que je dois le stocker (UUID v4) quelque part en relation avec l'UUID v5 généré? Dans les deux cas, pourquoi cela n’est-il pas fait automatiquement?

Le nom est une chaîne de longueur arbitraire.

name une chaîne complètement aléatoire? Quel est le but de cela alors? Peut-il être décodé à partir de l'UUID v5?

90
Gajus

Le nom et l'espace de noms peuvent être utilisés pour créer une hiérarchie d'UUID (très probablement) uniques.

En gros, un UUID de type 3 ou de type 5 est généré en hachant ensemble un identifiant d'espace de nom avec un nom. Les UUID de type 3 utilisent MD5 et les UUID de type 5 utilisent SHA1. Seuls 128 bits sont disponibles et 5 bits sont utilisés pour spécifier le type. Par conséquent, tous les bits de hachage ne sont pas convertis en UUID. (De plus, MD5 est considéré comme cassé sur le plan cryptographique et SHA1 en est à sa dernière étape. Ne l'utilisez donc pas pour vérifier des données qui doivent être "très sécurisées"). Cela dit, cela vous permet de créer une fonction de "hachage" répétable/vérifiable, mappant un nom éventuellement hiérarchique sur une valeur de 128 bits probablement unique, agissant potentiellement comme un hachage hiérarchique ou un MAC.

Supposons que vous ayez un magasin (clé, valeur), mais qu'il ne supporte qu'un seul espace de noms. Vous pouvez générer un grand nombre d'espaces de noms logiques distincts à l'aide d'UUID de type 3 ou de type 5. Commencez par créer un UUID racine pour chaque espace de nom. Cela peut être un UUID de type 1 (hôte + horodatage) ou de type 4 (aléatoire) tant que vous le stockez quelque part. Vous pouvez également créer un UUID aléatoire pour votre racine (ou utiliser le null UUID: 00000000-0000-0000-0000-000000000000 en tant que root), puis créez un UUID reproductible pour chaque espace-noms en utilisant "uuid -v5 $ROOTUUID $NAMESPACENAME ". Vous pouvez maintenant créer des UUID uniques pour les clés d’un espace-noms en utilisant" uuid -v5 $NAMESPACEUUID $KEY ". Ces UUID peuvent être jetés dans un seul magasin clé-valeur avec une probabilité élevée d’éviter les collisions. Ce processus peut être répété de manière récursive de sorte que, par exemple, la" valeur "associée à une clé UUID représente à son tour une sorte de logique. "namespace" comme un compartiment, un conteneur ou un répertoire, alors son UUID peut être utilisé à son tour pour générer plus d'UUID hiérarchiques.

L'UUID de type 3 ou de type 5 généré contient un hachage (partiel) de l'ID d'espace de nom et de l'espace de nom nom-dans-nom (clé). Il ne contient pas plus l'UUID de l'espace de noms qu'un message MAC ne contient le contenu du message à partir duquel il est codé. Le nom est une chaîne "arbitraire" (octet) du point de vue de l'algorithme uuid. Sa signification dépend toutefois de votre application. Il peut s'agir d'un nom de fichier dans un répertoire logique, d'un identifiant d'objet dans un magasin d'objets, etc.

Bien que cela fonctionne bien pour un nombre relativement grand d'espaces de noms et de clés, il finit par manquer de Steam si vous visez un très grand nombre de clés uniques avec une probabilité très élevée. L'entrée Wikipedia du problème d'anniversaire (ou Birthday Paradox) inclut un tableau qui donne les probabilités d'au moins une collision pour différents nombres de clés et de tailles de tableau. De cette manière, le hachage de 26 milliards de clés sur 128 bits a une probabilité de collision de p=10^-18 (négligeable), mais 26 000 milliards de clés augmentent la probabilité d’au moins une collision à p=10^-12 (un sur un billion), et hachage 26*10^15 _ touches, augmente la probabilité d'au moins une collision de p=10^-6 (un sur un million). Si vous réglez sur 5 bits qui encodent le type UUID, le processus s'épuisera un peu plus rapidement. Ainsi, un billion de clés a environ 1 chance sur 1 billion de collision.

Voir http://en.wikipedia.org/wiki/Birthday_problem#Probability_table pour le tableau de probabilités.

Voir http://www.ietf.org/rfc/rfc4122.txt pour plus de détails sur les codages UUID.

81
Jeff Anderson-Lee

Les UUID de type 3 et de type 5 sont simplement une technique consistant à insérer un hash dans un UUID.

  • Type 1: adresse MAC du périphérique, date/heure en 128 bits
  • Type: bourre un hachage MD5 en 128 bits
  • Type 4: bourre des données aléatoires sur 128 bits
  • Type 5: insère un hachage SHA1 en 128 bits

Un hachage SHA1 génère 160 bits (20 octets). Le résultat du hachage est converti en un UUID. Parmi les 20 octets de SHA1:

SHA1 Digest:   74738ff5 5367 e958 9aee 98fffdcd1876 94028007
UUID (v5):     74738ff5-5367-5958-9aee-98fffdcd1876
                             ^_low nibble is set to 5 to indicate type 5
                                  ^_first two bits set to 1 and 0, respectively

(Notez que les deux premiers bits de "9" sont déjà 1 et 0, respectivement, cela n'a donc aucun effet).

Qu'est-ce que je hache?

Vous vous demandez probablement ce que je suis supposé hacher. En gros, vous hachez la concaténation de:

sha1([NamespaceUUID]+[AnyString]);

Vous préfixez votre chaîne avec ce qu'on appelle namespace pour éviter les conflits de noms.

Le ID RFC prédéfinit quatre espaces de noms pour vous:

  • NameSpace_DNS: {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
  • NameSpace_URL: {6ba7b811-9dad-11d1-80b4-00c04fd430c8}
  • NameSpace_OID: {6ba7b812-9dad-11d1-80b4-00c04fd430c8}
  • NameSpace_X500: {6ba7b814-9dad-11d1-80b4-00c04fd430c8}

Donc, vous pouvez hacher ensemble:

StackOverflowDnsUUID = sha1(Namespace_DNS + "stackoverflow.com");
StackOverflowUrlUUID = sha1(Namespace_URL + "stackoverflow.com");

La RFC définit ensuite comment:

  • prendre les 160 bits de SHA1
  • et le convertir en 128 bits d'un UUID

Le Gist de base est de ne prendre que les 128 premiers bits, farcis un 5 dans l’enregistrement type, puis définissez les deux premiers bits de l’enregistrement clock_seq_hi_and_reserved section à 1 et 0, respectivement.

Plus d'exemples

Maintenant que vous avez une fonction qui génère ce qu'on appelle Nom, vous pouvez avoir la fonction (en pseudo-code):

UUID NameToUUID(UUID NamespaceUUID, String Name)
{
    byte[] hash = sha1(NamespaceUUID.ToBytes() + Name.ToBytes());
    UUID result;
    Copy(hash, result, 16);
    result[6] &= 0x0F; 
    result[6] |= 0x50;
    result[8] &= 0x3F; 
    result[8] |= 0x80;
    return result;
}

(Notez que l’endurance de votre système peut affecter les index des octets ci-dessus)

Vous pouvez avoir des appels:

uuid = NameToUUID(Namespace_DNS, 'www.stackoverflow.com');
uuid = NameToUUID(Namespace_DNS, 'www.google.com');
uuid = NameToUUID(Namespace_URL, 'http://www.stackoverflow.com');
uuid = NameToUUID(Namespace_URL, 'http://www.google.com/search&q=rfc+4112');
uuid = NameToUUID(Namespace_URL, 'http://stackoverflow.com/questions/5515880/test-vectors-for-uuid-version-5-converting-hash-into-guid-algorithm');

Revenons maintenant à votre question

Pour les UUID de version 3 et de version 5, l'espace de noms et le nom des arguments de ligne de commande supplémentaires doivent être indiqués. L'espace de nom est un UUID sous forme de chaîne ou un identifiant pour les UUID d'espace de nom prédéfinis en interne (connus actuellement sous les noms "ns: DNS", "ns: URL", "ns: OID" et "ns: X500"). Le nom est une chaîne de longueur arbitraire.

Le namespace correspond à l’UUID de votre choix. Ce peut être l’un des prédéfinis, ou vous pouvez créer le vôtre, par exemple:

UUID Namespace_RectalForeignExtractedObject = '4d79546f-6e67-7565-496e-486572417373'

Le nom est une chaîne de longueur arbitraire.

Le nom est simplement le texte que vous souhaitez voir ajouté à l'espace de noms, puis haché, puis copié dans un UUID:

uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'screwdriver');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'toothbrush');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'broomstick');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'orange');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'axe handle');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'impulse body spray');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'iPod Touch');

Note: Tout code publié dans le domaine public. Aucune attribution requise.

180
Ian Boyd

Un nom n'est rien d'autre qu'un identifiant unique dans un espace de noms. Le problème est que les espaces de noms sont souvent assez petits et que les noms d’un nom se heurtent souvent à ceux d’autres. Par exemple, le numéro de plaque d'immatriculation de ma voiture (nom) est unique dans l'espace de noms de mon État DMV, mais ce n'est probablement pas unique au monde; d'autres DMV d'état peuvent avoir utilisé le même nom dans leurs propres espaces de noms. Heck, quelqu'un d'autre peut avoir un numéro de téléphone (nom) qui correspond également parce que c'est encore un autre espace de noms, etc.

Les UUID peuvent être vus comme habitant un seul espace de noms si vaste qu'il peut fournir un nom unique pour tout; c'est ce que "l'universel" signifie. Mais comment mappez-vous des noms existants dans d'autres espaces de noms vers un UUID?

Une solution évidente consiste à générer un UUID (V1 ou V4) pour chaque élément afin de remplacer les anciens noms dans leurs espaces de noms disjoints. L'inconvénient est qu'ils sont beaucoup plus volumineux, vous devez communiquer tous les nouveaux noms à tous ceux qui ont une copie de votre jeu de données, mettre à jour toutes vos API, etc. Quoi qu'il en soit, ce qui signifie maintenant que chaque élément a deux noms, alors avez-vous amélioré ou aggravé la situation?

C’est là que V3/V5 entrent en jeu. Les UUID look aussi aléatoires que V4 mais sont en réalité déterministes; Toute personne disposant du bon UUID pour un espace-noms peut alors indépendamment générer le même UUID pour n'importe quel nom donné dans cet espace-noms. Vous n'avez pas besoin de les publier du tout ni même de les pré-générer car tout le monde peut les créer à la volée au besoin!

Les noms DNS et les URL sont des espaces de noms très utilisés. C'est pourquoi des UUID standard ont été publiés pour ceux-ci; Les OID ASN.1 et les noms X.500 ne sont pas aussi communs, mais les organismes de normalisation les aiment, ils ont donc publié des UUID d'espaces de noms standard.

Pour tous les autres espaces de noms, vous devez générer votre propre UUID d'espace de noms (V1 ou V4) et le communiquer à toute personne qui en a besoin. Si vous avez plusieurs espaces de noms, la publication de l'UUID pour chacun d'entre eux n'est clairement pas idéale.

C’est là que la hiérarchie entre en jeu: vous créez un UUID "de base" (quel que soit son type), puis vous l’utilisez comme espace de noms pour nommer vos autres espaces de noms! De cette façon, il vous suffit de publier l'UUID de base (ou d'utiliser un nom évident) et tout le monde peut calculer le reste.

Par exemple, restons, nous voulions créer des UUID pour StackOverflow; qui a un nom évident dans l’espace de noms DNS, la base est donc évidente:

uuid ns_dns = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
uuid ns_base = uuidv5(ns_dns, 'stackoverflow.com');

StackOverflow lui-même possède des espaces de noms distincts pour les utilisateurs, des questions, des réponses, des commentaires, etc., mais ceux-ci sont également assez évidents:

uuid ns_user = uuidv5(ns_base, 'user');
uuid ns_question = uuidv5(ns_base, 'question');
uuid ns_answer = uuidv5(ns_base, 'answer');
uuid ns_comment = uuidv5(ns_base, 'comment');

Cette question particulière est # 10867405, donc son UUID serait:

uuid here = uuidv5(ns_question, '10867405');

Notez qu'il n'y a rien aléatoire dans ce processus. Ainsi, toute personne qui suit la même logique obtiendra la même réponse, mais l'espace de noms UUID est si vaste qu'il le sera (en réalité, étant donné la sécurité d'un fichier de 122 bits). cryptographic hash) n'entre jamais en conflit avec un UUID généré à partir d'une autre paire d'espace de nom/nom.

9
StephenS