Comment hacker un portefeuille Bitcoin ?

J’imagine que vous êtes là pour apprendre et pour votre culture générale. Bien évidemment.
A la fin de cet article vous devriez comprendre ce slogan plutôt célèbre en crypto : Your keys, your coins. Not your keys, Not your coins.

Bon. Spoiler. Direct. Vous allez devoir être chanceux.
Très très très très très très chanceux. Ou malin et ingénieux. Ça peut passer.

Comment fonctionne un portefeuille Bitcoin ?

Pour savoir comment hacker, il faut déjà savoir comment ça fonctionne. C’est la base de ce qu’on pourrait appeler le ‘reverse engineering’.

Nous allons considérer que vous connaissez la Blockchain et son fonctionnement. Internet regorge de documents et d’informations à ce sujet. Ce sera peut être le sujet d’un prochain article. Un de plus voguant à travers les méandres d’Internet. Ou pas. Bref, Nous allons ici nous concentrer plus précisément sur les portefeuilles. L’ARGENT.

Elliptic Curve Digital Signature Algorithm

“Wooooow. C’est quoi ce truc compliqué ?”
Attends. Calme toi.

La blockchain est un registre financier public et distribué. C’est son principe même. Chaque portefeuille, ou compte, possède un identifiant public unique appelé adresse.

Ok super mais qu’est-ce qui empêche quelqu’un de transférer votre argent d’un compte à un autre alors que ce système est accessible par tous ?
Tout simplement votre clé privée. C’est cette clé, connue seulement de vous, qui permet de signer et de valider une transaction.

“Euh certes. Mais dans les faits comment ça ce passe ? Comment les mineurs peuvent ils vérifier que la signature est correcte alors que moi seul connait la clé ?”
J’y viens. On va rentrer dans le vif du sujet.

Protagonistes

Commençons par mettre en avant nos deux protagonistes. Ceux que vous rencontrerez dès qu’on parle sécurité et chiffrement.

Alice

A ma gauche vous avez Alice, 1.60m, “Bitcoin enthusiast”, mariée, sans enfants, toujours le mot pour rire.

Bob

Et à ma droite voici Bob, 1.59m, chef de chantier, marié, une fille, il se demande toujours pourquoi il a acheté une pizza pour 1000 Bitcoins.

Clé Privée

Comme nous venons d’en parler, tout repose sur cette fameuse clé privée. C’est elle qui vous donne les pleins droits sur votre portefeuille. Il s’agit tout simplement d’un nombre aléatoire de 256 bits. Comme celui-ci :

5368566D597133743677397A244326462948404D635166546A576E5A72347537

“Olala mais le mec n’y connait rien, c’est un scandale. C’est pas un nombre ça, il y a des lettres et tout.”
Chuuut, doucement. C’est en notation hexadécimale. Si tu ne sais pas ce que c’est n’hésite pas à te renseigner.

C’est à partir de ce nombre, qui est donc votre clé privée, qu’est généré votre clé publique. Et c’est là qu’entre en scène l’Elliptic Curve Digital Signature Algorithm (ou ECDSA).

Clé Publique

Je ne vais pas vous faire un cours de Mathématiques avancées. Si vous souhaitez en comprendre les méandres et les détails les plus fins je ne vous invite que trop à faire vos propres recherches. Le net abonde de ressources à ce sujet. Comme à peu près tout d’ailleurs.

L’ECDSA est quelque chose de puissant. Comme beaucoup d’algorithmes à chiffrement asymétrique qui existent de nos jours. Il va permettre de générer un nombre dérivé de votre clé privée avec des caractéristiques fondamentales remarquables.

Oui j’emploie des mots forts en couleur mais c’est pour bien vous imprégner du concept.

Ce nombre dérivé de votre clé privée correspondra donc à votre clé publique.

Première caractéristique : Il s’agit d’une opération à sens unique. Vous pouvez dériver le plus “simplement” du monde votre clé privée pour obtenir votre clé publique. Mais il est impossible de retrouver la clé privée à partir de la clé publique. Votre clé publique peut donc être partagée à travers le réseau dans la plus grande quiétude.

C’est une des caractéristiques des fonctions de hash tels que md5 ou sha que vous connaissez peut être. Le md5 du mot ‘hello’ vous donnera comme résultat : 5D41402ABC4B2A76B9719D911017C592. Vous obtiendrez toujours ce résultat mais il vous sera impossible de réaliser l’opération inverse.
Vous pouvez vous amuser à en générer sur ce site : https://passwordsgenerator.net/md5-hash-generator/

