top of page
  • Loïc Morel

Le portefeuille Bitcoin - extrait ebook Bitcoin Démocratisé 2.



Sommaire :



 

Si vous ne comprenez pas certains mots techniques utilisés dans cet article, nous avons rédigé un glossaire permettant de définir tous ces termes. Retrouvez le en cliquant ici : https://www.pandul.fr/post/glossaire-s%C3%A9rie-d-ebooks-bitcoin-d%C3%A9mocratis%C3%A9


Cet article est extrait de l'ebook Bitcoin Démocratisé 2. Il a été légèrement modifiée par rapport à l'ouvrage original afin de l'adapter au format du blog. Pour accéder à l'ebook original, cliquez ici : https://www.pandul.fr/ressources


Cet ouvrage est mis à disposition selon les termes de la Licence Creative Commons : Attribution - Partage dans les Mêmes Conditions 4.0 International (CC BY-SA 4.0), à l'exception des logos de Pandul seuls qui demeurent la propriété intellectuelle de l'Ei Loïc Morel.


Pour en savoir plus, cliquez ici :

https://creativecommons.org/licenses/by-sa/4.0/


Merci à l’ensemble des personnes qui m’ont apporté leur aide, leurs conseils d’experts et leurs encouragements sur l'ouvrage original :


Merci également à tous ceux qui m’ont apporté leur aide sur ce projet mais qui ont préféré rester anonymes.

 

Dans ce tome 2 nous allons entrer dans le vif du sujet. Nous allons étudier en profondeur le portefeuille Bitcoin.


L’objectif va être de pouvoir visualiser comment se construit un portefeuille sur Bitcoin, comment il se décompose et à quoi servent les différentes informations qui le constituent. Cette compréhension des mécanismes du portefeuille vous permettra par la suite d'améliorer votre utilisation de Bitcoin en termes de sécurisation et de confidentialité.


Entropie, phrase mnémonique, graine, xpub, passphrase ou encore adresses, nous allons étudier et vulgariser tous ces concepts dont vous entendez parler mais dont vous ne comprenez pas forcément le fonctionnement technique.


Mais avant de commencer, je pense qu’il est important de rappeler ce qu’est un portefeuille Bitcoin et quelle est son utilité.


Comme je l’ai évoqué dans le tome 1, le mot “portefeuille” est finalement assez mal choisi. En effet, des bitcoins ne peuvent pas être stockés de la même façon que l’on stockerait des pièces dans un portefeuille en cuir. Au lieu de cela, les unités de compte bitcoin sont représentées sur le réseau par des UTXO (Unspent Transaction Output), qui sont tout simplement des morceaux de bitcoins.


Ces UTXO sont associés à un utilisateur à travers sa clé publique. Pour pouvoir dépenser ses bitcoins, l’utilisateur devra généralement produire une signature à partir de la clé privée associée à cette clé publique. C’est ce que je décrivais dans le premier tome de la série.


Les informations qui doivent être conservées précieusement par l'utilisateur sont donc les clés privées.


Le portefeuille Bitcoin permet à l’utilisateur de conserver facilement ses clés privées en un seul lieu. Le fonctionnement ressemble donc plus à celui d’un porte-clés qu’à celui d’un portefeuille.


Les premiers portefeuilles utilisés sur Bitcoin étaient simplement des logiciels regroupant des clés privées, déterminées de manières pseudo-aléatoire, qui n’avaient aucun lien entre elles. C’est ce que l’on appelle un portefeuille JBOK (Just a Bunch Of Keys).


Ces premiers portefeuilles sont quelque peu laborieux à utiliser puisqu’ils obligent l’utilisateur à réaliser une nouvelle sauvegarde pour toute nouvelle paire de clés générée.


En 2012, Pieter Wuille publie le BIP32, une proposition visant à construire des portefeuilles Bitcoin déterministes hiérarchiques. L’idée derrière ce nouveau format de portefeuille est de ne plus déterminer aléatoirement les clés privées, mais de toutes les dériver de façon déterministe et hiérarchique depuis une information unique : la graine (seed).


Ainsi, l’utilisateur n’a plus besoin de réaliser une nouvelle sauvegarde pour toute nouvelle paire de clés générée, comme dans le cas des portefeuilles JBOK. Une unique sauvegarde de la graine permettra de retrouver de manière déterministe l’ensemble des paires de clés du portefeuille.


Le portefeuille HD (déterministe hiérarchique) BIP32 sera amélioré avec le BIP39 qui a introduit une façon standardisée d’encoder la graine afin de la rendre lisible plus aisément par un utilisateur et d’en faciliter la sauvegarde : C’est la fameuse phrase mnémonique, également nommée phrase de récupération ou encore phrase de 24 mots.


Aujourd’hui, l'extrême majorité des utilisateurs de Bitcoin disposent d’un portefeuille de type HD. C’est donc le format que l’on va étudier ici.


Vous pouvez toutefois garder à l’esprit que l’utilisation du protocole Bitcoin peut se faire autrement, avec d’autres standards de portefeuilles.





L’entropie.


Comme nous l'avons vu en introduction avec les portefeuilles JBOK, et comme je l’avais expliqué dans le tome 1, une clé privée Bitcoin doit être un nombre pseudo-aléatoire. Au plus ce nombre sera aléatoire et désordonné, au plus la paire de clé sera sécurisée.


En effet, nous avions vu que le nombre de clés privées possibles sur Bitcoin est presque de 2^256, un nombre extrêmement grand proche du nombre d'atomes dans l’univers observable. Le nombre de possibilités est tellement grand que si vous déterminez une clé privée de façon aléatoire, il est presque impossible qu’un autre utilisateur tombe sur la même clé ou trouve votre clé.


En revanche, si le caractère aléatoire n’est pas assez prononcé, il y aura statistiquement plus de chances que votre clé soit trouvée.


Le problème avec la génération aléatoire des clés privées est que l’utilisateur devra réaliser une nouvelle sauvegarde pour toute nouvelle clé générée. Les portefeuilles HD ne génèrent donc plus les clés privées de façon aléatoire, mais de façon déterministe à partir d’une information unique, de telle sorte que l’utilisateur n’ait plus qu’une seule information à sauvegarder.


Pour conserver un caractère pseudo-aléatoire lors de la détermination des clés privées d’un portefeuille HD, l’information unique utilisée à la base du portefeuille sera un nombre aléatoire ou pseudo-aléatoire.


L’entropie représente alors le niveau de désordre de ce nombre. Au plus ce nombre est grand et désordonné, au plus le portefeuille qui en découle est sécurisé.


Ce nombre est ensuite ramené à une taille standard, entre 128 bits et 256 bits afin de pouvoir organiser son encodage.


⇨ La plupart du temps, ce nombre est généré directement par le logiciel qui héberge le portefeuille grâce à un PRNG (Pseudo Random Number Generator). Néanmoins, il est tout à fait possible de générer ce nombre soi-même puis de l’importer dans un logiciel par la suite. Cela permet d’avoir la main sur la génération de l’entropie et d’en maîtriser le caractère pseudo-aléatoire ainsi que la taille.

La taille de ce nombre déterminera par la suite la taille de la phrase mnémonique. Les standards les plus utilisés sont ainsi les entropies de 128 bits donnant une phrase mnémonique de 12 mots, et les entropies de 256 bits donnant une phrase mnémonique de 24 mots.


Une des façons de générer une bonne entropie de 256 bits est de réaliser 256 lancés de dés afin de disposer d’une chaîne binaire de 256 caractères. J’ai rédigé un article vous détaillant étape par étape comment générer soi-même son entropie, et comment l’utiliser pour générer un portefeuille HD. Vous pouvez le retrouver en cliquant ici : Comment générer soi-même sa phrase mnémonique Bitcoin ?


Une autre façon de générer une bonne entropie est de déterminer aléatoirement un nombre très grand, supérieur à 256 bits, et de venir réduire ce nombre à 256 bits en utilisant la fonction de hachage SHA256. C’est le système que vous retrouvez notamment dans les Coldcard avec l’option “Dice Roll”.


Maintenant que nous avons défini ce qu’est l’entropie à la base du portefeuille HD, voyons ensemble comment passer de ce nombre pseudo-aléatoire à une phrase mnémonique.





La phrase mnémonique.


Également nommée “seed phrase”, “phrase de récupération”, “24 mots” ou encore “phrase secrète”, la phrase mnémonique est un encodage de la graine du portefeuille permettant d’en faciliter la sauvegarde. Introduite en 2013 avec le BIP39, elle représente aujourd’hui un standard utilisé pour l'extrême majorité des portefeuilles Bitcoin.


