L'algorithme ElGamal est un algorithme de cryptographie asymétrique basé sur les logarithmes discrets. Il a été créé par Taher Elgamal.
Cet algorithme est utilisé par le logiciel libre GNU Privacy Guard, de récentes versions de PGP, et d'autres systèmes de chiffrement, et n'a jamais été sous la protection d'un brevet contrairement à RSA.
Il peut être utilisé pour le chiffrement et la signature électronique. L'algorithme DSA du NIST est basé sur ElGamal.
Il est facile de transformer la technique d'échange de clé selon Diffie et Hellman, en un système de cryptographie à clé publique : c'est la méthode d'El Gamal.
Voici comment Bob peut envoyer un message chiffré à Alice (avec la clé publique d'Alice)...
Alice déchiffre $c$ pour obtenir $m$, de la façon suivante : $m = \left( B^{p-1-a} \times c \right) %p$
En effet, on a : $B^{p-1-a} c \equiv g^{b(p-1-a)}g^{ab}m \equiv g^{b(p-1)}m \equiv m % p$ car $g^{p-1} = 1 %p$ : valable pour toute racine primitive modulo $p$.
Notons que, pour transmettre le message $m$, qu'il a chiffré en $c$, Bob est conduit à transmettre le couple ($B$,$c$), message approximativement deux fois plus long que $m$.
Plusieurs possibilités pour obtenir un nombre premier :
On peut, déjà, chercher des valeurs déjà calculées sur Internet.
On peut aussi ne pas être fin : tester chacune des valeurs de 2 à $p-1$, jusqu'à obtenir une racine primitive (voir le précédent TP, pour savoir de quoi il s'agit).
On peut encore utiliser cette méthode...
$ m^{\phi(p)/p_i} % p$ pour $i=1, \ldots, k$, en utilisant l'exponentiation rapide.
Dès que nous trouvons un nombre $m$ pour lequel ces $k$ valeurs sont toutes différentes de 1, nous stoppons : $m$ est une racine primitive.
Pour obtenir les facteurs premiers de $n$, on pourra par exemple utiliser le bout de code suivant :
>>> def facteur(n): ... if n==1: ... return set([]) ... else: ... for k in range(2,n+1): ... if n%k == 0: ... L = facteur(n/k) ... return L.union([k]) ... >>> list(facteur(100)) [2, 5]
Voici, ci-dessous, les fonctions nécessaires à El Gamal.
Tout d'abord, la fonction qui, à partir du nombre premier $p$, de la racine primitive $g$, et de l'entier $a$ choisi dans $\{1, ..., p-1\}$ renvoie le couple clé publique, clé privée ($= a$)...
>>> def cles(p,g,a): ... A = g**a%p ... publique = (p,g,A) ... prive = a ... return (publique, prive) ...
Alice doit utiliser cette fonction pour générer sa clé publique $A$, à envoyer à Bob : ce dernier l'utilisera pour envoyer un message chiffré à Alice.
Si Alice souhaite envoyer un message chiffré à Bob, ce dernier devra lui-aussi faire appel à la fonction cles pour envoyer une clé publique à Alice.
Passons au chiffrement :
>>> def chiffre(message, publique, b): ... (p,g,A) = publique ... B = g**b%p ... c = message*A**b%p ... return (B, c) ...
Ci-dessus, message est le nombre à chiffrer, avec la clé publique publique, et la clé privée b choisie.
Il reste à déchiffrer :
>>> def dechiffre(cryptogramme, publique, prive): ... (p,g,A), a = publique, prive ... (B,c) = cryptogramme ... return B**(p-1-a)*c%p ...
Programmez le chiffrement d'El Gamal au complet.
On proposera à l'utilisateur de générer la clé, de chiffrer un texte ou de le déchiffrer.