Archi Chiffrement

Identification

Infoforall

11 - Chiffrement symétrique


Nous avons vu qu'Internet utilise principalement deux protocoles :

  1. le protocole IP gère l'identification des machines et des réseaux. Grace à lui, on peut ainsi savoir si deux machines sont sur le même réseau, ou pas et on peut identifier clairement une machine précise sur un réseau, avec son adresse ... IP.
  2. le protocole TCP gère l'acheminement des paquets IP :
    • Il est chargé d'identifier les programmes sur un ordinateur en leur attribuant des adresses nommées ... PORTS
    • Il est chargé de découper les communications des programmes en les découpant en petits segments qui formeront autant de petits paquets IP. De cette façon, plusieurs programmes peuvent utiliser la carte réseau sans la monopoliser le temps de leurs commmunications.
    • Il est chargé de vérifier que les paquets envoyés ont bien été suivi d'une réception d'un accusé de réception. Si ce n'est pas le cas, un mécanisme se charge de renvoyer les paquets ou de couper la communication.
    • Il est chargé d'optimiser la vitesse de transmission entre les deux machines

Nous avons vu que le Web utilise principalement deux protocoles :

  1. le protocole HTTP où les paquets IP transitent de routeurs en routeurs en clair. N'importe qui possèdant des droits sur les routeurs peut lire la communication s'il en a envie du coup... Pas terrible pour les transmissions sensibles comme les mots de passe ou les numéros de carte banquaire.
  2. le protocole HTTPS où les paquets IP transitent de routeurs en routeurs en étant chiffrés, cryptés. Cette fois, même en étant interceptés, les paquets IP ne peuvent pas être compris. Ils peuvent être lus mais leurs contenus semblera totalement aléatoire et incompréhensible.

Nous allons nous intéresser à ces techniques de chiffrement.

Evaluation ✎ : -

Documents de cours :

1 - Le code de César

Le code de César n'est pas utilisé pour crypter les communications. Il est beaucoup trop simple à déchiffrer une fois qu'on connaît le principe.

Cette technique est basée sur un simple décalage des lettres.

Par exemple, on décalage les lettres de 1 position vers la droite.

A devient B, B devient C... jusqu'à Z qui devient ... A.

Pourquoi César ?

César aurait utilisé un tel cryptage pour sa correspondance.

Il utilisait un décalage de 3 lettres vers la droite en utilisant l'alphabet ... grec. Deux niveaux de difficultés pour les gens qui cherchaient à intercepter ses courriers.

Appliqué à notre alphabet, le décalage de 3 lettres de César donne ceci :

César

Commençons par voir comment nous pourrions décaler les lettres simplement avec un tableau contenant notre séquence de lettres.

01° Créer la fonction trouveIndex dont voici le prototype :

1
trouveIndex(element:str, sequence:str) -> int

Votre fonction devra renvoyer l'index de l'élément dans le tableau. Si plusieurs éléments identiques se trouvent dans le tableau, on renvoie le plus petit.

Exemple avec le tableau ALPHABET que vous pouvez visualiser en ligne 1.

>>> trouveIndex('B', ALPHABET) 1

Principe de l'algorithme : pour chaque valeur d'index, lire l'élément correspondant. S'il correspond à l'élement cherché, on renvoie l'index actuel.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
ALPHABET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] def trouveIndex(element, sequence) : '''Renvoie l'index de element dans le tableau sequence :: param element(divers) :: l'élément qu'on cherche à trouver :: param sequence(list) :: un tableau contenant des éléments :: return (int) :: l'index de l'élément (ou None) >>> lettres = ['A', 'B', 'C', 'D', 'E', 'F'] >>> trouveIndex('A', lettres) 0 >>> trouveIndex('C', lettres) 2 >>> trouveIndex('Z', lettres) ''' pass if __name__ == '__main__' : import doctest doctest.testmod()

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
ALPHABET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] def trouveIndex(element, sequence) : '''Renvoie l'index de element dans le tableau sequence :: param element(divers) :: l'élément qu'on cherche à trouver :: param sequence(list) :: un tableau contenant des éléments :: return (int) :: l'index de l'élément (ou None) >>> lettres = ['A', 'B', 'C', 'D', 'E', 'F'] >>> trouveIndex('A', lettres) 0 >>> trouveIndex('C', lettres) 2 >>> trouveIndex('Z', lettres) ''' for index in range(len(sequence)) : if sequence[index] == element : return index if __name__ == '__main__' : import doctest doctest.testmod()

