{ "cells": [ { "cell_type": "markdown", "source": [ "\"Cryptographie" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "# TP2. Chiffrement symétrique, oracles et cryptanalyse\n", "\n", "Dans ce TP nous travaillerons en Python 3, directement à l'intérieur de ce notebook jupyter.\n", "\n", "L'objectif de cette fiche est double :\n", "1. d'une part découvrir l'utilisation en pratique d'AES, des modes opératoires et du padding ;\n", "2. d'autre part comprendre pourquoi la brique de chiffrement symétrique ne suffit pas à assurer la confidentialité d'un protocole de communication.\n", "\n", "Pour illustrer le second point, nous revisitons l'attaque du _padding CBC_ vue en cours ainsi que l'attaque _chopchop_ contre le protocole WEP de chiffrement de réseau sans fil.\n", "\n", "Nous avons choisi d'utiliser la bibliothèque [PyCryptodome](http://www.pycryptodome.org/). Pour rejouer cette fiche en dehors du TP, il convient d'installer une version récente de [PyCryptodome](http://www.pycryptodome.org/) sur votre système." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## 1. Échauffement : bytes, XOR, AES, CBC/CTR et padding\n", "\n", "En Python 3, les séquences d'octets sont représentées par le type ``bytes`` lorsqu'elles ne sont pas modifiables (comme des chaînes de caractères) et par le type ``bytearray`` lorsqu'elles sont modifiables (comme des listes). Le passage d'une chaîne de caractère à une séquence d'octets prend en compte le codage des caractères (par défaut on suppose que vous utilisez UTF-8 mais des arguments optionnels permettent de préciser autre chose)." ], "metadata": {} }, { "cell_type": "code", "source": [ "s = \"L'éléphant se dandine sur le toit.\"\n", "print('s =',repr(s), len(s))\n", "b = s.encode()\n", "print('b =',repr(b), len(b))\n", "x = bytes(5)\n", "print('x =',repr(x))\n", "y = bytes([65,66,67,68])\n", "print('y =',repr(y))\n", "z = bytearray(y)\n", "z[1] += 32\n", "print('z =',repr(z))\n", "t = z.decode()\n", "print('t =',repr(t))\n", "l = list(z)\n", "print(l)" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "s = \"L'éléphant se dandine sur le toit.\" 34\n", "b = b\"L'\\xc3\\xa9l\\xc3\\xa9phant se dandine sur le toit.\" 36\n", "x = b'\\x00\\x00\\x00\\x00\\x00'\n", "y = b'ABCD'\n", "z = bytearray(b'AbCD')\n", "t = 'AbCD'\n", "[65, 98, 67, 68]\n" ] } ], "execution_count": 2, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:28:14.476Z", "iopub.execute_input": "2020-10-11T21:28:14.490Z", "iopub.status.idle": "2020-10-11T21:28:14.520Z", "shell.execute_reply": "2020-10-11T21:28:14.533Z" } } }, { "cell_type": "markdown", "source": [ "La bibliothèque ``Crypto`` fourni une fonction très pratique pour appliquer un masque sur une séquence d'octets." ], "metadata": {} }, { "cell_type": "code", "source": [ "from Crypto.Util.strxor import strxor\n", "\n", "m = b\"lapin\"\n", "k = b\"poule\"\n", "c = strxor(m,k)\n", "print(m,'⊕',k,'=',c)\n", "s = strxor(c,k)\n", "print(c,'⊕',k,'=',s)" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "b'lapin' ⊕ b'poule' = b'\\x1c\\x0e\\x05\\x05\\x0b'\n", "b'\\x1c\\x0e\\x05\\x05\\x0b' ⊕ b'poule' = b'lapin'\n" ] } ], "execution_count": 3, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:28:20.421Z", "iopub.execute_input": "2020-10-11T21:28:20.446Z", "iopub.status.idle": "2020-10-11T21:28:20.559Z", "shell.execute_reply": "2020-10-11T21:28:20.627Z" } } }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 1.** Déchiffrer le message ``l`` ci-dessous qui a été chiffré par le chiffrement du XOR avec la clé ``CAKE``." ], "metadata": {} }, { "cell_type": "code", "source": [ "l = [1, 51, 42, 51, 44, 109, 107, 51, 44, 52, 56, 101, 48, 32, 61, 32, 57, 97, 62, 49, 42, 45, 34, 54, 38, 51, 107, 41, 38, 97, 40, 45, 42, 39, 45, 55, 38, 44, 46, 43, 55, 97, 59, 36, 49, 97, 51, 42, 49, 97, 46, 43, 99, 17, 50, 49, 43, 46, 37, 101, 98]" ], "outputs": [], "execution_count": 3, "metadata": {} }, { "cell_type": "markdown", "source": [ "Il est temps de lire un peu de documentation avant de chiffrer des messages :\n", "1. [Crypto.Cipher](https://www.pycryptodome.org/en/latest/src/cipher/cipher.html) permet de manipuler les briques de chiffrement symétrique comme ``AES`` en précisant le mode opératoire ;\n", "2. [Crypto.Util.Padding](https://www.pycryptodome.org/en/latest/src/util/util.html#crypto-util-padding-module) permet le bourrage réversible des séquences d'octet pour obtenir des séquences de longueur multiple de la taille d'un bloc ;\n", "3. [Crypto.Random](https://www.pycryptodome.org/en/latest/src/random/random.html) permet de générer des séquences pseudo-aléatoires de qualité cryptographique.\n", "\n", "Voici comment chiffrer un message avec une clé et un IV aléatoire :" ], "metadata": {} }, { "cell_type": "code", "source": [ "from Crypto.Cipher import AES\n", "from Crypto.Util.Padding import pad, unpad\n", "from Crypto.Random import get_random_bytes\n", "\n", "k = get_random_bytes(32)\n", "m = b\"Je code en Python et c'est ma joie.\"\n", "p = pad(m,16)\n", "cipher = AES.new(k,AES.MODE_CBC)\n", "c = cipher.encrypt(p)\n", "iv = cipher.iv\n", "\n", "print(\"c =\",repr(c))\n", "print(\"k =\",repr(k))\n", "print(\"iv =\",repr(iv))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "c = b\"a\\xd9\\xbe9\\xfa\\xfc\\x07\\xe5\\xf1J\\xf2\\x8e<\\x9f\\xb3\\xaf\\xc4\\xc1\\xf4z\\n\\xd7-\\xd2\\xd5\\xf7\\x89\\xb8\\x8f\\x9e-_`\\x9e'\\xad:(\\xb6\\xc1\\xca\\x8aBh\\x04\\xb4\\xac\\xcd\"\n", "k = b'\\xebV\\xae\\xcf\\xe9\\x99\\xad\\x88\\xaa\\x1dVs\\x8c\\x92\\xfe\\x04\\x9bzqH\\xae\\xdfU\\x03\\n\\x80\\x18Obf\\xeb\\xdd'\n", "iv = b':s\\x03\\xfd\\xd1-L\\xba%nlA5\\xcf\\xe2\\x1c'\n" ] } ], "execution_count": 4, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:28:43.473Z", "iopub.execute_input": "2020-10-11T21:28:43.488Z", "iopub.status.idle": "2020-10-11T21:28:43.734Z", "shell.execute_reply": "2020-10-11T21:28:43.776Z" } } }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 2.** Déchiffrer le message ``c`` ci-dessous, chiffré en mode CBC avec la clé ``k`` et l'IV ``iv``, à l'aide de ``Crypto.Cipher.AES`` !" ], "metadata": {} }, { "cell_type": "code", "source": [ "c = b\"\\xcf\\xbcs\\xe4\\xa3\\xeb\\x96\\xa6\\xe9\\xa9\\xd5\\xf5Ob\\x91\\x8f\\x8d9\\xa2\\x1f\\x16\\xcft\\xcf\\xcf\\xc7\\xe3\\x1d\\xd9'.\\x81'U\\xf6(\\x96\\xe4&\\x166n3\\xc5d\\x94]\\xf3\\xb0\\x98\\x88\\xd9\\x1ew\\xde\\x06\\xa6\\x91,\\x82\\xd7\\x06,.hJc\\xd2\\xe2\\x1cA\\xc6g\\xc5IM\\xd5\\x059%\\xa1=\\xfct\\x03\\xdf\\xc3[r\\n/\\xcf9\\xd9\\xaa\\xb0\"\n", "iv = b'\\x14\\xb0\\x8b\\x0c\\xc0\\xe1\\xa3Duj|\\x0e\\xf5T\\xebv'\n", "k = b\"There is no cake\"" ], "outputs": [], "execution_count": 5, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:28:56.015Z", "iopub.execute_input": "2020-10-11T21:28:56.028Z", "iopub.status.idle": "2020-10-11T21:28:56.046Z", "shell.execute_reply": "2020-10-11T21:28:56.060Z" } } }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 3.** Les deux messages ``c`` et ``d`` ci-dessous ont été chiffrés avec AES en mode CTR avec une clé inconnue. Ils sont préfixés par leur _nonce_ (l'équivalent de l'IV en mode CTR, codé ici sur 8 octets). Un indice : l'un des message commence par ``Bravo``." ], "metadata": {} }, { "cell_type": "code", "source": [ "c = b\"\\xe7\\xa5\\xfd\\xe9\\xd9B*\\xa5iI\\xc9\\xbc\\x9d\\xe1\\x85\\x00'\\x91/\\xd2\\xd8\\x0b\\xa3lho\\xfd\"\n", "d = b'\\xe7\\xa5\\xfd\\xe9\\xd9B*\\xa5nC\\xcb\\xaf\\x9e\\xad\\xc1N\\x10\\x96>\\xd3\\xcd]\\xa0la!\\xf2'\n", "e = strxor(c,d)\n", "print(repr(e))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x07\\n\\x02\\x13\\x03LDN7\\x07\\x11\\x01\\x15V\\x03\\x00\\tN\\x0f'\n" ] } ], "execution_count": 6, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:29:10.297Z", "iopub.execute_input": "2020-10-11T21:29:10.314Z", "iopub.status.idle": "2020-10-11T21:29:10.345Z", "shell.execute_reply": "2020-10-11T21:29:10.358Z" } } }, { "cell_type": "markdown", "source": [ "## 2. Attaque padding CBC\n", "\n", "Le code ci-dessous reproduit le protocole étudié en cours (l'envoi du message en moins) :\n", "- ``alice`` chiffre le message à envoyer à l'aide d'AES-256-CBC après avoir appliqué le bourrage et retourne la concaténation de l'IV et du message ainsi chiffré ;\n", "- ``bob`` déchiffre le message reçu grâce à l'IV, applique le débourrage et retourne le message déchiffré ou ``None`` si le bourrage est incorrect ;\n", "- ``oracle`` permet de savoir si ``bob`` serait capable ou non de déchiffrer le message (c'est l'équivalent du message ACK/NACK du cours).\n", "\n", "Le but de l'exercice est d'écrire une fonction ``attaque(c)`` capable de déchiffrer tout message ``c`` obtenu en appelant ``alice(m)`` pour un certain ``m``. Cette fonction ``attaque`` n'a pas le droit d'utiliser la clé ``k`` mais elle peut appeler la fonction ``oracle`` autant de fois qu'elle le souhaite." ], "metadata": {} }, { "cell_type": "code", "source": [ "key=get_random_bytes(32)\n", "\n", "def alice(m):\n", " p=pad(m,16)\n", " cipher=AES.new(key,AES.MODE_CBC)\n", " c=cipher.iv+cipher.encrypt(p)\n", " return c\n", "\n", "def bob(m):\n", " iv=m[:16]\n", " c=m[16:]\n", " cipher=AES.new(key,AES.MODE_CBC,iv=iv)\n", " p=cipher.decrypt(c)\n", " try:\n", " m=unpad(p,16)\n", " return m\n", " except ValueError:\n", " return None\n", "\n", "def oracle(m):\n", " return bob(m) is not None" ], "outputs": [], "execution_count": 7, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:29:51.573Z", "iopub.execute_input": "2020-10-11T21:29:51.586Z", "iopub.status.idle": "2020-10-11T21:29:51.611Z", "shell.execute_reply": "2020-10-11T21:29:51.624Z" } } }, { "cell_type": "markdown", "source": [ "Voici un exemple d'utilisation des fonctions ``alice``, ``bob`` et ``oracle`` :" ], "metadata": {} }, { "cell_type": "code", "source": [ "m=b\"Coucou c'est moi !\"\n", "print(\"pad(m) =\",pad(m,16))\n", "c=alice(m)\n", "print(\"c =\",c, \"(longueur :\", len(c)//16,\"blocs dont IV)\")\n", "print(\"oracle(c) =\",oracle(c))\n", "print(\"bob(c) =\",bob(c))\n", "d=strxor(c,bytes(len(c)-3) + b\"XXX\")\n", "print(\"oracle(d) =\",oracle(d))\n", "print(\"bob(d) =\",bob(d))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "pad(m) = b\"Coucou c'est moi !\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\\x0e\"\n", "c = b'\\xb1\\xfa\\x0e\\x18\\x05\\xf7\\x80U\\xe5\\x07\\xa8\\x1b(iY\\xabO`!$\\xf2y\\xd1\\x8fi\\xeeM}\\xd7\\xfc\\xc9yH\\x15\\x87]\\xe9\\x07\\xb2\\x91\\xdeG\\x80\\x90c\\x8d2X' (longueur : 3 blocs dont IV)\n", "oracle(c) = True\n", "bob(c) = b\"Coucou c'est moi !\"\n", "oracle(d) = False\n", "bob(d) = None\n" ] } ], "execution_count": 8, "metadata": { "execution": { "iopub.status.busy": "2020-10-11T21:30:06.313Z", "iopub.execute_input": "2020-10-11T21:30:06.329Z", "iopub.status.idle": "2020-10-11T21:30:06.354Z", "shell.execute_reply": "2020-10-11T21:30:06.366Z" } } }, { "cell_type": "markdown", "source": [ "En mode CBC, le déchiffrement du ième bloc $C_i$ chiffré d'un message en clair $M_i$ nécessite de connaître uniquement la clé $K$ et le (i-1)ème bloc chiffré $C_{i-1}$ (avec la convention $C_0=\\operatorname{IV}$) :\n", "$$\n", "M_i = D_K(C_i) \\oplus C_{i-1}\n", "$$\n", "\n", "Dans la suite on se concentre donc sur le déchiffrement d'un unique bloc $C$ à partir de son IV $I$ (la méthode se généralise ensuite à tout bloc $C_i$ avec l'IV $C_{i-1}$).\n", "\n", "Si, au lieu de transmettre $I\\cdot C$ à l'oracle, on lui transmet $(I\\oplus\\Delta)\\cdot C$, l'oracle va tester si $M\\oplus\\Delta$ possède un bourrage valide. En effet :\n", "$$\n", "M \\oplus \\Delta = (D_K(C) \\oplus I) \\oplus \\Delta = D_K(C) \\oplus (I \\oplus \\Delta)\n", "$$\n", "\n", "Un message possède un bourrage valide si et seulement si il termine par la séquence $k k \\cdots k$ qui répète $k$ fois une certaine valeur $k$.\n", "\n", "En particulier lorsque $I\\oplus \\Delta$ termine par la valeur 1, l'oracle valide le message. Il suffit pour cela de modifier uniquement le dernier octet de $I$ en trouvant le bon élément parmi les 256 possible." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 4.** Écrire une fonction ``flip(iv,j)`` qui retourne le bloc ``iv`` reçu en entrée dans lequel le dernier octet a été remplacé par son XOR avec l'entier ``j`` (c'est à dire par ``iv[-1] ^ j``). Utiliser cette fonction pour afficher parmi les 256 valeurs possibles pour ``j`` celles pour lesquels l'oracle valide ``flip(iv,j) + b``. En déduire le dernier caractère du déchiffrement de ``b``." ], "metadata": {} }, { "cell_type": "code", "source": [ "iv=c[:16]\n", "b=c[16:32]\n", "\n", "def flip(c,j):\n", " # TODO\n", " pass\n", "\n", "for j in range(256):\n", " # TODO\n", " pass" ], "outputs": [], "execution_count": 10, "metadata": {} }, { "cell_type": "markdown", "source": [ "Une fois qu'on a trouvé le dernier caractère en clair de $M$, on sait comment modifier le dernier octet de $I$ pour que $I\\oplus\\Delta$ termine par la valeur $2$. Il suffit d'utiliser l'oracle pour trouver la modification (parmi 256) à appliquer à l'avant-dernier octet de $I$ pour que $I\\oplus\\Delta$ termine par le padding valide $22$. Et on itère !" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 5.** Écrire une fonction ``gnapgnap(iv,b)`` qui déchiffre le bloc ``b`` à l'aide de l'oracle. En déduire une fonction ``attaque(c)`` qui déchiffre complétement un message ``c`` produit par un certain ``alice(m)`` sans utiliser la clé." ], "metadata": {} }, { "cell_type": "code", "source": [ "def gnapgnap(iv,b):\n", " # TODO\n", " pass\n", "\n", "print(gnapgnap(iv,b))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "None\n" ] } ], "execution_count": 11, "metadata": {} }, { "cell_type": "code", "source": [ "def attaque(c):\n", " # TODO\n", " pass\n", "\n", "print(attaque(c))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "None\n" ] } ], "execution_count": 12, "metadata": {} }, { "cell_type": "markdown", "source": [ "## 3. Attaque ChopChop contre WEP" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "_Ce dernier exercice est un exercice bonus pour ceux que l'exercice précédent aurait laissés sur leur faim._" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Le (désuet) protocole WEP chiffre les trames Wifi (IEEE 802.11) à l'aide de l'algorithme de chiffrement par flot RC4. Le contrôle d'intégrité est assuré par l'utilisation d'un checksum CRC32. Pour transmettre un message $M$ avec la clé secrète $K$ de 40 ou 104 bits, un IV aléatoire de 24 bits $\\mbox{IV}$ est généré, le CRC32 $\\operatorname{icv}(M)$ est concaténé au message $M$ et l'ensemble est masqué avec le flot RC4 généré par la concaténation de $\\mbox{IV}$ et $K$ :\n", "$$\n", "C = (M \\cdot \\operatorname{icv}(M)) \\oplus \\operatorname{RC4}(\\mbox{IV} \\cdot K)\n", "$$\n", "La paire $\\mbox{IV}\\cdot C$ est alors transmise sur le réseau sans fil.\n", "\n", "À la réception d'un message $\\mbox{IV}\\cdot C$ on calcule :\n", "$$\n", "M' \\cdot J = C \\oplus \\operatorname{RC4}(\\mbox{IV} \\cdot K)\n", "$$\n", "Si $J = \\operatorname{icv}(M')$ alors le message $M'$ est accepté. Sinon le message est rejetté silencieusement (pas d'acquittement négatif)." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Ce protocole a de nombreux défauts et il est possible aujourd'hui de trouver la clé d'un réseau WEP en moins de 60s en utilisant des faiblesses statistiques de l'algorithme RC4. Nous allons nous intéresser ici à une attaque apparue à partir de 2004 et connue sous le nom _ChopChop_. Cette attaque utilise les propriétés de linéarité de CRC32 pour s'en servir comme oracle pour déchiffrer un message (et donc obtenir la séquence $\\operatorname{RC4}(\\mbox{IV}\\cdot K)$ de longueur $|M|+4$)." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Le code ci-dessous met en œuvre le calcul d'$\\operatorname{icv}(M)$ :" ], "metadata": {} }, { "cell_type": "code", "source": [ "crc_tab=[0]*256 \n", "for i in range(256):\n", " r = i\n", " for j in range(8):\n", " if r & 1:\n", " r = (r>>1) ^ 0xedb88320\n", " else:\n", " r >>= 1\n", " crc_tab[i ^ 0xff] = r ^ 0xff000000\n", "\n", "def crc32(buf, crc=0):\n", " for k in buf:\n", " crc = (crc >> 8) ^ crc_tab[(crc & 0xff) ^ k] \n", " return crc\n", "\n", "def lsb(x,k=4):\n", " r=[]\n", " for i in range(k):\n", " r.append(x & 0xff)\n", " x>>=8\n", " return bytes(r)\n", "\n", "def icv(buf):\n", " return lsb(crc32(buf))" ], "outputs": [], "execution_count": 13, "metadata": {} }, { "cell_type": "markdown", "source": [ "Nous allons reproduire la même attaque en remplaçant RC4 par AES-256-CTR, qui est aussi un chiffrement par flot. Le code ci-dessous met en œuvre ce protocole sous la forme de deux fonctions ``alice`` et ``bob`` et une fonction ``oracle``." ], "metadata": {} }, { "cell_type": "code", "source": [ "def nonce(): \n", " return get_random_bytes(8)\n", "\n", "def alice(m):\n", " no=nonce()\n", " mc=m + icv(m)\n", " ci=AES.new(key,AES.MODE_CTR,nonce=no)\n", " return no + ci.encrypt(mc)\n", "\n", "def bob(c):\n", " no=c[:8]\n", " ci=AES.new(key,AES.MODE_CTR,nonce=no)\n", " mc=ci.decrypt(c[8:])\n", " ic=mc[-4:]\n", " m=mc[:-4]\n", " if icv(m) == ic:\n", " return m\n", " else:\n", " return None\n", "\n", "def oracle(c):\n", " return bob(c) is not None" ], "outputs": [], "execution_count": 14, "metadata": {} }, { "cell_type": "markdown", "source": [ "Voici un exemple d'utilisation des fonctions ``alice``, ``bob`` et ``oracle`` :" ], "metadata": {} }, { "cell_type": "code", "source": [ "m=b\"Tranchez leur la tete !\"\n", "c=alice(m)\n", "print(\"c =\",c)\n", "print(\"oracle(c) =\",oracle(c))\n", "print(\"bob(c) =\",bob(c))\n", "d=strxor(c,b\"XXX\" + bytes(len(c)-3))\n", "print(\"oracle(d) =\",oracle(d))\n", "print(\"bob(d) =\",bob(d))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "c = b'\\xffq\\x14\\x83\\x17h\\xfd\\x10v\\xebs\\xdf\\x8b,\\x94#*\\x1b\\xb1\"\\x9b\\x9b\\xd6\\xdc\\x19W#\\xdd\\xf8(\\xdb\\xe3\\xb7{\\xf0'\n", "oracle(c) = True\n", "bob(c) = b'Tranchez leur la tete !'\n", "oracle(d) = False\n", "bob(d) = None\n" ] } ], "execution_count": 15, "metadata": {} }, { "cell_type": "markdown", "source": [ "L'attaque consiste à transformer le chiffrement $C = C_1 C_2 \\cdots C_{n+4}$ d'un message $M = M_1 M_2 \\cdots M_n$ en un chiffré valide $D = D_1 D_2 \\cdots D_{n+3}$ du message tronqué $M' = M_1 M_2 \\cdots M_{n-1}$ en utilisant l'oracle pour faire un choix parmi 256 (comme dans l'attaque de l'exercice précédent). " ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Notons $K = K_1 K_2 \\cdots K_{n+4}$ le masque, $I = \\operatorname{icv}(M)$ et $J = \\operatorname{icv}(M')$. Alors on a les égalités suivantes :\n", "$$\n", "\\begin{array}{cccccccccc}\n", "& M_1 & M_2 & \\cdots & M_{n-1} & M_n & I_1 & I_2 & I_3 & I_4\\\\\n", "\\oplus & K_1 & K_2 & \\cdots & K_{n-1} & K_n & K_{n+1} & K_{n+2} & K_{n+3} & K_{n+4}\\\\\\hline\n", "& C_1 & C_2 & \\cdots & C_{n-1} & C_n & C_{n+1} & C_{n+2} & C_{n+3} & C_{n+4}\n", "\\end{array}\n", "$$\n", "et\n", "$$\n", "\\begin{array}{ccccccccccc}\n", "& M_1 & M_2 & \\cdots & M_{n-1} & J_1 & J_2 & J_3 & J_4 & \\phantom{I_4}\\\\\n", "\\oplus & K_1 & K_2 & \\cdots & K_{n-1} & K_n & K_{n+1} & K_{n+2} & K_{n+3} & \\phantom{K_{n+4}}\\\\\\hline\n", "& D_1 & D_2 & \\cdots & D_{n-1} & D_n & D_{n+1} & D_{n+2} & D_{n+3} & \\phantom{D_{n+4}}\n", "\\end{array}\n", "$$" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Les $n-1$ premières valeurs de $D_i$ sont égales aux $C_i$. Notons $X$ la modification à apporter à $C_n$ pour obtenir $D_n$, _i.e._ $X = C_n \\oplus D_n = M_n \\oplus J_1$." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 6.** En étudiant le code de CRC32, montrer comment calculer $D_{n+1}$, $D_{n+2}$, $D_{n+3}$ et $K_{n+4}$ à partir de $X$. On pourra commencer par chercher comment calculer $I$ à partir de $J$." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 7.** Écrire une fonction ``chop(c)`` qui à partir d'un message chiffré $C$ retourne une paire ``(d,x)`` où ``d`` est le chiffré du message tronqué $D$ et ``k`` le dernier octet du masque $K_{n+4}$." ], "metadata": {} }, { "cell_type": "code", "source": [ "def chop(c):\n", " # TODO\n", " pass\n", "\n", "print(chop(c))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "None\n" ] } ], "execution_count": 16, "metadata": {} }, { "cell_type": "markdown", "source": [ "✏️✏️✏️ **Question 8.** En déduire une fonction ``chopchop(c)`` qui déchiffre un message chiffré généré par ``alice(m)`` sans utiliser la clé secrète mais en utilisant l'oracle." ], "metadata": {} }, { "cell_type": "code", "source": [ "def chopchop(c):\n", " # TODO\n", " pass\n", "\n", "print(chopchop(c))" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "None\n" ] } ], "execution_count": 17, "metadata": {} } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.6.11", "mimetype": "text/x-python", "codemirror_mode": { "name": "ipython", "version": 3 }, "pygments_lexer": "ipython3", "nbconvert_exporter": "python", "file_extension": ".py" }, "nteract": { "version": "0.25.1" } }, "nbformat": 4, "nbformat_minor": 2 }