Sécuriser un portefeuille Ethereum via un provider KMS — l’algorithme de signature ECDSA
La sécurité des portefeuilles Ethereum est cruciale pour la protection des actifs numériques. L’aspect le plus vital de cette sécurité est la gestion des clés privées, qui sont au cœur de toutes les transactions sur la blockchain. Une clé privée compromise peut non seulement entraîner des pertes financières substantielles, mais aussi exposer les utilisateurs à des risques juridiques et réglementaires.
Cet article détaille une méthode sophistiquée pour sécuriser les clés privées Ethereum en utilisant des services de gestion de clés aussi appélé KMS tel que AWS, Google, HashiCorp Vault ou Azure Key Vault. Ces plateformes offrent une solution robuste pour la gestion des clés, en assurant que la clé privée ne quitte jamais l’infrastructure sécurisée. Cette approche permet de bénéficier d’une sécurité de niveau entreprise, y compris l’utilisation de modules de sécurité matériels (HSM) certifiés FIPS 140–2.
Le processus décrit ici permet de signer une transaction Ethereum avec une clé privée gérée et protégée par un provider KMS. En adoptant cette méthode, les utilisateurs peuvent garantir que leurs clés privées restent inviolables et à l’abri des attaques externes, tout en facilitant la gestion et l’audit des clés au sein de leur organisation.
L’article guide pas à pas dans le processus de configuration et d’utilisation pour sécuriser une clé privée Ethereum, en mettant l’accent sur la création, le stockage et la signature sécurisée des transactions sans exposer la clé privée. En adoptant cette approche, vous pourrez atteindre un niveau de sécurité équivalant à des services tel que Ledger Enterprise.
1. Génération des clés ECDSA
Tout comme Bitcoin, Ethereum utilise l’algorithme de signature numérique à courbe elliptique (ECDSA). Plus précisément, secp256k1 tel que définie dans les “Standards for Efficient Cryptography” (SEC) par Certicom Research (https://www.secg.org/sec2-v2.pdf).
Bien que la compréhension approfondie de l’ECDSA ne soit pas nécessaire pour suivre ce guide, une connaissance de base peut être utile. Pour ceux qui souhaitent approfondir, il existe de nombreux articles et ressources éducatives sur le sujet.
Pour démarrer, créons une paire de clés asymétriques ECDSA utilisant la courbe secp256k1. Pour illustrer cela, je présente 2 exemples pratiques : l’un utilisant AWS et l’autre GCP. Il est à noter que d’autres fournisseurs de services de gestion de clés (KMS), comme HashiCorp ou Azure, peuvent également être utilisés sans modifier la logique exposée dans cet article.
AWS KMS :
Google KMS :
Une fois ces étapes complétées, vous obtiendrez l’ID de votre paire de clés, que nous utiliserons dans la suite de l’article.
2. Récupération de la clé public et calcul de l’adresse Ethereum
Lors de l’utilisation d’un service de gestion de clés (KMS) comme AWS ou GCP, il est important de comprendre que la clé publique obtenue ne correspond pas immédiatement à une clé publique Ethereum standard. La clé publique obtenue est encodée selon le format DER (Distinguished Encoding Rules), qui est une méthode de codage binaire pour les données structurées. Cette clé est formatée en tant que SubjectPublicKeyInfo (SPKI), tel que défini dans la norme X.509 pour la certification des clés publiques et détaillé dans la RFC 5280. Pour obtenir la valeur brute de la clé publique nécessaire à la génération de l’adresse Ethereum, il faut d’abord décoder ce format DER. Le format SubjectPublicKeyInfo est plus amplement décrit dans la RFC 5480, section 2.
2.1 Récupérer la clé publique auprès du provider
Voici 2 exemples vous permettant de récupérer la clé publique au format DER sur AWS et GCP.
AWS KMS :
Google KMS :
Le résultat de votre clé publique au format DER ressemblera à ceci (après conversion en hexadécimal) :
3056301006072A8648CE3D020106052B8104000A03420004B8E9C055D6C601A803F4E301FACB1FAF1F3B9F6D1F5150A9068B678F5F6A58A20220F505AAAC12E4180EDF59B2466A30D1CF4D409FA028D4A3EDF8ACFE7AD597C
2.2 Décodage de la clé publique
Vous avez probablement déjà réalisé que la clé publique que vous avez récupérée ne ressemble en rien à une clé publique Ethereum. Eh bien, vous avez tout à fait raison. Pour palier à cela, nous allons utiliser la bibliothèque asn1js
. Un outil efficace pour décoder et interpréter les données encodées en DER de la clé publique (ligne 11 à 19).
De plus, selon la section 2.2 de la RFC 5480 , le premier octet 0x04
indique qu'il s'agit d'une clé non compressée. Une fois ce premier octet supprimé (ligne 26), nous obtenons une clé publique standard Ethereum.
Le résultat de votre clé publique standard Ethereum ressemblera à ceci (après conversion en hexadécimal) :
0x03facdb512c802dbc6c4b4faa4709696f302f612a36e9d5e76939ead59e0c268cc
2.3 Calcul de l’Adresse Ethereum
Comme expliqué au chapitre 2 de Mastering Ethereum , l’adresse correspond aux 20 derniers octets du hachage keccak256 de la clé publique. Ainsi, le code pour générer l’adresse Ethereum est le suivant :
Le résultat de votre adresse Ethereum ressemblera à ceci (après conversion en hexadécimal) :
0x5163678a8a0958626c7Fc6eBff87F946B7AcE0B5
En résumer, pour obtenir l’adresse Ethereum correspondante à votre paire de clés ECDSA, il suffit de suivre ces étapes
3. Signature d’une Transaction Ethereum
La signature d’une transaction Ethereum en utilisant un provider KMS est un processus qui se décompose en plusieurs étapes distinctes, chacune jouant un rôle important dans la création d’une signature valide. Voici une explication détaillée de chaque étape :
- Signature d’un Hachage Keccak-256 :
Le point de départ est de signer un hachage Keccak-256 du message (transaction) avec un provider KMS. - Décodage et calcul des composants
r
ets
de la signature :
Après avoir signé le message avec votre provider KMS, la signature obtenue sera codée en DER. Cette signature doit être décodée pour être utilisée dans le contexte d’une transaction Ethereum. Une fois la signature DER décodée, il faut en extraire les composantsr
ets
. Ces deux valeurs sont essentielles dans la structure de la signature ECDSA et sont nécessaires pour la validation de la transaction sur la blockchain Ethereum. - Détermination de la valeur
v
:
La dernière étape consiste à trouver la valeur de l’ identifiant de récupérationv
(explication dans la suite de l’article).
3.1 Signature d’un Hachage Keccak-256 :
Nous reviendrons sur la charge utile réelle plus tard. Pour l’instant, vous pouvez simplement signer un hachage keccak256
vide qui sera transmis à cette fonction sous la forme d’un Bufferdigest
.
Voici 2 exemples vous permettant de signer un message arbitraire avec AWS et GCP.
AWS KMS :
Google KMS :
3.2 Décodage et calcul des composants r
et s
de la signature :
Notre provider KMS nous renvoie une signature codée en DER conformément aux spécifications ANS X9.62–2005. Pour traiter et utiliser cette signature dans le contexte d’Ethereum, une étape de décodage est nécessaire, comme le stipule la section 2.2.3 de la RFC 3279.
Dans ce contexte, j’ai élaboré une fonction d’analyse spécifique pour décomposer la signature DER en ses composants essentiels. Cette fonction se concentre sur l’extraction de deux entiers, r
et s
, qui sont cruciaux pour la représentation d'une signature ECDSA.
Le résultat de cette analyse cible un point spécifique sur la courbe elliptique où r
représente la coordonnée x et s
la coordonnée y. Dans le contexte de la cryptographie ECDSA, ces deux valeurs sont fondamentales pour la validation et la vérification des signatures. r
et s
constituent ensemble la signature numérique qui est utilisée pour authentifier la transaction sur la blockchain Ethereum, garantissant ainsi que la transaction a été effectivement signée par le détenteur de la clé privée correspondante sans révéler la clé elle-même.
Selon l’EIP-2, autoriser des transactions avec n’importe quelle valeur de
s
(de 0 au nombre maximal sur la courbe secp256k1n) présente un risque de malléabilité des transactions. C'est pourquoi une signature avec une valeur des
supérieure à la moitié de la courbe secp256k1n (c'est-à-diresecp256k1n / 2
) est considérée comme invalide dans le contexte d'Ethereum. Bien que ce soit une signature ECDSA valide, d'un point de vue d’Ethereum, elle est sur le "côté obscur" de la courbe. Le code ci-dessus traite ce problème en vérifiant si la valeur des
est supérieure àsecp256k1n / 2
(voir ligne 38). Si c'est le cas, nous sommes sur le "côté obscur" de la courbe. Il est alors nécessaire d'inversers
(comme indiqué à la ligne 41) pour obtenir une signature Ethereum valide. Cette méthode fonctionne parce que la valeur des
ne définit pas un point distinct sur la courbe. La valeur peut être+s
ou-s
, les deux signatures étant valides du point de vue de l'ECDSA.
3.3 Détermination de la Valeur v
:
La signature ECDSA utilisée dans Ethereum se compose de trois éléments clés : r
, s
, et un identifiant de récupération nommé v
. Historiquement, avant la mise en œuvre de l'EIP-155, la valeur de v
pouvait être soit 27, soit 28. Cependant, depuis l'adoption de l'EIP-155, la valeur de v
est désormais déterminée en fonction de l'ID de la chaîne (chain_id
) où la transaction est effectuée, modifiant ainsi la méthode de calcul de cette composante essentielle de la signature.
Pour les transactions sur les réseaux où l’EIP-155 est actif, la valeur de v
est calculée en utilisant la formule v = chain_id * 2 + 35
ou v = chain_id * 2 + 36
.
L’une des principales motivations de l’EIP-155 est de prévenir les attaques de replay. Dans une attaque de replay, l’acteur malveillant capture une transaction valide — disons, un transfert de fonds — d’une blockchain et la diffuse sur une autre blockchain. Avant l’EIP-155, si deux chaînes avaient des historiques de transactions similaires (comme c’était le cas avec Ethereum et Ethereum Classic après leur scission), une transaction valide sur une chaîne pouvait potentiellement être rejouée sur l’autre. Cela posait un risque de sécurité significatif.
Pour identifier la valeur correcte de v
dans une signature Ethereum, on peut se servir de la fonction ecrecover(sig, v, r, s)
. Cette fonction renvoie la clé publique correspondant à une signature Ethereum. Puisque nous avons calculé l’adresse Ethereum à la section 2.2, nous savons déjà quel doit être le résultat de cette équation. Ainsi, il est possible de tester les deux valeurs potentielles de v
pour déterminer laquelle est correcte.
Attention: En raison de la nature de la courbe elliptique utilisée dans ECDSA, deux solutions sont valides pour une signature donnée, correspondant aux aspects positif et négatif de la courbe. La valeur
v
est un identifiant de récupération qui aide à déterminer quelle moitié de la courbe a été utilisée pour la signature. Le mécanisme de validation des transactions sur Ethereum acceptera une seule des deux valeurs dev
. Il est donc parfois nécessaire de tester les deux valeurs potentielles pour déterminer laquelle est correcte.
5. Envoi d’une Transaction Ethereum
Vous êtes maintenant prêt à envoyer votre première transaction Ethereum signée via KMS.
Premièrement, concentrons-nous sur la préparation de la charge utile, comme mentionné dans la section 3.1. L’étape initiale consiste à créer une transaction Ethereum valide.
Une fois la transaction définie txData
, elle est hachée avec Keccak-256 pour créer un “digest”, qui est essentiellement une empreinte numérique de la transaction. Ce digest est ensuite transmis à notre fonction signDigest
.
Nous utiliserons la fonction
fromTxData
de la bibliothèque@ethereumjs/tx
, qui formate la transaction au format RLP. Pour une compréhension plus approfondie du mécanisme interne de ce processus, il est recommandé de consulter la documentation de la bibliothèque@ethereumjs/tx
.
Après la récupération de la signature du KMS signedDigest
, nous utilisons notre fonction decodeRS
pour extraire les valeurs r
et s
de la signature. En parallèle, nous employons notre fonction calculateV
pour déterminer la valeur correcte de v
pour notre signature Ethereum.
Enfin, nous utilisons la fonction fromTxData
pour obtenir le hash de la transaction signée.
En résumé, ce processus implique plusieurs étapes clés : la création et le hachage de la transaction, la signature du digest avec KMS, le décodage de la signature pour obtenir r
et s
, la détermination de v
, et enfin, l'utilisation de @ethereumjs/tx
pour finaliser et obtenir le hash de la transaction signée.
Si vous avez suivi toutes les étapes correctement et réussi à signer votre transaction avec votre provider KMS, félicitations ! C’est un accomplissement significatif, surtout si c’est votre première transaction de ce type.
6. Conclusion : Défis et Perspectives de l’Intégration des Signatures Ethereum dans les Solutions de Gestion de Clés Existantes
Bien qu’Ethereum utilise l’algorithme ECDSA secp256k1 pour les signatures, cela ne garantit pas une intégration transparente avec les solutions de gestion de clés existantes. Les particularités d’Ethereum, comme celles introduites par l’EIP-2 et d’autres normes spécifiques, imposent des exigences supplémentaires qui dépassent les protocoles standards de gestion de clés. Ces exigences nécessitent souvent des ajustements minutieux au niveau des octets, augmentant ainsi la complexité et le risque d’erreurs dans le développement de solutions compatibles.
Cette situation souligne un besoin croissant pour une meilleure harmonisation entre les technologies blockchain et les infrastructures de gestion de clés traditionnelles. À mesure que la blockchain gagne en popularité et en adoption dans le milieu des entreprises, la pression monte pour que les fournisseurs de cloud et les entreprises d’infrastructure soutiennent davantage les normes spécifiques à la blockchain.
En attendant, les ingénieurs spécialisés en blockchain jouent un rôle crucial en comblant ces lacunes. Ils le font en développant des bibliothèques et des outils qui facilitent l’interopérabilité entre les plateformes blockchain comme Ethereum et les systèmes de gestion de clés conventionnels. Ces efforts sont essentiels pour assurer une intégration sécurisée et efficace de la blockchain dans les environnements d’entreprise, ouvrant ainsi la voie à une adoption plus large de cette technologie prometteuse.
7. Github et npm package
Pour une compréhension plus approfondie et pour enrichir vos projets, envisagez d’explorer cette bibliothèque qui offre une implémentation complète et avancée de ces mécanismes :