Comme la recherche d'un élément dans un tableau est une chose courante et que les tableaux sont gérés sous forme d'objets avec Python, il existe déjà une méthode qui fait ce que nous venons de coder... Le but de la NSI est néanmoins de parvenir à construire vos propres fonctions avant d'utiliser trop de fonctions créées par d'autres personnes.

02° Tester les instructions suivantes pour vous persuader que la méthode index permet de faire (presque) la même chose que la fonction que nous venons de construire. Attention, ALPHABET devra être en mémoire lors de ce test.

>>> ALPHABET.index('A') 0 >>> ALPHABET.index('B') 1 >>> ALPHABET.index('Z') 25 >>> ALPHABET.index('a')

Question : avez-vous trouvé la différence qui existe entre cette façon de faire et la fonction que nous avions conçue ?

On pourrait écrire ceci et l'utilisateur ne se rendrait compte de rien : l'interface reste la même et les deux versions de la version réagissent exactement de la même facon !

1 2 3 4 5 6 7 8 9 10
def trouveIndex(element, sequence) : '''Renvoie l'index de element dans le tableau sequence''' if element in sequence : return sequence.index(element) def trouveIndex(element, sequence) : '''Renvoie l'index de element dans le tableau sequence ''' for index in range(len(sequence)) : if sequence[index] == element : return index

Une fois qu'on a trouvé l'index de la lettre dans l'alphabet, il suffit de rajouter la clé et on obtient alors le cryptage qui remplace cette lettre.

Ainsi l'index de B est 1. On rajoute 3 et on obtient ainsi l'index 4. Il suffit de renvoyer la lettre située à cet index : E.

Comme nous allons toujours travailler à priori avec le tableau constant ALPHABET, j'ai rajouté ,en ligne 1 ci-dessous, cette valeur par défaut à ce paramètre. Cela nous évitera de le fournir à chaque fois.

03° Tester maintenant la fonction decale qui renvoie une lettre présente dans alphabet en la décalant de cle position vers la droite.

1 2 3 4 5
def decale(element, cle, sequence=ALPHABET) : '''Renvoie la lettre cryptant la lettre element en décalant de cle case vers la droite''' index = trouveIndex(element, sequence) new_index = index + cle return sequence[new_index]

Vous pourriez tester des appels comme ceux-ci :

>>> decale(element='A', cle=3) >>> decale(element='B', cle=3) >>> decale(element='C', cle=3) >>> decale(element='W', cle=3) >>> decale(element='X', cle=3)

Qu'est-ce qui provoque l'erreur qui survient parfois ?

...CORRECTION...

La fonction semble bien fonctionner sauf pour X et plus...

Pourquoi ? Simplement car l'index de X vaut 23. Or 23 + 3 = 26.

Notre tableau n'ayant des index valides que dans l'intervalle [0, 25], les lettres X, Y et Z provoquent une demande hors index.

Pour éviter ce problème, il faut parvenir à faire comprendre à la machine qu'après l'index 25, on veut l'index 0.

Ainsi, si on obtient l'index 23 du 'X' et qu'on rajoute 3, on obtient 26 mais on veut en réalité obtenir 0 pour 'A'.

Pour 'Y' (24), on obtient 24+3=27 mais on veut 'B' (index 1).

Comment faire ? Utiliser le modulo !

Rappel :

>>> 24 % 26 24 >>> 25 % 26 25 >>> 26 % 26 0 >>> 27 % 26 1 >>> 28 % 26 2

04° Modifier decale pour qu'elle gère bien les recherches dépassant l'index maximum.

>>> decale(element='W', cle=3) 'Z' >>> decale(element='X', cle=3) 'A' >>> decale(element='Y', cle=3) 'B'

