Aller au contenu

Version complète du protocole de Diffie-Hellman⚓︎

Gérer des messages plus grands

Le problème de la version précédente, c'est qu'avec une clef de 1024 bits, le texte ne peut pas dépasser 128 caractères. Pour palier cela, il faut découper le texte en plusieurs morceaux et les chiffrer indépendamment. On convertit le texte en binaire, que l'on découpe en blocs de 512 bits (ou la moitié de la longueur de la clef). Le dernier bloc peut être plus petit. Pour chacun des blocs, on complète les 512 bits manquants de la manière suivante :

  • On rajoute un octet à gauche correspondant au nombre d'octets du message d'origine (512 bits = 64 octets).
  • On complète entre cet octet et ceux du messages avec des bits tirés au hasard.

Puisque le premier octet vaut au maximum 64, le premier bit est forcément 0, ce qui garantit que le bloc obtenu est inférieur à la clef. L'ajout de bits aléatoires permet d'assurer que si deux blocs du messages sont identiques, leurs chiffrements seront différents.

Le padding

Le fait d'ajouter des bits aléatoires à des données pour obtenir un bloc d'une taille donnée s'appelle le padding (ou remplissage en français). La fonction suivante permet d'effectuer cette opération, avec binaire qui est un morceau du message dont la longueur est inférieure ou égale à 512 bits.

La fonction de remplissage
def padding(binaire, taille_bloc=1024):
    reste = taille_bloc - len(binaire)
    nb_octets = len(binaire) // 8  # il faut que ce soit un multiple de 8
    tete = entier_binaire(nb_octets)
    padd = "".join([random.choice("01") for _ in range(reste-8)])
    return tete + padd + binaire

Chacun des blocs peut alors être chiffré avec la clef, ce qui produira des blocs de 1024 bits qui peuvent être recollés.

Pour enlever le padding, il faut regarder le premier octet pour savoir combien d'octets garder à la fin. La fonction suivante permet de faire cette dernière opération :

Pour enlever le remplissage
def enleve_padding(bloc):
    tete = bloc[:8]
    nb_octets = binaire_entier(tete)
    return bloc[len(bloc)-8*nb_octets:]
La nouvelle fonction de chiffrement

Pour chiffrer un texte, on chiffre donc le padding de chaque morceau du texte.

La fonction de chiffrement
import math 

def chiffrement(texte, clef, p, taille=1024):
    binaire = texte_binaire(texte)
    taille2 = taille//2
    n = math.ceil(len(binaire)/taille2) # on arrondit au dessus
    final = ""
    for i in range(n):
        bloc = binaire[i*taille2:(i+1)*taille2]
        nb = binaire_entier(padding(bloc, taille))
        nb2 = (nb * clef) % p
        final = final + entier_binaire(nb2, taille)
    return final
La nouvelle fonction de déchiffrement

Pour déchiffer, il faut découper le message chiffré en blocs de 1024 bits, le déchiffrer avec l'inverse de la clef puis le reconvertir en binaire, qui correspond au padding, qu'on retire. Il suffit de recoller les blocs pour retrouver le message original.

La fonction de déchiffrement
def dechiffrement(binaire, clef, p, taille=1024):
    inv = inverse(clef, p)
    n = len(binaire)//taille
    final = ""
    for i in range(n):
        bloc = binaire[i*taille:(i+1)*taille]
        nb = binaire_entier(bloc)
        nb2 = nb * inv % p
        bloc2 = entier_binaire(nb2, taille)
        final = final + enleve_padding(bloc2)
    return binaire_texte(final)
Exercice 24

Tester les fonctions de chiffrement et de déchiffrement avec des messages longs. Si vous n'avez pas d'idées, vous pouvez, par exemple, prendre des choses comme "bonjour "*200

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : /∞

Pour aller plus loin

Le fichier client_dh.py permet d'échanger des messages sur le réseau en utilisant un échange de clef de Diffie-Hellman. L'ordinateur qui reçoit les messages doit utiliser l'instruction serveur().

Pour envoyer un message, il faut utiliser l'instruction envoyer(message, ip), où ip est un texte correspondant à l'adresse IP du serveur.