Deuxième caractéristique : Votre clé publique permet de valider un message signé à l’aide de votre clé privée. Cependant il sera impossible de valider ce même message si vous le signez avec la clé publique.

On a donc la capacité d’affirmer la provenance d’un message sans pour autant pouvoir ni le reproduire ni le falsifier.

Ces deux caractéristiques ont l’air prometteuses ! Surtout quand on parle d’un système publique et distribué. Appliquons tout ça au Bitcoin.

Exemple d’une Transaction

Revenons à nos protagonistes.

Alice veut transférer une partie de ses Bitcoins à Bob pour payer sa maison. Ils possèdent tous les 2 un portefeuille Bitcoin et sont identifiés sur le réseau par leur adresse.

Il ne faut pas confondre clé publique et adresse. L’adresse est dérivée de la clé publique. Un détail qui a son importance comme nous le verrons dans la suite. Je vous épargne les détails techniques pour le moment.

Alice
Alice

Adresse : 1234

Bob
Bob

Adresse : 5678

Alice et Bob sont donc connus respectivement sur le réseau comme étant ‘1234‘ et ‘5678‘.

Pour transférer des Bitcoins de son compte vers celui de Bob, Alice doit créer et envoyer une transaction.

Cette transaction est composée de plusieurs éléments dont la clé publique d’Alice et bien évidemment la somme à transférer ainsi que l’adresse publique du destinataire. Elle est ensuite signée numériquement grâce à la clé privée d’Alice.

Le tout est envoyé au réseau, constitué notamment de mineurs qui vérifieront la conformité de la transaction. D’une part en validant, via la clé publique d’Alice, que la signature est correct. Mais également que le montant à transférer est présent sur le portefeuille d’Alice.

Si tout est valide, la transaction est ajoutée à la Blockchain de manière définitive. Une transaction est immuable.

“Ok cool c’est bien beau tout ça mais on n’est pas un peu sorti du but premier de l’article ? Si on ne peut pas trouver la clé privée à partir de la clé publique on ne peut rien faire. Aucun moyen de dépenser l’argent d’Alice à sa place. Tu nous a menti. On te déteste. Elle va pouvoir acheter sa maison tranquille.”

Et bien oui. Et non. Venons en au fait.

Hacker le portefeuille d’Alice

Comme nous venons de le voir, tout repose sur l’ECDSA et la clé privée d’Alice. Donc comment faire pour hacker son portefeuille ?

Trois solutions :

  1. Regarder par dessus son épaule au moment où elle génère la transaction et recopier sa clé privée.
  2. Trouver une vulnérabilité au niveau de l’ECDSA.
  3. Attaquer par force brute

Espionnage et piratage

La première solution n’est clairement pas irréaliste. Mais pas comme vous êtes en train de l’imaginer. Marchant sur la pointe des pieds derrière Alice et attendant ce moment fatidique où elle ouvrira son ordinateur. Ne se doutant de rien elle affichera sa clé privée et vous, votre crayon en main, n’en perdrez pas une miette.

Non, pas comme ça. Quoique…

En fait, beaucoup de personnes, vous inclut, ne connaissent pas leurs clés privées. Pour la simple et bonne raison que les plateformes d’échanges et une bonne partie des portefeuilles en ligne vous permettent de faire abstraction de tout cet aspect. Pour en simplifier grandement l’utilisation.

Ce sont eux qui détiennent vos clés privées et les génèrent à la création de votre compte. Compte pouvant être bien plus vulnérable que vous ne le pensez. Notamment à cause d’un mot de passe apportant une trop faible sécurité. Ou bien d’une faille exploitable sur la plateforme que vous utilisez.

Ça y est ? Vous le voyez venir ?

Your keys, your coins. Not your keys, Not your coins.

Vulnérabilité au niveau de l’ECDSA

La deuxième solution est peu probable mais toujours possible. Il est déjà arrivé par le passé qu’un algorithme de chiffrement devienne complètement obsolète après la découverte d’une faille dans sa conception. Les algorithmes de cryptographie ne sont pas créés par des développeurs mais par des Mathématiciens. Ils se basent sur des théories Mathématiques extrêmement avancées et solides. Si vous voulez créer votre petit algorithme de chiffrement dans votre coin, je peux vous affirmer à 100% qu’il sera hacké en moins de temps qu’il vous aura fallu pour le concevoir.

Donc dans le cas où cette deuxième solution serait possible. Sachez que beaucoup de personnes bien plus qualifiées que vous ont déjà tentés de démolir l’ECDSA pour justement s’assurer de sa robustesse.