...CORRECTION...

1 2 3 4 5
def decale(element, cle, sequence=ALPHABET) : '''Renvoie la lettre cryptant la lettre element en décalant de cle case vers la droite''' index = trouveIndex(element, sequence) new_index = (index + cle) % len(sequence) return sequence[new_index]

Le problème du code de César est qu'il ne gère pas tous les caractères : on ne travaille qu'avec des lettres majuscules non accentuées ou autres. On acceptera certains caractères de ponctuation qu'on ne modifiera pas d'ailleurs.

05° Expliquer de la façon la plus précise possible comment fonctionne la fonction filtre. On rappelle que le string est en Python une structure de données non mutable et qu'on doit donc recréer un string lorsqu'on veut en "modifier" un.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# Constantes ALPHABET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] PONCTUATION = [' ', '.', '!', '?', ',', "'", ' '] # Déclaration des fonctions def filtre(message:str) -> str : '''Renvoie un string où les lettres sont toutes en majuscules''' message = message.upper() # Méthode des strings qui renvoie les lettres en majuscules reponse = '' # on va créer un string de réponse progressivement : on l'initialise for caractere in message : if caractere in ALPHABET or caractere in PONCTUATION : reponse = reponse + caractere # on ne le garde que s'il fait partie d'un des 2 tableaux return reponse # Programme principal if __name__ == '__main__' : message = "L'épreuve est au mois de mars, vraiment ?"

Expliquer ensuite pourquoi on obtient la réponse suivante en lançant la fonction avec la variable message.

>>> message "L'épreuve est au mois de mars, vraiment ?" >>> mess_filtre = filtre(message) >>> mess_filtre "L'PREUVE EST AU MOIS DE MARS, VRAIMENT ?"

Nous allons maintenant nous intéresser au cryptage de la chaîne de caractères filtrée qui ne contient donc que des caractères compatibles avec la fonction cryptage.

Voici le code du projet en l'état. Il reprend les fonctions réalisées plus haut (trouveIndex, decale et filtre) mais rajoute la fonction cryptage qui va permettre d'agir sur toute une chaîne de caractère, pas uniquement sur un seul caractère à la fois.

Pour gagner quelques lignes, j'ai décidé d'utiliser la forme de documentation courte pour les trois fonctions déjà étudiées.

06° Mettre le code ci-dessous en mémoire. Utiliser les instructions suivantes pour visualiser son fonctionnement.

>>> message "L'épreuve est au mois de mars, vraiment ?" >>> message = filtre(message) >>> message "L'PREUVE EST AU MOIS DE MARS, VRAIMENT ?" >>> mc = cryptage(message, 3) >>> mc "O'SUHXYH HVW DX PRLV GH PDUV, YUDLPHQW ?" >>> mc = cryptage(message, 3, debug=True) L devient O P devient S R devient U E devient H U devient X V devient Y E devient H E devient H S devient V T devient W A devient D U devient X M devient P O devient R I devient L S devient V D devient G E devient H M devient P A devient D R devient U S devient V V devient Y R devient U A devient D I devient L M devient P E devient H N devient Q T devient W
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
'''Permet de gérer le cryptage par code de César. Fonctions --------- 1 :: trouveIndex(element:str, sequence:list=ALPHABET) -> int 2 :: decale(element:str, cle:int, sequence:list=ALPHABET) -> str 3 :: filtre(message:str) -> str 4 :: cryptage(message:str, cle:int, sequence:list=ALPHABET, ponctuation:list=PONCTUATION, debug:bool=False) ''' # Constantes ALPHABET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] PONCTUATION = [' ', '.', '!', '?', ',', "'", ' '] # Déclarations des fonctions def trouveIndex(element:str, sequence:list=ALPHABET) -> int : '''Renvoie l'index de element dans le tableau sequence ''' for index in range(len(sequence)) : if sequence[index] == element : return index def decale(element:str, cle:int, sequence:list=ALPHABET) -> str : '''Renvoie la lettre cryptant la lettre element en décalant de cle case vers la droite''' index = trouveIndex(element, sequence) new_index = (index + cle) % len(sequence) return sequence[new_index] def filtre(message:str) -> str : '''Renvoie un string où les lettres sont toutes en majuscules''' message = message.upper() # Méthode des strings qui renvoie les lettres en majuscules reponse = '' # on va créer un string de réponse progressivement : on l'initialise for caractere in message : if caractere in ALPHABET or caractere in PONCTUATION : reponse = reponse + caractere # on ne le garde que s'il fait partie d'un des 2 tableaux return reponse def cryptage(message, cle, sequence=ALPHABET, ponctuation=PONCTUATION, debug=False) : '''Renvoie un string en décalant les lettres majusucles de cle rangs vers la droite :: param message(str) :: un string filtré ne contenant que des majuscules ou de la ponctuation :: param cle(int) :: la valeur entière du décalage vers la droite pour crypter :: param sequence(list) :: la séquence des caractères cryptables :: param ponctuation(list) :: la séquence des caractères inchangées lors du cryptage :: return (str) :: le string crypté :: exemple :: >>> cryptage("ABCé D,XYZ", 3) 'DEF G,ABC' ''' reponse = '' for caractere in message : if caractere in ponctuation : reponse = reponse + caractere elif caractere in sequence : crypte = decale(caractere, cle) reponse = reponse + crypte if debug : print(f"{caractere} devient {crypte}") return reponse # Programme principal if __name__ == '__main__' : import doctest doctest.testmod() message = "L'épreuve est au mois de mars, vraiment ?"