Pour passer d’une entropie à une phrase mnémonique, il suffit de calculer la checksum de l’entropie, et de concaténer (action de mettre bout à bout deux chaînes de caractères) entropie et checksum.


La checksum (ou “somme de contrôle” en français) représente le début du hash de l’entropie utilisant SHA256. Pour une entropie de 256 bits, la checksum sera de 8 bits.


On va donc passer notre entropie dans la fonction de hachage SHA256 pour en obtenir un hash. On va récupérer les 8 premiers bits de ce hash. Et enfin, on va mettre bout à bout l’entropie de 256 bits et la checksum de 8 bits, ce qui nous donne une phrase mnémonique de 264 bits.


Ajout de la somme de contrôle à la phrase mnémonique

La taille de la checksum et de la phrase mnémonique dépendent de la taille de l’entropie (ENT) initiale. La taille de la checksum (CS) est déterminée en divisant la taille en bits de l’entropie par 32.


Par exemple, pour une entropie de 256 bits :

CS = ENT / 32
CS = 256 / 32 = 8

Voici un tableau de correspondance entre la taille de l’entropie et la taille de la phrase qui en découle :

Entropie (bits)

Checksum (bits)

ENT || CS (bits)

Phrase (mots)

128

4

132

12

160

5

165

15

192

6

198

18

224

7

231

21

256

8

264

24


Pour passer de la concaténation ENT || CS à une phrase de 24 mots, nous allons diviser ENT || CS en 24 segments de 11 bits chacun.



Encodage de la phrase mnémonique en 24 mots

Vous remarquerez sur ce schéma que les 8 derniers bits en rouge correspondent à la checksum.


Dans notre exemple, avec ENT || CS d’une taille de 264 bits, nous disposerons de 24 segments de 11 bits. Chaque segment va permettre de déterminer le rang d’un mot au sein d’une liste de 2048 mots décrite dans BIP39.


Par exemple, si mon premier segment de 11 bits est 00101101110. En base 10 cela donnera 366. Comme la liste de mots est numérotée de 1 à 2048, il y a un décalage d’un rang avec ce segment pouvant aller de 0 à 2047. J’additionne donc 1 ce qui donne 367.


La base 2 correspond à un système de numération binaire (0 et 1). La base 10 est un système de numération décimal (les chiffres que l’on utilise dans la vie courante : de 0 à 9). La base 16 est un système de numération hexadécimal (de 0 à 9 et de A à F).

Je n’ai plus qu'à récupérer le mot n°367 sur la liste décrite dans le BIP39, qui est en l'occurrence : column.


Nous procéderons de même pour les 23 autres segments de bits afin de disposer de notre phrase de 24 mots.


⇨ Une des caractéristiques de cette liste est qu’aucun mot ne dispose des mêmes quatre premières lettres dans le même ordre. Ainsi, il suffit de noter les quatre premières lettres de chaque mot de notre phrase mnémonique pour disposer d’une sauvegarde fonctionnelle. Cela permet de gagner de la place, notamment si vous utilisez un support en métal.




La passphrase BIP38/BIP39.


La passphrase est un sel cryptographique optionnel d’une taille choisie. Elle permet d'améliorer la sécurité d’un portefeuille HD en ajoutant une information arbitraire qui, une fois aggloméré à la phrase mnémonique, permettra de calculer la graine.


La passphrase est parfois également nommée : “two-factor seed phrase”, “password”, “seed extension”, “extention word” ou encore “13ème ou 25ème mot”.

La passphrase est un mot de passe déterminé librement par l’utilisateur sans lequel il est impossible de dériver les clés d’un portefeuille. Elle est proposée pour la première fois sur Bitcoin avec le BIP38. Dans cette amélioration, la passphrase permet alors simplement de sécuriser une clé privée. Avec BIP39 et l’arrivée des phrases mnémoniques, elle est reprise et adaptée au format du portefeuille HD. Ainsi, elle ne sert non plus à sécuriser seulement une clé privée, mais bien l’intégralité d’un portefeuille.


Parfois appelée à tort 25ème mot, elle ne fait pas partie de la phrase mnémonique. Contrairement à celle-ci, la passphrase est une donnée libre, qui ne sera généralement pas stockée sur le logiciel qui stocke la phrase mnémonique.