Force Brute

Nous voici à la troisième solution. La force brute. Méthode utilisée entre autre pour casser des mots de passe. C’est celle-ci qui nous intéresse. Installez vous confortablement. Nous allons jouer.

Règles du jeu

Les règles sont simples. Vous savez, à présent, que toutes les clés privées utilisées sur le réseau Bitcoin sont des nombres aléatoires. Certes, très grands. Mais ça n’en reste pas moins des nombres aléatoires.

Comme nous l’avons vu, une clé privée est composé de 256 bits. Et vous devez savoir, du moins je l’espère, qu’un ordinateur est codé en binaire. Ce qui nous donne donc un nombre total de clés privées possibles égale à 2^256.

C’est beaucoup. Vraiment beaucoup. Si vous voulez un ordre d’idée, c’est un peu moins que le nombre estimé d’atomes dans l’univers. Cet article est d’ailleurs très intéressant : https://waitbutwhy.com/2014/11/1000000-grahams-number.html

Mais vous pouvez être rassuré car, concernant le Bitcoin, l’adresse ne correspond pas exactement à la clé publique. En effet, pour obtenir l’adresse, chaque clé publique est hashée en utilisant l’algorithme RIPEMD-160. Comme son nom l’indique, cet algorithme de hashage produit une signature de 160 bits à partir de notre clé publique.

Ce n’est pas la seule transformation que subit votre clé publique pour devenir votre adresse mais le reste nous intéresse moins. Si vous voulez le détail passez par ici : https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses

Comme vous pouvez vous en douter cette réduction n’est pas sans conséquences. L’espace de clés se trouvant fortement réduit, passant de 2^256 à 2^160, implique un risque de collisions. C’est à dire que plusieurs clés publiques, et donc privées, pointent vers la même adresse Bitcoin.

Si on prend on considération ces collisions, une adresse correspond à 2^(256-160) = 2^96 clés privées. 2^96 clés privées peuvent mener à la même adresse. Ça parait fou ? Oui mais en fait ça ne l’est pas tant que ça.

Sortons la calculatrice

Ça ne l’est pas tant que ça car un espace de 2^160 clés est toujours hors normes.

Prenons le hash rate actuel du Bitcoin (juillet 2019) : 70 Th/s. Multiplions le par un milliard : 70 x 10^9 soit ‭‭70 000 000 000 000 000 000 000‬ h/s.
On va considérer qu’il s’agisse du nombre de clés que vous générez par seconde. Pas trop mal comme puissance de calcul. Prévoyez d’acheter quelques centrales nucléaires pour alimenter tout ça.

Il vous faudra ‭‭20 878 594 819 012 898 831 481 211‬ secondes pour trouver toutes les clés. Ce qui correspond à 66 x 10^16 ans. C’est tout simplement l’age de l’univers.

Ça calme.

Je vous vois, vous recommencez à crier au scandale. Mais rappelez vous. Vous devez être soit très chanceux. Soit malin.

En effet de nombreux comptes se sont fait piller par des gens malins.

Le cas des Brainwallets

Vous en avez peut être entendu parlé. Le principe des Brainwallets est simple. La création de votre clé privée repose sur une passphrase, ou phrase secrète en français. Celle-ci peut être composée d’un ou plusieurs mots, de différents caractères, etc. C’est vous qui choisissez. Comme pour votre mot de passe. Le même que vous utilisez sur tous les sites.

Une fois que vous avez choisi votre phrase secrète, celle-ci est hashée en utilisant l’algorithme sha256 et devient votre clé privée.

Exemple : J’ai cru pouvoir hacker un portefeuille Bitcoin
Devient : ca0059995487ea40029b8728f1fc25bc992dcf1e32e5d7b3fc70333800ab6db8

Le point faible est évident non ? C’est le même que pour les mots de passe.

Oui, c’est la simplicité des phrases secrètes choisies par les utilisateurs. Beaucoup de personnes avaient utilisées un ou quelques mots du dictionnaire. Qu’est ce qu’il s’est passé ? Attaque par force brute en prenant le Collins et le Petit Larousse.

Résultat : entre 2013 et 2014 ce fut une hécatombe. Presque 20 000 comptes Bitcoin ont été hackés.

Un jeu d’enfants.

Vous voyez, finalement, il y a toujours une opportunité. Tout est possible.

Vous maîtrisez l’ensemble des règles à présent. Il est l’heure de jouer.

Application