07° Expliquer de la façon la plus précise possible comment fonctionne la fonction cryptage. On rappelle que le string est en Python une structure de données non mutable et qu'on doit donc recréer un string lorsqu'on veut en "modifier" un.

08° Réaliser la fonction decryptage qui doit pouvoir retrouver le texte de base si on lui fournit le texte crypté et la clé en entrée.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
def decryptage(message, cle, sequence=ALPHABET, ponctuation=PONCTUATION, debug=False) : '''Renvoie un string en décalant les lettres majusucles de cle rangs vers la droite :: param message(str) :: un string crypté ne contenant que des majuscules ou de la ponctuation :: param cle(int) :: la valeur entière du décalage vers la droite pour crypter :: param sequence(list) :: la séquence des caractères cryptables :: param ponctuation(list) :: la séquence des caractères inchangées lors du cryptage :: return (str) :: le string crypté :: exemple :: >>> decryptage('DEF G,ABC', 3) 'ABC D,XYZ' ''' pass

Exemple d'utilisation (mc veut dire message crypté et md message décrypté)

>>> message = filtre(message) >>> message "L'PREUVE EST AU MOIS DE MARS, VRAIMENT ?" >>> mc = cryptage(message, 3) >>> mc "O'SUHXYH HVW DX PRLV GH PDUV, YUDLPHQW ?" >>> md = decryptage(mc, 3) >>> md "L'PREUVE EST AU MOIS DE MARS, VRAIMENT ?"

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
def decryptage(message, cle, sequence=ALPHABET, ponctuation=PONCTUATION, debug=False) : '''Renvoie un string en décalant les lettres majusucles de cle rangs vers la droite :: param message(str) :: un string crypté ne contenant que des majuscules ou de la ponctuation :: param cle(int) :: la valeur entière du décalage vers la droite pour crypter :: param sequence(list) :: la séquence des caractères cryptables :: param ponctuation(list) :: la séquence des caractères inchangées lors du cryptage :: return (str) :: le string crypté :: exemple :: >>> decryptage('DEF G,ABC', 3) 'ABC D,XYZ' ''' reponse = '' for caractere in message : if caractere in ponctuation : reponse = reponse + caractere elif caractere in sequence : crypte = decale(caractere, -cle) reponse = reponse + crypte if debug : print(f"{caractere} devient {crypte}") return reponse
Cryptage symétrique

Une méthode de cryptage est dite symétrique lorsqu'on a besoin de la même clé pour crypter ou décrypter le message. Les deux personnages voulant communiquer doivent donc partager une clé commune permettant de crypter et décrypter les messages.