Elle permet à l’utilisateur d’un portefeuille HD d’ajouter une couche supplémentaire de sécurité. Un attaquant en possession de la phrase mnémonique d’un portefeuille, ou du matériel qui héberge la phrase mnémonique, ne sera pas en capacité de dériver les paires de clés (et donc d'accéder aux bitcoins) tant qu’il n’aura pas trouvé la passphrase. Cela ajoute donc une garantie supplémentaire en cas de vol du hardware wallet ou de la phrase mnémonique.


En revanche, cette passphrase est à double tranchant. Si l’utilisateur lui-même oublie sa passphrase, il ne pourra pas retrouver l’accès à ses bitcoins.


Nous verrons dans la partie suivante comment cette information s’inclut dans le processus de dérivation d’un portefeuille HD.


⇨ Si vous souhaitez en savoir plus sur la passphrase, je vous conseille de lire mon article sur ce sujet : Tout savoir sur la Passphrase Bitcoin.




La graine.


Une fois la phrase mnémonique obtenue, nous allons pouvoir commencer la dérivation d’un portefeuille HD Bitcoin. La prochaine étape de dérivation est la graine (ou seed en anglais).


Son standard BIP39 la décrit comme une suite alphanumérique de 512 bits qui constitue la base d’un portefeuille HD. À partir de la graine, il sera possible de dériver l’intégralité des paires de clés d’un portefeuille Bitcoin.


Pour dériver une graine depuis une phrase mnémonique, on utilise la fonction PBKDF2 (Password Based Key Derivation Function 2). Comme expliqué dans le tome 1, c’est un algorithme de dérivation de clé qui applique une fonction choisie par l’utilisateur à un message de taille arbitraire avec un sel cryptographique, et répète l’opération plusieurs fois.


Sur le protocole Bitcoin, les paramètres de cette fonction sont :

  • Pour le message nous prenons la phrase mnémonique.

  • Pour le sel nous prenons la passphrase.

  • La fonction choisie est HMAC-SHA512.

  • Le nombre d’itération est de 2048.


Si le portefeuille ne dispose pas de passphrase, le champ du sel sera laissé vide.


Voici la représentation schématique du fonctionnement de PBKDF2 lors de la dérivation de la graine d’un portefeuille HD :



Dérivation de la graine du portefeuille HD Bitcoin


⇨ Pour rappel, HMAC est un algorithme cryptographique permettant de calculer un code d’authentification en utilisant une combinaison d’une fonction de hachage et d’une clé secrète, utilisé ici avec la fonction de hachage SHA512. Je décris leurs fonctionnements en détail dans le tome 1 de la série d’ebooks.

Quelle que soit la taille de votre phrase mnémonique, la taille de votre graine sera toujours de 512 bits si vous respectez le standard BIP39.


Une fois que le portefeuille dispose de la graine (seed), nous allons pouvoir commencer la dérivation des paires de clés.





La clé maîtresse.


Après avoir dérivé la graine, la prochaine étape dans la dérivation d’un portefeuille HD va être de déterminer la clé privée maîtresse et le code de chaîne maître.


Pour obtenir ces deux informations essentielles au processus de dérivation des paires de clés, il faut appliquer la fonction HMAC-SHA512 à la graine. Le résultat de cette opération sera un nombre de 512 bits.


Pour rappel, la fonction HMAC-SHA512 utilise en entrée un message et une clé. Dans la cas de la dérivation de la clé maîtresse, ces deux informations sont :

  • Message : les 512 bits de la graine.

  • Clé : identique pour tout le monde, les deux mots Bitcoin Seed.


La raison pour laquelle la clé est identique pour chaque utilisateur est que HMAC-SHA512 nécessite forcément une deuxième entrée. Les développeurs du BIP32 n’ont pas utilisé simplement SHA512 car la fonction n’était pas implémentée dans Bitcoin contrairement à HMAC-SHA512. De plus, l’ajout de la clé Bitcoin seed permet de générer une clé maîtresse unique à Bitcoin plutôt que d’utiliser n’importe quel ancien hash SHA512.


La sortie de 512 bits sera séparée en deux :

  • Les 256 bits de gauche donneront la clé privée maîtresse du portefeuille.

  • Les 256 bits de droite donneront le code de chaîne maître.


⇨ En réalité, on appliquera le format parse256 aux 256 bits de gauche pour obtenir la clé privée maîtresse : On interprète cette séquence comme un nombre de 256 bits, l'octet le plus significatif en premier.

Voici la représentation schématique de la génération de la clé privée maîtresse et du code de chaîne maître, à partir de la graine :


Dérivation de la clé maîtresse et du code de chaine maître


La clé maîtresse d’un portefeuille est en quelque sorte la clé parent de toutes les autres clés enfants obtenues par dérivation. Elle représente la profondeur zéro du portefeuille HD, c’est-à-dire l’information de base.


Le code de chaîne intervient dans la dérivation des clés enfants. Il est impossible de dériver des clés sans en avoir la connaissance. Il permet d'introduire une source d’entropie dans le processus de dérivation.


A partir de ces deux informations que sont la clé privée maîtresse et le code de chaîne maître, nous allons pouvoir dériver des clés enfants.


Chaque paire enfant se décompose en trois partie :

  • La clé privée.

  • La clé publique.

  • Le code de chaîne.





Les clés étendues.


Souvent confondues avec la clé maîtresse, les clés étendues, également nommées clés extensibles, sont pourtant bien différentes de celle-ci.


En théorie, une clé étendue représente simplement la concaténation de n’importe quelle clé (publique ou privée) et de son code de chaîne associé. En réalité, le terme de clés étendues est aujourd’hui utilisé seulement pour désigner la xpub et la xprv : la paire parent d’un compte.


Comme expliqué précédemment, une clé privée parent seule ou une clé publique parent seule ne permettent pas de dériver les clés enfants descendantes de cette paire. Pour ce faire, il faut nécessairement disposer du code de chaîne associé à la paire de clé parent en question.


Étant donné que les clés étendues agrègent ces deux informations (la clé et le code de chaîne), elles permettent donc de rassembler en une seule chaîne de bits l’intégralité des informations nécessaires pour dériver des clés enfants.


Détermination d'une clé étendue


Lorsqu’elles sont mises en forme, ces clés étendues disposent d’un préfixe qui permet de les différencier. Ainsi les clés privées étendues commencent toujours par : xprv, yprv ou zprv. Et les clés publiques étendues commencent toujours par : xpub, ypub ou zpub.


La clé privée étendue permet de dériver l’intégralité des clés privées enfants du compte, et donc par addition et doublement de points sur les courbes elliptiques, l’intégralité des clés publiques enfants.


La clé publique étendue xpub permet de dériver l’intégralité des clés publiques enfants du compte, sauf les clés publiques enfants endurcies (voir partie suivante).


Contrairement à la clé privée étendue, la clé publique étendue ne permettra pas d’accéder aux clés privées enfants.


Une personne en possession d’une xpub d’un compte sur un portefeuille HD pourra donc observer toutes les clés publiques enfants du compte (sauf les éventuelles endurcies). Il pourra également voir les fonds qui y transitent et dériver des adresses, mais il ne pourra jamais débloquer les bitcoins associés à ces clés publiques.


⇨ Le lien mathématique irréversible entre clé privée et clé publique est expliqué en détail dans le tome 1 de la série. Pour résumer : On utilise l'addition et le doublement de points sur les courbes elliptiques pour dériver une clé publique unique depuis une clé privée. Cette opération est à sens unique, ce qui veut dire qu’il est facile de déterminer une clé publique en sachant sa clé privée mais qu’il est actuellement impossible de faire l’inverse.

Pour obtenir la clé privée étendue d’un compte, il faut concaténer la clé privée choisie pour être parent, et son code de chaîne associé. Cela nous donne une suite de 512 bits.


Pour obtenir la clé publique étendue d’un compte, il faut concaténer la clé publique choisie pour être parent, et son code de chaîne associé. Cela nous donne une suite de 520 bits.


On a donc une clé privée étendue représentée par k || c, où k est la clé privée choisie, et c est le code de chaîne associé.


On a également une clé publique étendue représentée par K || c, où c est le même code de chaîne et où K = point(k).


La fonction point représente la dérivation de clé publique sur les courbes elliptiques.


En théorie, seuls la clé (publique ou privée) et le code de chaîne sont nécessaires pour dériver les clés enfants. En réalité, d’autres informations vont être ajoutées aux clés étendues afin d’identifier la clé parent et d'indiquer sa place dans la hiérarchie du portefeuille.


Premièrement, un préfixe de 1 octet est ajouté à la clé privée afin qu’elle soit d’une taille similaire à la clé publique : 33 octets.


Les autres informations qui composent une clé étendue sont :

Version

Permet de placer “xprv” ou “xpub” au début de la clé étendue.

4 octets

Profondeur

Nombre de dérivations par rapport à la clé maîtresse (je vous explique à quoi cela correspond dans la partie suivante).

1 octet

Empreinte parent

Quatre premiers octets du HASH160 de la clé parent :


HASH160 (Kpar) = RIPEMD160(SHA256(Kpar))

4 octets

Numéro index

Numéro de cette paire enfant parmi ses sœurs.

4 octets

Code de chaîne

​Code de chaîne (voir partie précédente).

32 octets

Clé

La clé privée + un préfixe de 1 octet, ou la clé publique seule.


La clé publique étant plus longue que la clé privée de l’ordre de 1 octet, l’octet supplémentaire ajouté à la clé privée permet d’égaliser sa taille. Cet octet supplémentaire est OxOO concaténé au départ de la chaîne de bits.

33 octets

Somme de contrôle

Checksum des lignes précédentes utilisant HASH256 (double SHA256).

4 octets


Au total, une clé étendue fait donc 78 octets sans la checksum, et 82 octets avec la checksum. Une fois cette somme de contrôle ajoutée, on convertit toutes ces informations en Base58 afin de disposer d’un format lisible plus aisément par un utilisateur.



Voici à quoi ressemble une clé publique étendue, avec les informations supplémentaires décrites ci-dessus, et les couleurs correspondantes :


En HEX (base 16) : 
0488B21E036D5601AD80000000C605DF9FBD77FD6965BD02B77831EC5C78646AD3ACA14DC3984186F72633A89303772CCB99F4EF346078D167065404EED8A58787DED31BFA479244824DF50658051F067C3A

En Base 58 :
xpub6CTNzMUkzpurBWaT4HQoYzLP4uBbGJuWY358Rj7rauiw4rMHCyq3Rfy9w4kyJXJzeFfyrKLUar2rUCukSiDQFa7roTwzjiAhyQAdPLEjqHT




Dérivation de paires de clés.


A partir de la clé maîtresse et du code de chaîne maître, nous allons être capables de dériver un certain nombre de paires de clés enfants. Ces clés enfants pourront soit être utilisées comme telles pour des échanges de bitcoins, soit servir à leur tour de clés parents ce qui donnera des paires de clé petits-enfants.


Ce fonctionnement hiérarchique permet de segmenter des branches et d’offrir de nombreuses options de gestion des clés et de structures de portefeuille.



Dérivation et structure du portefeuille HD Bitcoin


Il existe alors deux types de paires de clés enfants : les clés enfants endurcies (ou renforcées) et les clés enfants non endurcies (également nommées clés enfants normales).


Les clés publiques enfants normales peuvent être dérivées soit à partir de la clé publique étendue parent, soit à partir de clé privée étendue parent.


En revanche, les clés enfants endurcies et les clés privées enfants normales ne peuvent être dérivées que depuis la clé privée étendue parent. En conséquence, il sera impossible de tracer ces clés endurcies à partir de la clé publique étendue parent, contrairement aux clés normales.



Dérivation de clé enfants depuis les clés étendues


Chaque paire de clés étendues dispose de 2^31 paires de clés enfants normales et de 2^31 paires de clés enfants endurcies. Chacune de ces paires dispose d’un numéro d’indice (index), un nombre entier de 32 bits permettant de différencier chaque paire de clés de ses autres sœurs.


Les paires de clés enfants normales disposent d’un index compris entre 0 et 2^(31-1). Et les paires de clés enfants endurcies disposent d’un index compris entre 2^31 et 2^(32-1).


Le processus de dérivation des clés enfants fait de nouveau intervenir la fonction HMAC-SHA512. Pour rappel, cet algorithme applique une fonction de hachage à un message et à une clé en entrée, pour donner une sortie de 512 bits comparable à un condensat.


⇨ Attention ! La “clé” utilisée dans la fonction HMAC n’a rien à voir avec les paires de clés (publiques et privées) dont nous parlions jusqu’ici. Dans l’utilisation de HMAC, le mot “clé” désigne simplement une variable utilisée en input de la fonction.

Dans le cas de la dérivation de clés enfants, la “clé” de la fonction HMAC sera le code de chaîne parent, et le message sera une concaténation de la clé parent et de l’index choisi.


Voici ci-dessous les différents processus de dérivation en fonction des catégories de clés enfants souhaitées, et du type de clé parent en entrée.


Pour chaque processus :

Cpar = Code de chaîne parent
→ kpar = Clé privée parent
→ Kpar = Clé publique parent
 
→ Cenf = Code de chaîne enfant
→ kenf = Clé privée enfant
→ Kenf = Clé publique enfant
 
→ h = Sortie de la fonction HMAC-SHA512
→ H = Résultat de h  G, où G est le point générateur 
 (Addition et doublement de points sur les courbes elliptiques).

→ n = Ordre de la courbe elliptique sachant le point d’origine (voir tome 1).


  • Clé privée parent → clé privée enfant.


Nous allons dériver kenf et Cenf à partir de kpar et de Cpar.


Premièrement on choisit un nombre i de 32 bits pour l’index de la clé. Si i < 2^31, alors nous calculerons une clé normale. Si i ≥ 2^31, alors nous calculerons une clé endurcie.


  • Pour kenf endurcie, la formule sera :

h = HMAC-SHA512 (Clé = Cpar, Message = 0X00 || kpar || i )

⇨ Pour rappel, 0X00 est ici le préfixe permettant d’amener la clé privée à la même taille que la clé publique, à savoir 264 bits ou 33 octets.
|| est le symbole pour une concaténation, cela consiste simplement à mettre bout à bout deux opérandes.

  • Pour kenf normale la formule sera :

h = HMAC-SHA512 (Clé = Cpar, Message = point(kpar) || i )

Pour rappel, la fonction point(p) permet de calculer le point P (la clé publique de p) sur la courbe elliptique tel que P = p⋅ G . On a donc : point(p) = P

Schématiquement, ces opérations ressemblent à cela :

Dérivation de clés enfants


Deuxièmement, on récupère h (la sortie de la fonction HMAC) et on le sépare en deux séquences de 32 octets :

  • les 32 premiers octets seront h1,

  • les 32 derniers octets seront h2.


La clé privée enfant kenf sera alors égale à :

kenf = parse256(h1) + kpar [mod n]

Dans la formule précédente, nous avons additionné h1 mis en forme parse256, et kpar. Pour maintenir cette nouvelle clé privée enfant dans le rang de notre courbe elliptique, on la module avec n.


Le code de chaîne enfant sera : Cenf = h2.


Si parse256(h1) ≥ n ou si kenf = 0, alors la clé enfant est invalide. Il faudra alors réessayer l’opération avec le prochain index.


Ce schéma illustre la dérivation d’une clé privée enfant endurcie :


Dérivation d'une clé privée enfant à partir de la clé privée étendue parent

Pour disposer d’une clé privée enfant normale, le schéma serait similaire mis à part que la clé privée parent (bleu) en entrée 1 serait remplacée par la clé publique parent (verte).





  • Clé publique parent → clé publique enfant.


Nous allons dériver Kenf et Cenf à partir de Kpar et de Cpar.


⇨ Pour rappel, “k” minuscule désigne une clé privée et “K” majuscule désigne la clé publique associée.

Premièrement on choisit un nombre i de 32 bits pour l’index de la clé. À partir d’une clé publique parent, nous ne pourrons calculer qu’une clé publique enfant normale (pas endurcie) il faut donc que : i < 2^31.


Ensuite on applique la fonction HMAC :

h = HMAC-SHA512 (Clé = Cpar, Message = Kpar || i )

Puis on récupère h (la sortie de la fonction HMAC) et on le sépare en deux séquences de 32 octets :

  • les 32 premiers octets seront h1,

  • les 32 derniers octets seront h2.


La clé publique enfant Kenf sera :

Kenf = point(parse256(h1)) + Kpar

Le code de chaîne enfant sera :

Cenf = h2

Si parse256(h1) ≥ n, ou si Kenf est le point à l’infini, alors la clé enfant est invalide. Il faudra réessayer l’opération avec un autre index.


Ci-dessous, le schéma de la dérivation d’une clé publique enfant à partir de la clé publique parent. En admettant que : point(parse256(h1)) = H1.


Dérivation clé publique enfant à partir de la clé publique étendue parent


  • Clé privée parent → clé publique enfant.