Nous allons voir de manière très succincte comment générer une clé privée et une addresse en Python. Si vous n’y connaissez rien en développement Python ce n’est clairement pas ici que vous allez apprendre.

On va avoir besoin de quelques librairies et de quelques fonctions utilitaires :

import binascii
import hashlib
import base58
import ecdsa

def hex_to_string(value):
    return str(binascii.hexlify(value), "ascii")


def string_to_hex(value):
    return bytearray.fromhex(value)


def sha256(data):
    sha256_hash = hashlib.sha256()
    sha256_hash.update(data)
    return sha256_hash.digest()


def ripemd160(data):
    ripemd160_hash = hashlib.new('ripemd160')
    ripemd160_hash.update(data)
    return ripemd160_hash.digest()
  • hex_to_string : Permet de convertir une valeur hexadécimale en string
  • string_to_hex : On fait l’inverse, on convertit une string en valeur hexadécimale
  • sha256 : Retourne le hash sha256 d’une valeur
  • ripemd160 : Retourne le hash ripemd160 d’une valeur

Impeccable, commençons par générer notre clé privée.

Clé privée

Nous avons vu qu’il est quasi impossible de tomber sur une clé privée déjà utilisée. Tentons notre chance en se basant sur une phrase secrète : “Hello this is my private key”. Rien ne vous empêche de faire de même avec l’intégralité du dictionnaire. Ou avec des dates, un nombre que vous incrémentez, etc, etc.

Il faut savoir que l’aléatoire n’existe pas en informatique. Il n’y a rien de plus déterministe qu’un ordinateur. Si vous connaissez l’état complet n d’un ordinateur, il est théoriquement possible d’en déduire son état n+1. L’aléatoire est simulé. Pour réellement générer de l’aléatoire, il est nécessaire d’apporter des éléments extérieurs qui vont venir perturber le système. Les logiciels de sécurité utilisent par exemple les mouvements de votre souris.

En conséquence si vous connaissez l’état complet d’un ordinateur au moment où il a généré une clé privée. Il est théoriquement possible de pouvoir re-générer cette même clé. Oui je m’avance un peu. Mais on l’a dit. Soyez malin.

Revenons en à notre clé privée :

# Generate private key from a passphrase
passphrase = "Hello this is my private key"
private_key = sha256(passphrase.encode('utf-8'))
print("Private Key : " + hex_to_string(private_key))

Oui c’est tout. On fait un hash sha256 de notre phrase secrète et c’est bon. Passons à la clé publique.

Clé publique

Pour ce faire, on se base donc sur l’ECDSA afin de dériver notre clé privée et d’obtenir notre clé publique non compressée :

UNCOMPRESSED_KEY_FLAG = '04'

# Get ECDSA public key
signing_key = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1)
verifying_key = signing_key.get_verifying_key()
uncompressed_public_key = UNCOMPRESSED_KEY_FLAG + hex_to_string(verifying_key.to_string())

Une clé publique non compressée est préfixée par ’04’ pour pouvoir l’identifier. Le réseau Bitcoin n’utilise plus ce type de clé publique mais la version compressée. Pour des raisons d’économie d’espace disque évidentes. C’est parti on compresse :

public_key = compress_public_key(uncompressed_public_key)

def compress_public_key(key):
    if ord(bytearray.fromhex(key[-2:])) % 2 == 0:
        compressed_public_key = '02'
    else:
        compressed_public_key = '03'
    compressed_public_key += key[2:66]
    return compressed_public_key

Nous avons alors deux versions de notre clé publique à partir desquelles nous pouvons générer deux adresses différentes. Une clé privée correspond donc potentiellement sur le réseau à 2 clés publiques et à 2 adresses différentes. Mais ici nous allons ignorer la version non compressée car elle ne présente plus vraiment d’intérêt.

Adresse

Pour savoir si on a trouvé le sésame d’un portefeuille avec des dizaines de Bitcoins, il nous faut l’adresse pour en vérifier le solde.

On prend les spécifications techniques : https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses

Et on applique les transformations à la clé publique :

MAIN_NETWORK_FLAG = '00'

def generate_address(public_key):
    address = string_to_hex(public_key)

    # Step 1 : Perform sha256
    address = sha256(address)

    # Step 2 : Perform ripemd160 and add prefix '00'
    address = string_to_hex(MAIN_NETWORK_FLAG + hex_to_string(ripemd160(address)))

    # Step 3 : Perform sha256 twice and get checksum
    checksum = sha256(sha256(address))[:4]

    # Step 4 : Append checksum to address
    address = address + checksum

    # Step 5 : Convert into base58
    address = base58.b58encode(bytes(address)).decode('utf-8')

    return address

