{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![En tête general](img/En_tete_general.png)\n",
"\n",
"\n",
"*(C) Copyright Franck CHEVRIER 2019-2020 http://www.python-lycee.com/*\n",
"\n",
" Pour exécuter une saisie Python, sélectionner la cellule et valider avec SHIFT+Entrée.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chiffrement RSA (corrigé)\n",
"\n",
"### Activité sur le chiffrement n°3\n",
"##### (prérequis: congruences, équations diophantiennes, nombres premiers, théorème de Gauss, petit théorème de Fermat)\n",
"\n",
"![Illustration_detectives](img/Chiffrement_RSA.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cette activité propose, sous forme simplifiée, d'étudier le principe du chiffrement RSA.
\n",
"\n",
"### Sommaire\n",
"\n",
"1. Principe du chiffrement RSA
\n",
"2. Échanges sécurisés de message
\n",
"3. Principe d'authentification
\n",
"4. Compléments arithmétiques
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Principe du chiffrement RSA"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Archibald, chef d'une agence de détectives, souhaite que tous ses associés cryptent les messages qu'ils lui envoient. Il souhaite donc leur donner à tous la même méthode de chiffrement, mais -méfiant- souhaite aussi s'asssurer d'être le seul à pouvoir décoder les messages qui lui parviennent, au cas où un espion intercepterait un de ces messages.
\n",
"Dans les activités de chiffrement précédentes, la connaissance de la clé de chiffrement permettait directement de déterminer la clé de déchiffrement, ce qui ne convient pas à Archibald.
\n",
"Pour réaliser son chiffrement, Archibald :\n",
"
\n",
" - fixe deux nombres premiers $p$ et $q$ distincts ;
\n",
" - pose $n=pq$ et $m=(p-1)(q-1)$ ;
\n",
" - choisit un entier $c$ premier avec $m$ tel que $1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
\n",
" Dans cette partie, on pose $p=11$ ; $q=23$ et $c=9$.\n",
"
\n",
"\n",
"__1.1. Vérifier que $p$ ; $q$ et $c$ vérifient bien les contraintes annoncées, et donner les valeurs de $n$ et $m$.__\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"$p=11$ et $q=23$ sont bien des nombres premiers.
\n",
"$n=pq=11 \\times 23=253$
\n",
"$m=(p-1)(q-1)=10 \\times 22=220$
\n",
"$c=9$ vérifie bien $1\n",
"\n",
"\n",
"Archibald fournit le couple $(n;c)$ à ses associés, et garde les valeurs $p$ et $q$ secrètes.
\n",
"Balthazar, un associé d'Archibald, souhaite coder un message à l'aide du couple $(n;c)$, appelé __clé publique__.
\n",
"(pour simplifier, on suppose que le message est exclusivement composé d'espaces et de lettres majuscules, sans accents ni caractères spéciaux)
\n",
"Pour cela, il commence par associer à chaque caractère de son message un entier $x$ compris entre $0$ et $26$ à l'aide du tableau de correspondance ci-dessous.
\n",
"Ensuite, il associe à la valeur $x$ obtenue la valeur $y$ telle que $0 \\leq y \\leq n-1$ et $y \\equiv x^{\\;c} \\;[n]$.
\n",
"\n",
"| 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 | (espace) |\n",
"|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:---------|\n",
"| 0 | 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 |\n",
"\n",
"
\n",
"Exemple :
\n",
"Avec les valeurs choisies précédemment, la lettre I correspond à la valeur $x=8$.
\n",
"Comme $x^9=8^9=134217728 \\equiv 216 [253]$, cette lettre se code avec la valeur $216$.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__1.2. Balthazar souhaite envoyer le message \"BINGO\" à Archibald. Quelle succession de nombres va-t-il lui envoyer ?__
\n",
"$\\;\\;\\;\\;\\;$On pourra utiliser une (des) zone(s) de saisie Python pour effectuer des calculs utiles."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 216, 72, 200, 136]"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Utiliser si nécessaire cette zone pour les calculs en Python\n",
"[ k**9 %253 for k in [1,8,13,6,14] ]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__1.3. On donne les fonctions Python chiffrage et chiffrement_RSA ci-dessous.__
\n",
"$\\quad\\;\\;$__À l'aide d'appels à ces fonctions, vérifier le résultat de la question 1.2.__"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#Mise en mémoire de l'alphabet (+espace)\n",
"Alphabet=\"ABCDEFGHIJKLMNOPQRSTUVWXYZ \"\n",
"\n",
"def chiffrage(message):\n",
" \"\"\"\n",
" Fonction qui renvoie la liste des valeurs correspondantes aux caractères du message\n",
" (A->0 , B->1 , ...)\n",
" \"\"\"\n",
" return [ Alphabet.index(caractere) for caractere in message ]\n",
" \n",
" \n",
"def chiffrement_RSA(n,c,liste_nombres):\n",
" \"\"\"\n",
" Fonction effectuant le codage RSA de la liste de valeurs avec la clé publique (n,c)\n",
" \"\"\"\n",
" code = [] \n",
" for x in liste_nombres: # pour chaque valeur x de la liste donnée\n",
" y = x**c %n # on calcule y correspondant à x\n",
" code.append(y) # on complète la liste de valeurs avec y\n",
" return code\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 216, 72, 200, 136]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici les appels aux fonctions chiffrage et chiffrement_RSA\n",
"\n",
"liste = chiffrage(\"BINGO\")\n",
"\n",
"chiffrement_RSA(253,9,liste)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__1.4.__ Dans cette question, on souhaite effectuer le décodage du message à l'aide du triplet $(p;q;c)$, appelé __clé privée__.
\n",
"$\\;\\;\\;\\;\\;$__a. Sans chercher à le déterminer, démontrer qu'il existe un unique entier $d$ tel que $1 \\leq d < m$ et $cd \\equiv 1 \\;[m]$.__
\n",
"\n",
"\n",
"Existence :\n",
"Comme $c$ et $m$ sont premiers entre eux, d'après le théorème de Bézout il existe deux entiers $d$ et $v$ tels que $cd+vm=1$. Ce qui donne $cd=1-mv$ et donc $cd \\equiv 1 [m]$.\n",
"Unicité :\n",
"Si $d_1$ et $d_2$ sont deux entiers qui conviennent, alors on a $d_1-d_2 \\equiv 0 \\;[m]$, donc $m$ divise $d_1-d_2$.\n",
"D'autre part, $1 \\leq d_1 < m$ et $1 \\leq d_2 < m$ permettent de déduire que $-m+1 \\leq d_1-d_2 < m-1$.\n",
"Or le seul multiple de $m$ qui appartient à cet intervalle est $0$, donc $d_1-d_2=0$, c'est à dire $d_1=d_2$.\n",
"\n",
"\n",
"$\\;\\;\\;\\;\\;$__b. Déterminer cette valeur $d$ (on pourra commencer par appliquer l'algorithme d'Euclide).__\n",
"\n",
"\n",
"On a $m=(p-1)(q-1)=10\\times22=220$ et $c=9$.
\n",
"En appliquant l'algorithme d'Euclide et en remontant les calculs, on détermine un couple de coefficients de Bézout :\n",
"\n",
"\n",
" \n",
" Algorithme d'Euclide | \n",
" Recherche des coefficients de Bézout | \n",
"
\n",
" \n",
" $220 = 9 \\times 24 + 4$ | \n",
" $4 = 220 - 9 \\times 24 = m - 24c$ | \n",
"
\n",
" \n",
" $9 = 4 \\times 2 +1$ | \n",
" $1 = 9 - 4 \\times 2 = c - (m-24c) \\times 2 = -2m+49c$ | \n",
"
\n",
" \n",
" $4 = 4 \\times 1 +0$ | \n",
" | \n",
"
\n",
"
\n",
"\n",
"On en déduit que $49c=1+2m$, c'est à dire $49c \\equiv 1 \\;[m]$.
\n",
"On pose $d=49$ qui convient puisque $1<49\n",
"\n",
"\n",
"$\\;\\;\\;\\;\\;$__c. À l'aide de saisies en Python, calculer $x^{cd}$ modulo $n$ pour différentes valeurs entières positives de $x$. Que constate-t-on ?__
\n",
"\n",
"\n",
"Il semble que $x^{cd} \\equiv x \\;[n]$ quelle que soit la valeur entière $x$ positive choisie.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[13, 50, 77, 80]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici les calculs\n",
"c = 9\n",
"d = 49\n",
"n = 253\n",
"\n",
"[ x**(c*d) %n for x in [13,50,77,80] ] #tests pour diverses valeurs de x\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\;\\;\\;\\;\\;$__d. On admet pour l'instant\\* que l'observation de la question 1.4.b. est correcte pour tout entier positif $x$, et on rappelle que $y$ vérifie $y \\equiv x^{\\;c} \\;[n]$.
\n",
"$\\quad\\quad$(*La démonstration mathématique de ce résultat sera détaillé dans la partie 4)
\n",
"$\\quad\\quad$Exprimer $x$ en fonction de $y$ modulo $n$.__
\n",
"\n",
"\n",
"On sait que $x^c \\equiv y \\;[n]$.
\n",
"En élevant à la puissance $d$, on obtient:
\n",
"$(x^c)^d \\equiv y^d \\;[n]$
\n",
"$x^{cd} \\equiv y^d \\;[n]$
\n",
"et comme on a admis que $x^{cd} \\equiv x \\;[n]$, on en déduit que :
\n",
"$x \\equiv y^d \\;[n]$
\n",
"\n",
"\n",
"$\\;\\;\\;\\;\\;$__e. Effectuer le décodage des nombres de la question 1.2 et vérifier qu'on retrouve bien le message \"BINGO\".__
\n",
"$\\;\\;\\;\\;\\;\\;\\;\\;$On pourra utiliser une (des) zone(s) de saisie Python pour effectuer des calculs utiles."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 8, 13, 6, 14]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Utiliser si nécessaire cette zone pour les calculs en Python\n",
"c = 9\n",
"d = 49\n",
"n = 253\n",
"\n",
"[y**d %n for y in [1, 216, 72, 200, 136] ]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__1.5. On fournit ci-dessous la fonction Python inv qui reçoit en argument m et c, et renvoie d.__
\n",
"$\\;\\;\\;\\;\\;\\;$(NB : Cette fonction est basée sur une recherche de coefficients de Bézout ; elle est étudiée dans l'activité PGCD / Euclide / Bézout)
\n",
"$\\;\\;\\;\\;\\;\\;$__Vérifier que la fonction inv permet de retrouver la réponse à la question 1.5.a.__"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"def inv(m,c):\n",
" \"\"\"\n",
" Recherche de d, inverse de c modulo m\n",
" (passage par les coefficients de Bézout)\n",
" \"\"\"\n",
" a,b=m,c\n",
" q = a//b\n",
" P = np.array([ [ 0 , 1 ] , [ 1 , -q ] ]) \n",
" while a%b!=0:\n",
" a,b = b,a%b\n",
" q = a//b\n",
" P = np.dot( np.array([ [ 0 , 1 ] , [ 1 , -q ] ]) , P )\n",
" u,v = P[0]\n",
" return int(v%m)\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"49"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici un appel à la fonction inv\n",
"p = 11 ; q = 23\n",
"m = (p-1)*(q-1) ; c = 9\n",
"\n",
"d = inv(m,c)\n",
"d "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__1.6.a. Écrire une fonction Python dechiffre_RSA qui reçoit en argument p, q, c et code (liste de valeurs fournie par la fonction chiffrement_RSA) et qui effectue les instructions suivantes:__
\n",
"\n",
" - calculer n
\n",
" - calculer m
\n",
" - calculer d
\n",
" - renvoyer la liste des valeurs x correspondantes aux valeurs y du code
\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"#Écrire ici la fonction dechiffre_RSA\n",
"\n",
"def dechiffre_RSA(p,q,c,code):\n",
" \"\"\"\n",
" Fonction effectuant le décodage RSA du code à partir des nombres premiers p et q\n",
" \"\"\"\n",
" n = p*q #calcul de n\n",
" m = (p-1)*(q-1) #calcul de m\n",
" d = inv(m,c) #calcul de d\n",
" \n",
" return [y**d %n for y in code] #renvoie la liste des valeurs correspondantes aux valeurs y du code\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\;\\;\\;$__b. On donne la fonction Python lettrage ci-dessous.__
\n",
"$\\quad\\;\\;$__Vérifier que votre fonction dechiffre_RSA et cette fonction lettrage permettent de décoder la liste de valeurs des questions 1.2 et 1.3.__"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"def lettrage(code):\n",
" \"\"\"\n",
" Fonction qui convertit une liste de valeurs (comprises entre 0 et 26) en chaine de caractères\n",
" (0->A , 1->B , ...)\n",
" \"\"\"\n",
" message = \"\"\n",
" for y in code:\n",
" message += Alphabet[y]\n",
" \n",
" return message"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 8, 13, 6, 14]"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici un appel à la fonction dechiffre_RSA\n",
"liste = dechiffre_RSA(11,23,9,[1, 216, 72, 200, 136])\n",
"liste"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'BINGO'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici un appel à la fonction lettrage\n",
"lettrage(liste)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\;\\;\\;$__c. Archibald reçoit ce code de la part de Casper, un autre de ses associés : $36, 5, 145, 36, 43, 0$.__
\n",
"$\\;\\;\\;\\;\\;\\;$__Décoder ce message.__
"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[4, 20, 17, 4, 10, 0]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici un appel à la fonction dechiffre_RSA\n",
"liste=dechiffre_RSA(11,23,9,[36, 5, 145, 36, 43, 0])\n",
"liste"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'EUREKA'"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici un appel à la fonction lettrage\n",
"lettrage(liste)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Échanges sécurisés de message\n",
"
\n",
"On reprend dans cette partie les notations de la partie précédente."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__2.1. Exécuter la cellule ci-dessous, qui permet de générer deux nombres premiers $p$ et $q$ distincts à 3 chiffres et un nombre entier $c$ tel que $c$ et $m=(p-1)(q-1)$ sont premiers entre eux avec $1\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(607, 151, 78391)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from random import randint\n",
"\n",
"def PGCD(a,b):\n",
" \"\"\"\n",
" Fonction qui calcule le PGCD de a et b\n",
" \"\"\"\n",
" return a if b==0 else PGCD(b,a%b)\n",
"\n",
"def est_premier(n):\n",
" \"\"\"\n",
" Fonction qui détermine si un entier est premier\n",
" \"\"\"\n",
" if n%2==0 or n==1: return False\n",
" for k in range(3,int(n**0.5)+1,2):\n",
" if n%k==0 : return False\n",
" return True\n",
"\n",
"def premier(min=10**2,max=10**3-1):\n",
" \"\"\"\n",
" Fonction qui renvoie un nombre premier aléatoire compris entre min et max\n",
" \"\"\"\n",
" p=0\n",
" while not est_premier(p):\n",
" p=randint(min,max)\n",
" return p\n",
"\n",
"#génération d'un nombre premier p à 3 chiffres\n",
"p = premier() \n",
"\n",
"#génération d'un nombre premier q à 3 chiffres, distinct de p\n",
"q = p\n",
"while q == p : q = premier() \n",
"\n",
"#génération de c premier avec m\n",
"m = (p-1)*(q-1) \n",
"c = 0\n",
"while PGCD(c,m)!=1: c = randint(2,m-1) \n",
"\n",
" \n",
"p,q,c"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__2.2. Effectuer les saisies nécessaires pour calculer $n$.__"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"91657"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici les saisies pour le calcul de n\n",
"n = p*q\n",
"n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__2.3. Fournir à deux personnes B et C votre clé publique $(n,c)$.__
\n",
"$\\;\\;\\;\\;\\;$__B et C vous envoient alors un message codé à l'aide de la fonction chiffrement_RSA.__
\n",
"$\\;\\;\\;\\;\\;$__Décoder ces messages à l'aide de la fonction dechiffre RSA.__\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[73240, 0, 86762, 15374, 75670]"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Saisies effectuées par B pour générer son message codé\n",
"message_de_B=\"SALUT\"\n",
"\n",
"code=chiffrement_RSA(n,c,chiffrage(message_de_B))\n",
"code"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'SALUT'"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Saisies effectuées pour décoder le message\n",
"lettrage(dechiffre_RSA(p,q,c,code))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Si C interceptait le message codé envoyé par B, pourrait-il le décoder ?...
\n",
"Pour décoder un message, il est nécessaire de connaître les valeurs de $p$ et $q$, afin de déterminer $m$ puis $d$.
\n",
"Connaissant $n$, C devrait retrouver la décomposition en facteurs premiers $n=pq$.
\n",
"La sécurité du code dépend donc de la difficulté à réaliser cette décomposition. Pour de petites valeurs de $n$, il est possible d'automatiser cette recherche avec un temps de calcul relativement court. C'est pourquoi, dans la pratique, les nombres $p$ et $q$ utilisés pour un chiffrement RSA sont des nombres premiers qui comportent plusieurs centaines de chiffres !
\n",
"Par ailleurs, le chiffrement RSA procède en réalité par codage par blocs et non par caractères."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Principe d'authentification\n",
"
\n",
"On reprend dans cette partie les notations des parties précédentes.
\n",
"\n",
"Archibald et Balthazar disposent chacun d'une clé publique et d'une clé privée pour le chiffrement RSA.
\n",
"\n",
"Archibald souhaite envoyer un message à Balthazar de telle sorte que celui-ci soit certain de l'origine du message.
\n",
"Mais toutes les personnes qui écrivent à Balthazar utilisent la même clé publique...
\n",
"\n",
"Pour l'exemple traité dans cette partie, les clés sont données dans le tableau ci-après :\n",
"\n",
"\n",
"\n",
" \n",
" $\\;\\;\\;$ | \n",
" Archibald | \n",
" $\\;\\;\\;$ | \n",
" Balthazar | \n",
"
\n",
" \n",
" Clé privée | \n",
" $$ p_A=11 \\;;\\; q_A=23 \\;;\\; c_A=9 $$ | \n",
" $\\;\\;\\;$ | \n",
" $$ p_B=7 \\;;\\; q_B=13 \\;;\\; c_B=5 $$ | \n",
"
\n",
" \n",
" Clé publique | \n",
" $$n_A=253 \\;;\\; c_A=9$$ | \n",
" $\\;\\;\\;$ | \n",
" $$n_B=91 \\;;\\; c_B=5$$ | \n",
"
\n",
"
\n",
"\n",
"\n",
"Supposons qu'Archibald souhaite envoyer le message \"VOICI MON MESSAGE IMPORTANT\" à Balthazar :\n",
"\n",
" - il va appliquer la clé publique de cryptage de Balthazar $(n_B,c_B)=(91,5)$ à ce message ;
\n",
" - il va appliquer sa propre clé privée de décryptage à une partie de ce message (par exemple le premier mot) qui servira à authentifier l'expéditeur ;
\n",
" - enfin, il envoie les deux listes de valeurs à Balthazar.
\n",
"
\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__3.1. Dans la cellule ci-dessous, on a créé le message à envoyer, ainsi que le mot d'authentification.__
\n",
"$\\quad\\;$__Utiliser les zones de saisie suivantes pour obtenir les deux listes de valeurs code1 et code2qu'Archibald va envoyer à Balthazar.__"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('VOICI MON MESSAGE IMPORTANT', 'VOICI')"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"message = \"VOICI MON MESSAGE IMPORTANT\" #message à envoyer\n",
"mot_auth = message[:5] #partie du message pour l'authentification (ici le premier mot)\n",
"\n",
"message , mot_auth"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"([21,\n",
" 14,\n",
" 8,\n",
" 2,\n",
" 8,\n",
" 26,\n",
" 12,\n",
" 14,\n",
" 13,\n",
" 26,\n",
" 12,\n",
" 4,\n",
" 18,\n",
" 18,\n",
" 0,\n",
" 6,\n",
" 4,\n",
" 26,\n",
" 8,\n",
" 12,\n",
" 15,\n",
" 14,\n",
" 17,\n",
" 19,\n",
" 0,\n",
" 13,\n",
" 19],\n",
" [21, 14, 8, 2, 8])"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici les saisies nécessaires pour convertir le message et le mot d'authentification en listes de nombres\n",
"#(on pourra nommer ces listes l1 et l2)\n",
"l1 = chiffrage(message)\n",
"l2 = chiffrage(mot_auth)\n",
"\n",
"l1 , l2"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"([21,\n",
" 14,\n",
" 8,\n",
" 32,\n",
" 8,\n",
" 52,\n",
" 38,\n",
" 14,\n",
" 13,\n",
" 52,\n",
" 38,\n",
" 23,\n",
" 44,\n",
" 44,\n",
" 0,\n",
" 41,\n",
" 23,\n",
" 52,\n",
" 8,\n",
" 38,\n",
" 71,\n",
" 14,\n",
" 75,\n",
" 80,\n",
" 0,\n",
" 13,\n",
" 80],\n",
" [175, 15, 62, 193, 62])"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer ici les saisies pour obtenir les listes envoyées par Balthazar\n",
"#(on pourra nommer ces listes code1 et code2)\n",
"code1 = chiffrement_RSA(91,5,l1) #codage du message à l'aide de la clé publique de Balthazar\n",
"code2 = dechiffre_RSA(11,23,9,l2) #codage du mot d'authentification à l'aide de la clé privée d'Archibald\n",
"\n",
"code1 , code2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__3.2 On se place maintenant du côté de Balthazar, qui souhaite interpréter les deux codes reçus code1 et code2.__
\n",
"$\\quad\\;$__a. Quelles sont les clés qu'il va appliquer à chacun de ces codes pour obtenir les valeurs initiales ?__
\n",
"\n",
"\n",
"\n",
"Balthazar va :\n",
"\n",
" - appliquer sa propre clé privée de décryptage $(p_B,q_B,c_B)=(7,13,5)$ à code1 ;
\n",
" - appliquer la clé publique d'Archibald $(n_A,c_A)=(253,9)$ à code2
\n",
" - convertir en lettres les listes de valeurs obtenues.
\n",
"
\n",
"\n",
"\n",
"$\\quad\\;$__b. Effectuer les saisies Python correspondantes, et convertir les résultats en lettres.__"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('VOICI MON MESSAGE IMPORTANT', 'VOICI')"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Effectuer les saisies pour interpréter code1 et code2\n",
"lettrage(dechiffre_RSA(7,13,5,code1)) , lettrage(chiffrement_RSA(253,9,code2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\quad\\;$__c. Qu'est ce qui assure à Balthazar que le message provient bien d'Archibald ?__\n",
"\n",
"\n",
"Seul Archibald a pu déterminer la liste de valeurs code2 qui redonne le mot d'authentification \"VOICI\" quand on lui applique sa clé publique.
\n",
"Ceci assure donc à Balthazar qu'Archibald est bien l'expéditeur.\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Compléments arithmétiques\n",
"
\n",
"On rappelle l'énoncé du petit théorème de Fermat :\n",
"\n",
"Théorème : Petit théorème de Fermat.
\n",
"Soit $x \\in \\mathbb{N}$. Si $\\begin{Bmatrix} p \\text{ est un nombre premier} \\\\ p \\text{ ne divise pas } x \\end{Bmatrix}$ alors $x^{\\;p-1} \\equiv 1 \\;[p]$.\n",
"
\n",
"\n",
"On reprend dans cette partie les notations de la partie 1, notamment :
\n",
"\n",
" - $p$ et $q$ sont des nombres premiers distincts ;
\n",
" - $n=pq$ et $m=(p-1)(q-1)$ ;
\n",
" - $c$ et $m$ sont premiers entre eux et vérifient $1\n",
"
- $d$ vérifie $1 \\leq d < m$ et $cd \\equiv 1 \\;[m]$.
\n",
"
\n",
"\n",
"Le but de cette partie est de démontrer le résultat qui a été admis dans la question 1.4.c. :
\n",
"On considère un entier positif $x$ et on souhaite démontrer que $x^{cd} \\equiv x \\;[n]$.
\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"__4.0. a. Justifier qu'il existe un entier $k$ tel que $cd = km+1$.__
\n",
"\n",
"\n",
"$cd \\equiv 1 \\;[m]$ donc il existe un entier $k$ tel que $cd = 1 +km$.\n",
"\n",
"\n",
"$\\quad\\;\\;$__b. Dresser la liste des diviseurs positifs de $n$ et en déduire les valeurs possibles de $PGCD(x,n)$.__
\n",
"\n",
"\n",
"La décomposition de $n$ en produit de facteurs premiers est $n=pq$, donc les diviseurs positifs de $n$ sont $1$,$p$,$q$ et $pq$.
\n",
"Comme $PGCD(x,n)$ est un diviseur de $n$, il peut être égal à $1$,$p$,$q$ ou $pq$.\n",
"\n",
"\n",
"\n",
"Nous allons maintenant procéder à la démonstration par disjonction des cas.
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__4.1. On suppose dans cette question que $PGCD(x,n)=1$, c'est à dire que $x$ et $n$ sont premiers entre eux.__
\n",
"\n",
"$\\quad\\;$__a. Justifier que $x^{(p-1)(q-1)} \\equiv 1 \\;[p]$ et que $x^{(p-1)(q-1)} \\equiv 1 \\;[q]$.__
\n",
"\n",
"\n",
"$p$ est un nombre premier qui divise $n$, donc il ne peut pas diviser $x$ (sinon $PGCD(x,n)$ ne vaudrait pas 1).
\n",
"$p$ n'apparait donc pas dans la décomposition en facteurs premiers de $x$ et donc pas non plus dans celle de $x^{q-1}$.
\n",
"On peut donc appliquer le petit théorème de Fermat à $p$ et $x^{q-1}$, et on en déduit que :
\n",
"$(x^{q-1})^{p-1} \\equiv 1 \\;[p]$
\n",
"$x^{(p-1)(q-1)} \\equiv 1 \\;[p]$
\n",
"Un raisonnement similaire (en permutant les rôles de $p$ et $q$) permet de démontrer que $x^{(p-1)(q-1)} \\equiv 1 \\;[q]$
\n",
"\n",
"\n",
"$\\quad\\;$__b. En déduire que $pq$ divise $x^{(p-1)(q-1)}-1$, et donc que $x^m \\equiv 1 \\;[n]$.__
\n",
"\n",
"\n",
"$p$ et $q$ sont premiers, distincts, et divisent tous deux $x^{(p-1)(q-1)}-1$ d'après la question précédente.
\n",
"$p$ et $q$ apparaissent donc dans la décomposition de $x^{(p-1)(q-1)}-1$ en produit de facteurs premiers, et comme ils sont distincts, on en déduit que $pq$ divise $x^{(p-1)(q-1)}-1$.
\n",
"(NB : $p$ et $q$ étant premiers entre eux et divisant $x^{(p-1)(q-1)}-1$, on peut aussi conclure que $pq$ divise $x^{(p-1)(q-1)}-1$ en utilisant le corollaire du théorème de Gauss)
\n",
"Il en résulte que $x^{(p-1)(q-1)}-1 \\equiv 0 \\;[pq]$, ce qui s'écrit aussi $x^m-1 \\equiv 0 \\;[n]$, c'est à dire finalement $x^m \\equiv 1 \\;[n]$.\n",
"\n",
"\n",
"$\\quad\\;$__c. À l'aide des questions 4.0.a et 4.1.b, démontrer que $x^{cd} \\equiv x \\;[n]$.__\n",
"\n",
"\n",
"Comme $x^m \\equiv 1 [n]$, on en déduit en élevant à la puissance $k$ que $(x^m)^k \\equiv 1 [n]$.
\n",
"Enfin, on a :
\n",
"$x^{cd}=x^{km+1}=(x^m)^kx \\equiv x \\;[n]$.
\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__4.2. On suppose dans cette question que $PGCD(x,n)=pq$.__
\n",
"$\\quad\\;\\;$__Justifier que, dans ce cas, $x \\equiv 0 \\;[n]$ puis que $x^{cd} \\equiv x \\;[n]$.__
\n",
"\n",
"\n",
"$PGCD(x,n)=pq=n$ donc $n$ divise $x$, et il en résulte que $x \\equiv 0 \\;[n]$.
\n",
"En élevant à la puissance $cd$, on obtient $x^{cd} \\equiv 0 \\;[n]$.
\n",
"Finalement, comme $x$ et $x^{cd}$ sont tous deux congrus à $0$ modulo $n$, ils sont congrus entre eux modulo $n$ :
\n",
"$x^{cd} \\equiv x \\;[n]$\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__4.3. On suppose dans cette question que $PGCD(x,n)=p$.__
\n",
"$\\quad\\;\\;$__a. Justifier que $p$ est un diviseur de $x^{cd}-x$.__
\n",
"\n",
"\n",
"$PGCD(x,n)=p$ donc $p$ est un diviseur de $x$.
\n",
"Comme $cd>=1$, $p$ est aussi un diviseur de $x^{cd}$.
\n",
"Enfin, on en déduit que $p$ divise $x^{cd}-x$ (qui est une combinaison linéaire de $x^{cd}$ et $x$).\n",
"\n",
"\n",
"$\\quad\\;\\;$__b. Démontrer que $x^{cd} = (x^{q-1})^{k(p-1)}x$.__
\n",
"\n",
"\n",
"$x^{cd}=x^{km+1}=x^{k(p-1)(q-1)+1}=(x^{q-1})^{k(p-1)}x$\n",
"\n",
"\n",
"$\\quad\\;\\;$__c. Justifier que $x^{q-1} \\equiv 1 \\;[q]$.__
\n",
"\n",
"\n",
"$q$ divise $n$ donc ne peut pas diviser $x$ (sinon $q$ diviserait $PGCD(x,n)=p$, ce qui est absurde).
\n",
"Comme $q$ est premier et ne divise pas $x$, on peut appliquer le petit théorème de Fermat :
\n",
"$x^{q-1} \\equiv 1 \\;[q]$ \n",
"\n",
"\n",
"$\\quad\\;\\;$__d. Déduire des questions 4.3.b. et 4.3.c que $x^{cd} \\equiv x \\;[q]$, c'est à dire que $q$ est un diviseur de $x^{cd}-x$__
\n",
"\n",
"\n",
"$x^{q-1} \\equiv 1 \\;[q]$ donc en élevant à la puissance $k(p-1)$ on obtient $(x^{q-1})^{k(p-1)} \\equiv 1 \\;[q]$.
\n",
"On a donc :
\n",
"$x^{cd}=(x^{q-1})^{k(p-1)}x \\equiv x \\;[q]$\n",
"\n",
"\n",
"\n",
"\n",
"$\\quad\\;\\;$__e. À l'aide des questions 4.3.a. et 4.3.d, justifier que $x^{cd} \\equiv x \\;[n]$.__\n",
"\n",
"\n",
"$x^{cd} \\equiv x \\;[q]$ donne $x^{cd}-x \\equiv 0 \\;[q]$, ce qui prouve que $q$ divise $x^{cd}-x$.\n",
"On a finalement démontré que $p$ et $q$ sont deux facteurs premiers distincts de la décomposition de $x^{cd}-x$ en produit de facteurs premiers.
\n",
"Il en résulte que $n=pq$ divise $x^{cd}-x$, c'est à dire que $x^{cd} \\equiv x \\;[n]$
\n",
"(NB : $p$ et $q$ étant premiers entre eux et divisant $x^{cd}-x$, on peut aussi conclure que $pq$ divise $x^{cd}-x$ en utilisant le corollaire du théorème de Gauss) \n",
"\n",
"\n",
"\n",
"\n",
"__4.4. Conclure.__
\n",
"\n",
"\n",
"Le cas où $PGCD(x,n)=q$ étant similaire à celui étudié à la question 4.3 (en permutant les rôles de $p$ et $q$), on a bien démontré dans tous les cas que $x^{cd} \\equiv x \\;[n]$.\n",
"\n",
"\n",
"\n",
"Remarque : Le résultat de la question 4.1.b est un cas particulier du théorème d'Euler en arithmétique modulaire, qui est une généralisation du petit théorème de Fermat."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![RSA](img/RSA.png)\n",
"\n",
" Adi Shamir, Ronald Rivest et Leonard Adleman sont à l'origine de l'algorithme de chiffrement RSA"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*(C) Copyright Franck CHEVRIER 2019-2020 http://www.python-lycee.com/*
\n",
"*Remerciements particuliers à Nicolas EHRSAM pour sa précieuse collaboration.*"
]
}
],
"metadata": {
"celltoolbar": "Raw Cell Format",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 2
}