Si quelqu'un intercepte la communication, il ne pourra lire que le message crypté.

symétrique

Il est possible qu'on doive utiliser différemment cette clé lors de la phase de cryptage et lors de la phase de décryptage mais la clé est bien la même dans les deux cas.

Initialisation

Les deux personnes qui désirent communiquer doivent donc partager cette clé à un moment ou à un autre AVANT de pouvoir communiquer de façon crypter.

Si cet échange se fait physiquement, les deux personnes pourront alors communiquer à distance en utilisant cette clé.

Deux problèmes émergent donc de cette technique de cryptage :

  • On ne doit pas pouvoir retrouver le message d'origine en un temps raisonnable (soit par force brute, soit en utilisant une faille permettant de limiter le vrai nombre de clés valides)
  • On ne peut pas initier un telle communication à distance entre deux inconnus en utilisant cette technique : elles devraient se mettre d'accord sur la clé en utilisant des moyens de communication non crypté : on pourrait alors très bien intercepter la clé envoyée en clair puis continuer à écouter les messages cryptés et les décrypter avec la clé interceptée en clair !
  • échange d'une clé symétrique en clair ?

L'échange en clair d'une clé symétrique est bien entendu dangereux et stupide : le but est de garantir la confidentialité de l'échange. S'il suffit d'écouter le premier échange pour parvenir à pénétrer la protection... Autant ne rien faire.

Nous verrons dans la prochaine activité comment parvenir à échanger cette clé symétrique de façon sécurisée.

09° Le cryptage de César est-il une solution symétrique ou asymétrique. Justifier.

...CORRECTION...

Symétrique puisqu'on utilise la même clé pour la fonction de cryptage et la fonction de décryptage.

10° Combien de clés sont-elles possibles ici ? Ce système est-il résistant à une recherche par force brute ?

...CORRECTION...

Il n'y a que 25 combinaisons avec nos 25 letttres. Et encore, le cas 0 est un peu stupide : on ne décale pas...

Bref, 24 valeurs de clé à tester. Non, ce système n'est pas utilisable en crytographie réelle.

Chiffrement ou cryptage ?

Puisqu'on stocke tout sous forme d'octets, on parle en réalité plutôt de chiffrement puisqu'on peut toujours interpréter un octet comme un nombre compris entre 0 et 255.

Rappel : un octet correspond à 8 bits.

Il y a donc 28 valeurs possibles (256).

Un octet permet donc d'obtenir des entiers naturels compris entre 0 et 255.

Chiffrement est donc synomyme de cryptage puisqu'on transforme en réalité une donnée en nombre et qu'on transforme ce nombre.

Si on prend le code de César, on pourrait utiliser la simple table ASCII :

  • A encodé en octet valant 65. Le 65 est transformé en 65 + 3 = 68.
  • Lors du déchiffrement, on récupère le 68 et on obtient 68 - 3 = 65. Un A.

2 - XOR bit à bit

Intéressons nous maintenant à une méthode permettant d'obtenir une meilleure résistance à la force brute.

Imaginons qu'on désire transmettre le message "ABC".

Ce n'est pas cette chaîne de caractères qui transite sur les routeurs mais uniquement la représentation en octets de celle-ci.

Voici la table ASCII complète, en version hexadécimale. Comme je ne suis pas méchant, vous pouvez visualiser la valeur décimale d'un caractère en stabilisant la souris au dessus du caractère.

Table ASCII en version hexadécimale
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _A _B _C _D _E _F
0_ NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI _0
1_ DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 1_
2_ ! " # $ % & ' ( ) * + , - . / 2_
3_ 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 3_
4_ @ A B C D E F G H I J K L M N O 4_
5_ P Q R S T U V W X Y Z [ \ ] ^ _ 5_
6_ ` a b c d e f g h i j k l m n o 6_
7_ p q r s t u v w x y z { | } ~ DEL 7_
_0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F

11° Donner la valeur des trois octets qui encodent notre message.

...CORRECTION...

65 pour A, 66 pour B et 67 pour C.

Nous allons donc envoyer trois octets : 65, 66 et 67 en base 10.

12° Exprimer maintenant vos octets sous forme binaire : donner la suite de bits qui sera envoyé.

...CORRECTION...

65 donne 0100 00012, soit 64 + 1.

66 donne 0100 00102, soit 64 + 2.

67 donne 0100 00112, soit 64 + 2 + 1.

Maintenant que nous avons notre message binaire, regardons comment le chiffrer.

13° Compléter (sur une feuille) la table de vérité du ET(AND), du NON-ET(NAND), du OU(OR) et du NON-OU(NOR) :

Rappel :

  • ET est évalué à VRAI si toutes les conditions sont vraies
  • OU est évalué à VRAI si l'une des conditions est vraie

NAND et NOR sont juste des inversions des réponses du AND et du OR.

Valeur de a Valeur de b a ET b a NAND b
VRAI VRAI ? ?
FAUX VRAI ? ?
VRAI FAUX ? ?
FAUX FAUX ? ?

Pour le ET, cela revient à chercher cela avec Python :

a and b

Cela revient à chercher cela avec Javascript, C, C++ :

a && b
Valeur de a Valeur de b a OU b a NOR b
VRAI VRAI ? ?
FAUX VRAI ? ?
VRAI FAUX ? ?
FAUX FAUX ? ?

Pour le OU, cela revient à chercher cela avec Python :

a or b

Cela revient à chercher cela avec Javascript, C, C++ :

a || b

...CORRECTION...

Pour le AND et le NAND

Valeur de a Valeur de b a ET b a NAND b
VRAI VRAI VRAI FAUX
FAUX VRAI FAUX VRAI
VRAI FAUX FAUX VRAI
FAUX FAUX FAUX VRAI

Pour le OU et le NOR :

Valeur de a Valeur de b a OU b a NOR b
VRAI VRAI VRAI FAUX
FAUX VRAI VRAI FAUX
VRAI FAUX VRAI FAUX
FAUX FAUX FAUX VRAI

14° Compléter la table de vérité du XOR en utilisant simplement le rappel suivant : un OU eXclusif, également nommé XOR, différe du OU car il n'est évalué à VRAI si que l'une des expressions est VRAIE. Si deux expressions sont vraies, il est évaluée à FAUX.

Valeur de a Valeur de b a XOR b
0 0 ?
0 1 ?
1 0 ?
1 1 ?

...CORRECTION...

Valeur de a Valeur de b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0

Nous allons utiliser le XOR entre les bits de nos messages et les bits de la clé commune choisie. Vous allez voir qu'on obtient alors un chiffrement efficace et que le déchiffrement se fait avec la même clé.

Imaginons que notre message soit "ABC" (65-66-67) et notre clé soit "D" (68, donc 0100 0100).

Voici le contenu binaire du message, suivi du contenu binaire de la clé.

Message m : 01000001 01000010 01000011 Cle c : 01000100

Pour obtenir le message crypté mc à partir du message et de la clé, nous allons simplement écrire m XOR c entre chacun des bits de m et de c.

Pour rappel, voici la table du XOR.

Valeur de a Valeur de b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0

Premiers bits : 0 XOR 0 donne 0 car il n'y a pas une condition unique vraie.

Message m : 01000001 01000010 01000011 Cle c : 01000100 Message crypté mc = m XOR c : 0

Les bits suivants : 1 XOR 1 donne 0 car deux conditions vraies : on en veut une seule.

Message m : 01000001 01000010 01000011 Cle c : 01000100 Message crypté mc = m XOR c : 00

Les bits suivants : 1 XOR 1 donne 0 car deux conditions vraies : on en veut une seule.

Message m : 01000001 01000010 01000011 Cle c : 01000100 Message crypté mc = m XOR c : 000

15° Trouver les bits du premier octet du message crypté. Que vaut-il ? Si on ouvrait le fichier crypté comme un simple fichier texte en ASCII, à quel caractère correspond-t-il ?

...CORRECTION...

Message m : 01000001 01000010 01000011 Cle c : 01000100 Message crypté mc = m XOR c : 00000101

On obtient donc un octet "valant" 5.

Cela correspondrait à un caractère non imprimable exprimant une demande sur le réseau (ENQ, ENQUIRY).

Comment faire avec les octets suivants ? La clé n'est pas assez longue...

La solution retenue est simple : on copie-colle la clé autant de fois que nécessaire.

Message m : 01000001 01000010 01000011 Cle c : 01000100 01000100 01000100 Message crypté mc = m XOR c : 00000101

16° Déterminer maintenant le message crypté complet, sous forme binaire puis en exprimant chaque octet en décimal.

...CORRECTION...

Message m : 01000001 01000010 01000011 Cle c : 01000100 01000100 01000100 Message crypté mc = m XOR c : 00000101 00000110 00000111

On obtient le message crypté suivant :

00000101 00000110 00000111

5 6 7

L'émetteur veut donc envoyer "ABC", qui correspond aux bits 01000001 01000010 01000011 (65-66-67) mais il va envoyer 00000101 00000110 00000111 (5-6-7).

Comment fait alors le récepteur pour décoder le message crypté ? C'est là tout la beauté du cryptage en XOR : il suffit de refaire la même chose : on applique un XOR bit à bit entre le message crypté et la clé.

17° Vous êtes le récepteur. Vous venez de recevoir le message indiqué. Vous savez que la clé commune est 0000 0101. Déchiffrer le message émis. Retrouve-t-on le 'ABC' initial en utilisant la même valeur de clé pour le déchiffrement et le chiffrement ?

Message crypté mc : 00000101 00000110 00000111 Cle c : 01000100 Message m = mc XOR c :

...CORRECTION...

Message crypté mc : 00000101 00000110 00000111 Cle c : 01000100 01000100 01000100 Message m = mc XOR c : 01000001 01000010 01000011

On retrouve bien la suite 65 - 66 - 67.

S'il s'agit d'un texte en ASCII, c'est bien "ABC".

18° La technique de chiffrement par XOR est-elle un chiffrement symétrique ou asymétrique ? La clé est-elle commune, partagée entre émeteur et récepteur.

...CORRECTION...

Même clé pour chiffrer/crypter/coder et déchiffrer/décrypter/décoder.

Il s'agit donc d'un chiffrement symétrique.

Par définition même, la clé est donc commune ou partagée.

19° Si votre clé fait 8 bits, combien y-a-t-il de combinaisons possibles à tester ? Si votre clé fait 128 bits, combien y-a-t-il de combinaisons possibles ?

Ce crytpage peut-il cette fois résister à une recherche par force brute ?

...CORRECTION...

8 bits : 28 possibilités : soit 256 clés à tester.

128 bits : 2128 possibilités : soit 340282366920938463463374607431768211456 clés à tester.

20° Choisir une valeur-clé sur 2 octets avec un autre étudiant. Transmettez lui un message crypté de 5 octets. Vérifier que les deux parties parviennent bien à communiquer correctement.

Pourquoi 5 et 2 ? Car vous allez devoir faire un copier-coller non complet de la clé sur le dernier octet. Ce n'est pas grave.

Exemple avec un message de 12 bits et un clé de 5 bits.

Message m : 01000001 0100 Cle c : 11001 Message crypté mc = m XOR c :
Message m : 01000001 0100 Cle c : 11001110 0111 Message crypté mc = m XOR c :

...CORRECTION...

Message m : 01000001 0100 Cle c : 11001110 0111 Message crypté mc = m XOR c : 10001111 0011

On envoie donc sur le réseau le message crypté suivant : 10001111 0011.

Le récepteur reçoit ce message sur sa machine.

Il doit alors utiliser un XOR bit à bit entre le message crypté et la clé partagée.

Message m : 10001111 0011 Cle c : 11001110 0111 Message crypté mc = m XOR c : 01000001 0100

Le message décrypté est bien identique au message initial.

3 - FAQ

Activité publiée le 02 10 2020
Dernière modification : 02 10 2020
Auteur : ows. h.