Etape 1 : Hash sha256 de la clé publique
Etape 2 : Hash ripemd160 et on ajoute comme préfixe ’00’ qui est l’identifiant du réseau Bitcoin principal
Etape 3 : On prend le résultat, on effectue deux fois le Hash sha256 et on prend les 4 premiers bytes qui constitueront le checksum
Etape 4 : On reprend la valeur obtenue à l’étape 2 avec le ripemd160 et on concatène le checksum obtenu à l’étape 3
Etape 5 : On convertit le tout en base58

C’est terminé ! Vous êtes en capacité de générer une clé privée, une clé publique et l’adresse du portefeuille.

Code complet

Voici le code en intégralité :

import binascii
import hashlib

import base58
import ecdsa

UNCOMPRESSED_KEY_FLAG = '04'
MAIN_NETWORK_FLAG = '00'


def hex_to_string(value):
    return str(binascii.hexlify(value), "ascii")


def string_to_hex(value):
    return bytearray.fromhex(value)


def sha256(data):
    sha256_hash = hashlib.sha256()
    sha256_hash.update(data)
    return sha256_hash.digest()


def ripemd160(data):
    ripemd160_hash = hashlib.new('ripemd160')
    ripemd160_hash.update(data)
    return ripemd160_hash.digest()


def generate_public_key(private_key):
    # Get ECDSA public key
    signing_key = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1)
    verifying_key = signing_key.get_verifying_key()
    uncompressed_public_key = UNCOMPRESSED_KEY_FLAG + hex_to_string(verifying_key.to_string())
    # Compress the public key
    public_key = compress_public_key(uncompressed_public_key)
    return public_key


def compress_public_key(key):
    if ord(bytearray.fromhex(key[-2:])) % 2 == 0:
        compressed_public_key = '02'
    else:
        compressed_public_key = '03'
    compressed_public_key += key[2:66]
    return compressed_public_key


def generate_address(public_key):
    address = string_to_hex(public_key)

    # Step 1 : Perform sha256
    address = sha256(address)

    # Step 2 : Perform ripemd160 and add prefix '00'
    address = string_to_hex(MAIN_NETWORK_FLAG + hex_to_string(ripemd160(address)))

    # Step 3 : Perform sha256 twice and get checksum
    checksum = sha256(sha256(address))[:4]

    # Step 4 : Append checksum to address
    address = address + checksum

    # Step 5 : Convert into base58
    address = base58.b58encode(bytes(address)).decode('utf-8')

    return address


if __name__ == '__main__':
    # Generate private key from a passphrase
    passphrase = "Hello this is my private key"
    private_key = sha256(passphrase.encode('utf-8'))
    print("Private Key : " + hex_to_string(private_key))

    # Generate public key from private_key
    public_key = generate_public_key(private_key)
    print("Public Key : " + public_key)

    # Generate Address
    address = generate_address(public_key)
    print("Address : " + address)

Le résultat est le suivant :

Private Key : d5762f10975dd96b48bea9401dbe63d6af07709373933564ee1d4e33014db5f5
Public Key : 02b61051bf856e45b397bd34baa72d63dc889f07ba81df117bd77792da5b8a2242
Address : 18HiwtuvHfWq2C5jHzAXLM4i7onmYkqEXE

Vous pouvez facilement vérifier le solde d’une adresse à l’aide de cette URL :
https://www.blockchain.com/fr/btc/address/18HiwtuvHfWq2C5jHzAXLM4i7onmYkqEXE
Le dernier paramètre de l’URL correspond à l’adresse générée.

Voilà, automatisez la vérification du solde d’une adresse, faites ça en boucle 2^256 fois et vous êtes riche. Et possiblement en prison.

Conclusion

La probabilité d’arriver à hacker un portefeuille Bitcoin par force brute est si faible qu’il est donc théoriquement impossible de le faire.

La sécurité du Bitcoin pourrait être mise à mal si on découvre une faille de conception de l’ECDSA ou avec l’apparition des ordinateurs quantique. Mais on en est encore loin et rien ne dit que passer en revue 2^256 clés avec un ordinateur quantique ne prenne pas non plus des dizaines, voire des centaines, d’années.

Il reste cette bonne vieille erreur humaine.

En espérant que cet article vous a plu et vous a été utile !

Lâchez un don pour en apprendre toujours plus.

3 Replies to “Comment hacker un portefeuille Bitcoin ?”

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *