C’est quoi une signature ?

Si vous avez lu l’article sur les checksums en javascript (https://www.lavachequicode.fr/calculer-un-checksum-en-javascript) Vous aurez compris qu’un checksum peut être créé par n’importe qui.

Si on l’ajoute à la fin d’un message on peut repérer si il y a eu une erreur pendant le transport. On dit qu’on assure  l’intégrité de la donnée. Cependant rien n’empêche un attaquant de modifier le message, puis de modifier le checksum.

La signature électronique en revanche est créé à l’aide d’une donnée secrète, elle ne peut être généré que par l’émetteur du message.

Elle assure donc l’authenticité d’un message, exactement comme une signature sur un document papier.

signature symétrique

Dans le cas d’un chiffrement symétrique, les deux personnes souhaitant échanger un message se partage secrètement une clé. L’émetteur va ensuite calculer la signature du message qu’il veut envoyer au récepteur grâce à la clé secrète et à la fonction de signature f:

s = f(m,k)

puis il transmet le couple (s,m).

le récepteur peut vérifier que le message est authentique  en recalculant f(m,k). Si le résultat est S, le message est authentique.

Ainsi un attaquant ne pourra plus modifier le message : il ne peut pas recalculer s sans connaitre la clé k. De plus, s’il modifie simplement m, le récepteur verra que la signature ne correspond pas au message (c’est l’objet de cet article).

Notez que la signature ne protège pas contre le rejeu. un attaquant pourra renvoyer le message à posteriori et le récepteur aura l’impression d’avoir reçu deux fois le même message (embêtant si il s’agit d’un transfert d’argent par exemple).

Pour éviter cela, on peut par exemple inclure un timestamp dans la signature:

si h = now(), on calcule s = f(h+m,k) et on envoie (h,m,k). Le récepteur saura alors quand le message à été signé.

On peut également maintenir un compteur que l’on incrémente à chaque message:

on calcule s = (i+m,k) et on envoie (m,k) car le récepteur connait le numéro du message à venir.

signature asymétrique

Dans le cas d’un algorithme de signature asymétrique, l’émetteur choisi une clé secrète k et il en déduit clé k_public à partir de laquelle il est impossible de retrouver k en un temps raisonnable. Il peut donc la partager publiquement.

Lorsqu’il souhaite émettre un message il va donc signer le message avec une fonction g

s = g(m, k)

puis il diffuse (s,m)

Tout le monde va ensuite pouvoir vérifier l’authenticité du message à l’aide de la fonction de vérification (appelons la v).

Il suffit de calculer v(m, k_public, s)

Les algorithmes

Nous allons nous intéressé ici au cas asymétrique.

Il existe deux principaux algorithmes :

RSA du nom de ses inventeurs :  Rivest-Shamir-Adleman.

ECDSA pour elyptic curve digital signature algorithm.

Et en Javascript, ça donne quoi ?

Nous allons voir ici comment vérifier une signature ECDSA ethereum en javascript.

 

Pour être précis, les messages dont nous souhaitons vérifier la signature sont hachés avec le hash Keccak256 (souvent appelé sha3) puis signés avec l’algorithme ECDSA suivant la courbe secp256k1.

En NodeJS

vous aurez besoin au préalable des librairies web3 et ethereumjs-util.
Pour une utilisation en back (node):

puis dans votre fichier index.js:

notez qu’il est tout à fait possible d’effectuer la même opération en front.

Dans un navigateur

 

Pour pouvoir utiliser la librairie ethereumjs-util en front, on peut utiliser browserify.

Pour que notre objet ethereumjs soit accessible à l’extérieur de browserify (depuis nos scripts natif) on crée le fichier suivant :

et on crée le bundle:

il suffit ensuite d’inclure bundle.js dans notre index.html :

Notez qu’il n’est pas forcement nécessaire de créer un nouvel objet web3, il est dans certain cas déjà présent (utilisation du plugin metamask par exemple).

On pourra simplement faire: