diff --git a/M2/Cybersecurity/LSB_GSB.ipynb b/M2/Cybersecurity/LSB_GSB.ipynb new file mode 100644 index 0000000..107f41e --- /dev/null +++ b/M2/Cybersecurity/LSB_GSB.ipynb @@ -0,0 +1,624 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "siM8xBq5kDja" + }, + "outputs": [], + "source": [ + "from PIL import Image\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "QeDEw-sukFj9" + }, + "outputs": [], + "source": [ + "def texte_vers_binaire(texte):\n", + " \"\"\"Convertit un string en une chaîne de caractères binaires (8 bits par caractère).\"\"\"\n", + " return \"\".join(format(ord(c), \"08b\") for c in texte)\n", + "\n", + "def binaire_vers_texte(chaine_binaire):\n", + " \"\"\"Convertit une chaîne de caractères binaires en string.\"\"\"\n", + " octets = [chaine_binaire[i:i+8] for i in range(0, len(chaine_binaire), 8)]\n", + " return \"\".join(chr(int(octet, 2)) for octet in octets if len(octet) == 8)\n", + "\n", + "DELIMITEUR = \"#####\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "ULmRSCIExZ2j" + }, + "outputs": [], + "source": [ + "def cacher_message(chemin_image_entree, message_secret, chemin_image_sortie):\n", + " # On ouvre l'image et on s'assure qu'elle est en 8-bits (Niveaux de gris = mode 'L')\n", + " img = Image.open(chemin_image_entree).convert(\"L\")\n", + " pixels = np.array(img)\n", + "\n", + " # On ajoute le délimiteur à la fin du message et on convertit tout en binaire\n", + " message_complet = message_secret + DELIMITEUR\n", + " message_binaire = texte_vers_binaire(message_complet)\n", + "\n", + " # On aplatit le tableau de pixels en 1D pour faciliter le parcours\n", + " pixels_plats = pixels.flatten()\n", + "\n", + " # Vérification de la capacité de l'image\n", + " if len(message_binaire) > len(pixels_plats):\n", + " raise ValueError(\"Message is too long for the image.\")\n", + "\n", + " # Remplacement du bit de poids faible (LSB)\n", + " for i in range(len(message_binaire)):\n", + " bit_a_cacher = int(message_binaire[i])\n", + " # L'opération bit à bit '& 254' force le dernier bit à 0, puis on fait un 'OU' avec notre bit\n", + " pixels_plats[i] = (pixels_plats[i] & 254) | bit_a_cacher\n", + "\n", + " # On redonne à l'image sa forme originale et on sauvegarde\n", + " pixels_modifies = pixels_plats.reshape(pixels.shape)\n", + " img_modifiee = Image.fromarray(pixels_modifies, mode=\"L\")\n", + " img_modifiee.save(chemin_image_sortie, format=\"BMP\")\n", + " print(f\"Message succesfully hidden in : {chemin_image_sortie}\")\n", + "\n", + "# --- 3. FONCTION POUR EXTRAIRE LE MESSAGE (DÉCODAGE LSB) ---\n", + "\n", + "def extraire_message(chemin_image):\n", + " # On ouvre l'image modifiée\n", + " img = Image.open(chemin_image).convert(\"L\")\n", + " pixels_plats = np.array(img).flatten()\n", + "\n", + " bits_extraits = []\n", + "\n", + " # On récupère le dernier bit de chaque pixel\n", + " for pixel in pixels_plats:\n", + " bits_extraits.append(str(pixel & 1))\n", + "\n", + " chaine_binaire_complete = \"\".join(bits_extraits)\n", + "\n", + " # On lit le binaire par paquets de 8 bits (1 octet = 1 caractère)\n", + " message_decode = \"\"\n", + " for i in range(0, len(chaine_binaire_complete), 8):\n", + " octet = chaine_binaire_complete[i:i+8]\n", + " if len(octet) < 8:\n", + " break\n", + " caractere = chr(int(octet, 2))\n", + " message_decode += caractere\n", + "\n", + " # On s'arrête si on détecte le délimiteur\n", + " if message_decode.endswith(DELIMITEUR):\n", + " # On retourne le message sans le délimiteur\n", + " return message_decode[:-len(DELIMITEUR)]\n", + "\n", + " return \"No hidden message found (or delimiter not found).\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "g_e4U9O4lIOb" + }, + "outputs": [], + "source": [ + "nom_fichier_sortie = \"image_secrete.bmp\"\n", + "mon_message = \"Decode this!\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "oLpz4m1vk-zF", + "outputId": "1cdb06cb-9c4e-4131-b7a3-d76be6930c11" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Image 'image_test_8bits.bmp' created successfully!\n" + ] + } + ], + "source": [ + "# 1. On définit la taille de l'image (par exemple 256 pixels par 256 pixels)\n", + "largeur, hauteur = 256, 256\n", + "\n", + "# 2. On crée un tableau rempli de zéros (qui correspondra à du noir)\n", + "pixels = np.zeros((hauteur, largeur), dtype=np.uint8)\n", + "\n", + "# 3. On crée un dégradé horizontal\n", + "# Chaque colonne prend la valeur de son index (de 0 à 255)\n", + "for x in range(largeur):\n", + " pixels[:, x] = x\n", + "\n", + "# 4. On convertit le tableau NumPy en image PIL (mode 'L' = 8 bits niveaux de gris)\n", + "image_test = Image.fromarray(pixels, mode=\"L\")\n", + "\n", + "# 5. On sauvegarde le fichier au format BMP\n", + "nom_fichier = \"image_test_8bits.bmp\"\n", + "image_test.save(nom_fichier, format=\"BMP\")\n", + "\n", + "print(f\"Image '{nom_fichier}' created successfully!\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 602 + }, + "id": "s9NtmhpUkU8T", + "outputId": "699b8055-5e19-4fde-94fc-44464672a291" + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAEAAQABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APAkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSv/2Q==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAACuUlEQVR4AWJkYBzZgIlhhIPRABjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoCgBshCcABgCdkAL/fkEcHQAAAABJRU5ErkJggg==", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Message succesfully hidden in : image_secrete.bmp\n" + ] + }, + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAEAAQABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APAkqwlWEqylTpVhKsJVhKsJVhKspU6VYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK//2Q==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAAEwElEQVR4AWJkYGRkYAJjpv9MjCDA9J+JgZmBkZHpPzMDE5hGkWdg/s/EwMTAxAiSA+ll+g8WAakHm8DEwAjSD1HHyAimmUFiEHNx8UFWDwBmYmBgYITg/yCagYHhPyMD438w/Z8BQqPIM4LkQXpAcmAaIsLwH0SD9DGA9YN4IBPB9H+QGMRcXHyGgQGgABgYmweJraMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEotHA2CQRMSAOWM0AAYs6AeJxaMBMEgiYsCcMRoAAxb0g8Ti0QAYJBExYM4YDYABC/pBYvFoAAySiBgwZ4wGwIAF/SCxeDQABklEDJgzRgNgwIJ+kFg8GgCDJCIGzBmjATBgQT9ILB4NgEESEQPmjNEAGLCgHyQWjwbAIImIAXPGaAAMWNAPEosBG/EBAACB7C4KJpffiQAAAABJRU5ErkJggg==", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Message : Decode this!\n" + ] + } + ], + "source": [ + "display(Image.open(nom_fichier))\n", + "# 2. Cacher le message\n", + "cacher_message(nom_fichier, mon_message, nom_fichier_sortie)\n", + "\n", + "#display the image\n", + "display(Image.open(nom_fichier_sortie))\n", + "\n", + "# 3. Extraire le message\n", + "message_trouve = extraire_message(nom_fichier_sortie)\n", + "print(f\"Message : {message_trouve}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "HUvxyPw-knd9" + }, + "outputs": [], + "source": [ + "image_sortie = Image.open(nom_fichier_sortie)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 562 + }, + "id": "YW7UFBzMn7I7", + "outputId": "ddfdd830-f1ff-465a-d2e5-e45767510400" + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Message is too long for the image.", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 8\u001b[39m\n\u001b[32m 5\u001b[39m image_stego = \u001b[33m\"\u001b[39m\u001b[33mimage_secrete.bmp\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;66;03m# On cache ce long message dans notre image de test\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m8\u001b[39m \u001b[43mcacher_message\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimage_originale\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlong_message\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mimage_stego\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 10\u001b[39m \u001b[38;5;66;03m# 2. Fonction pour extraire tous les LSB d'une image\u001b[39;00m\n\u001b[32m 11\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mextraire_tous_les_lsb\u001b[39m(chemin_image):\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 15\u001b[39m, in \u001b[36mcacher_message\u001b[39m\u001b[34m(chemin_image_entree, message_secret, chemin_image_sortie)\u001b[39m\n\u001b[32m 13\u001b[39m \u001b[38;5;66;03m# Vérification de la capacité de l'image\u001b[39;00m\n\u001b[32m 14\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(message_binaire) > \u001b[38;5;28mlen\u001b[39m(pixels_plats):\n\u001b[32m---> \u001b[39m\u001b[32m15\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mMessage is too long for the image.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 17\u001b[39m \u001b[38;5;66;03m# Remplacement du bit de poids faible (LSB)\u001b[39;00m\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;28mlen\u001b[39m(message_binaire)):\n", + "\u001b[31mValueError\u001b[39m: Message is too long for the image." + ] + } + ], + "source": [ + "# 1. Préparation d'un LONG message pour que l'effet stégo soit visible\n", + "# On crée un faux message assez long pour remplir une bonne partie de l'image (256x256 = 65536 pixels)\n", + "long_message = \"Check if we can decode everything, like long messages\" * 200\n", + "image_originale = \"image_test_8bits.bmp\"\n", + "image_stego = \"image_secrete.bmp\"\n", + "\n", + "# On cache ce long message dans notre image de test\n", + "cacher_message(image_originale, long_message, image_stego)\n", + "\n", + "# 2. Fonction pour extraire tous les LSB d'une image\n", + "def extraire_tous_les_lsb(chemin_image):\n", + " img = Image.open(chemin_image).convert(\"L\")\n", + " pixels = np.array(img).flatten()\n", + " # On récupère uniquement le dernier bit avec l'opérateur '& 1'\n", + " return pixels & 1\n", + "\n", + "# On extrait les LSB des deux images\n", + "lsb_orig = extraire_tous_les_lsb(image_originale)\n", + "lsb_stego = extraire_tous_les_lsb(image_stego)\n", + "\n", + "# 3. Création des graphiques avec Matplotlib\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # 1 ligne, 2 colonnes\n", + "\n", + "# --- Graphique de gauche : Image Stego ---\n", + "ax1.hist(lsb_stego, bins=[-0.5, 0.5, 1.5], edgecolor=\"black\", alpha=0.7)\n", + "ax1.set_title(\"Histogramme des LSB - Image Stego\")\n", + "ax1.set_xticks([0, 1])\n", + "ax1.set_xticklabels([\"LSB=0\", \"LSB=1\"])\n", + "ax1.set_ylabel(\"Nombre d'occurrences\")\n", + "\n", + "# --- Graphique de droite : Image Originale ---\n", + "ax2.hist(lsb_orig, bins=[-0.5, 0.5, 1.5], edgecolor=\"black\", alpha=0.7)\n", + "ax2.set_title(\"Histogramme des LSB - Image Originale\")\n", + "ax2.set_xticks([0, 1])\n", + "ax2.set_xticklabels([\"LSB=0\", \"LSB=1\"])\n", + "ax2.set_ylabel(\"Nombre d'occurrences\")\n", + "\n", + "# Affichage du résultat\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0ZLEleEjmyyZ" + }, + "source": [ + "GSB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Y4uXeBJ_m7D7" + }, + "outputs": [], + "source": [ + "def cacher_messageGSB(chemin_image_entree, message_secret, chemin_image_sortie):\n", + " # On ouvre l'image et on s'assure qu'elle est en 8-bits (Niveaux de gris = mode 'L')\n", + " img = Image.open(chemin_image_entree).convert(\"L\")\n", + " pixels = np.array(img)\n", + "\n", + " # On ajoute le délimiteur à la fin du message et on convertit tout en binaire\n", + " message_complet = message_secret + DELIMITEUR\n", + " message_binaire = texte_vers_binaire(message_complet)\n", + "\n", + " # On aplatit le tableau de pixels en 1D pour faciliter le parcours\n", + " pixels_plats = pixels.flatten()\n", + "\n", + " # Vérification de la capacité de l'image\n", + " if len(message_binaire) > len(pixels_plats):\n", + " raise ValueError(\"The image is too small.\")\n", + "\n", + " # Remplacement du bit de poids faible (LSB)\n", + " for i in range(len(message_binaire)):\n", + " bit_a_cacher = int(message_binaire[i])\n", + " # bit_a_cacher << 7 décale le bit de 7 crans vers la gauche\n", + " pixels_plats[i] = (pixels_plats[i] & 127) | (bit_a_cacher << 7)\n", + "\n", + " # On redonne à l'image sa forme originale et on sauvegarde\n", + " pixels_modifies = pixels_plats.reshape(pixels.shape)\n", + " img_modifiee = Image.fromarray(pixels_modifies, mode=\"L\")\n", + " img_modifiee.save(chemin_image_sortie, format=\"BMP\")\n", + " print(f\"Message well hidden within : {chemin_image_sortie}\")\n", + "\n", + "# --- 3. FONCTION POUR EXTRAIRE LE MESSAGE (DÉCODAGE LSB) ---\n", + "\n", + "def extraire_messageGSB(chemin_image):\n", + " # On ouvre l'image modifiée\n", + " img = Image.open(chemin_image).convert(\"L\")\n", + " pixels_plats = np.array(img).flatten()\n", + "\n", + " bits_extraits = []\n", + "\n", + " # On récupère le dernier bit de chaque pixel\n", + " for pixel in pixels_plats:\n", + " # On isole le bit de poids fort, puis on le ramène tout à droite\n", + " bits_extraits.append(str((pixel & 128) >> 7))\n", + "\n", + " chaine_binaire_complete = \"\".join(bits_extraits)\n", + "\n", + " # On lit le binaire par paquets de 8 bits (1 octet = 1 caractère)\n", + " message_decode = \"\"\n", + " for i in range(0, len(chaine_binaire_complete), 8):\n", + " octet = chaine_binaire_complete[i:i+8]\n", + " if len(octet) < 8:\n", + " break\n", + " caractere = chr(int(octet, 2))\n", + " message_decode += caractere\n", + "\n", + " # On s'arrête si on détecte le délimiteur\n", + " if message_decode.endswith(DELIMITEUR):\n", + " # On retourne le message sans le délimiteur\n", + " return message_decode[:-len(DELIMITEUR)]\n", + "\n", + " return \"No hidden message found (or delimiter not found).\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 602 + }, + "id": "74Rinzm2nM7x", + "outputId": "5a12f02b-6db5-431b-f872-b28e57dd12fe" + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAEAAQABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APAkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSv/2Q==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAACuUlEQVR4AWJkYBzZgIlhhIPRABjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoChjhCWA0BYymgNEsMMLBaAoY4QlgNAWMpoDRLDDCwWgKGOEJYDQFjKaA0SwwwsFoCgBshCcABgCdkAL/fkEcHQAAAABJRU5ErkJggg==", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Message well hidden within : image_secrete.bmp\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/qx/qc20ksl50kb3r1gbtqwgqm2h0000gn/T/ipykernel_3336/3844268843.py:25: DeprecationWarning: 'mode' parameter is deprecated and will be removed in Pillow 13 (2026-10-15)\n", + " img_modifiee = Image.fromarray(pixels_modifies, mode='L')\n" + ] + }, + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAEAAQABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APBlnmO7Msh3IEbLHlRjAPsNo49h6Vcjv7wMjC7n3Iioh8w5VVIKgegBAIHYirEV/eLNFMt3OJYU2RuJDuRemAew5PA9auQatqUOPK1C7TCKg2zMPlXOB16DJwPenfa7mRQslxKwEYiwzk/IDkL9AQDjpVqO/vAyMLufciKiHzDlVUgqB6AEAgdiKcJHdUVnZgg2qCc7RknA9OST+NXjf3ksKwyXc7xKmxUaQlQvBwB6fKvHsPSpjd3M0axy3EsiKFVVZyQAudoA9snHpk1aW/vD5ebuc+Vt8v8AeH5NuduPTGTj0yatR6nfhoGF7cgwArCfNb92CMYXnjjjinRTzK0TLLIGh/1ZDHKc549OSTx3NWre7uYJIpIriWN4gVjZHIKA5yAe3U/masW93cwSRSRXEsbxArGyOQUBzkA9up/M1Yt7u5gkikiuJY3iBWNkcgoDnIB7dT+Zqzb3dzBJFJFcSxvECsbI5BQHOQD26n8zVa30ywgkikisraN4gVjZIlBQHOQDjjqfzNaaVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK+BkqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWUqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlfAyVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrKVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSvgZKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVlKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJXwMlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqylWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEqwlWEr4GSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVZSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCVYSrCV8DJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKspVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhKsJVhK/9k=", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAAC8UlEQVR4AWJkaGxkZARjxkbGRhBgBAmAhECiYBpEgGTB8mAOIyNYFUgFWBeY39gIZTdCFYNEQUIgxbhomOWMAwUYBsriQWIvE8MIB6MBMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEg9EUMMITwGgKGE0Bo1lghIPRFDDCE8BoChhNAaNZYISD0RQwwhPAaAoYTQGjWWCEA8BGfAoAADMZJv0gGr2bAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Message : Decode this!\n" + ] + } + ], + "source": [ + "display(Image.open(nom_fichier))\n", + "# 2. Cacher le message\n", + "cacher_messageGSB(nom_fichier, mon_message, nom_fichier_sortie)\n", + "\n", + "#display the image\n", + "display(Image.open(nom_fichier_sortie))\n", + "\n", + "# 3. Extraire le message\n", + "message_trouve = extraire_messageGSB(nom_fichier_sortie)\n", + "print(f\"Message : {message_trouve}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sITRU6MzoIpA" + }, + "source": [ + "Avec une clé" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4vYMdWoxoIWZ" + }, + "outputs": [], + "source": [ + "def generer_positions(cle, nb_bits_necessaires, max_pixels):\n", + " # On transforme la clé (ex: 1369) en une liste d'entiers [1, 3, 6, 9]\n", + " sauts = [int(chiffre) for chiffre in str(cle)]\n", + "\n", + " positions = []\n", + " pos_actuelle = 0\n", + "\n", + " for i in range(nb_bits_necessaires):\n", + " saut = sauts[i % len(sauts)]\n", + " # Sécurité : si un chiffre de la clé est 0, on avance d'au moins 1\n", + " # pour ne pas écraser le même pixel\n", + " if saut == 0:\n", + " saut = 1\n", + "\n", + " pos_actuelle += saut\n", + "\n", + " # On vérifie qu'on ne dépasse pas la fin de l'image\n", + " if pos_actuelle >= max_pixels:\n", + " raise ValueError(f\"The image is too small. It can only hold {i} bits with this key.\")\n", + "\n", + " positions.append(pos_actuelle)\n", + "\n", + " return positions\n", + "\n", + "# --- 2. ENCODAGE AVEC CLÉ ---\n", + "\n", + "def cacher_message_cle(chemin_image_entree, message_secret, cle, chemin_image_sortie):\n", + " img = Image.open(chemin_image_entree).convert(\"L\")\n", + " pixels_plats = np.array(img).flatten()\n", + "\n", + " message_binaire = texte_vers_binaire(message_secret + DELIMITEUR)\n", + "\n", + " # On génère exactement les positions dont on a besoin\n", + " positions = generer_positions(cle, len(message_binaire), len(pixels_plats))\n", + "\n", + " # On remplace les LSB uniquement sur ces positions précises\n", + " for i in range(len(message_binaire)):\n", + " pos = positions[i]\n", + " bit_a_cacher = int(message_binaire[i])\n", + " pixels_plats[pos] = (pixels_plats[pos] & 254) | bit_a_cacher\n", + "\n", + " img_modifiee = Image.fromarray(pixels_plats.reshape(np.array(img).shape), mode=\"L\")\n", + " img_modifiee.save(chemin_image_sortie, format=\"BMP\")\n", + " print(f\"Hidden message found with key '{cle}' !\")\n", + "\n", + "# --- 3. DÉCODAGE AVEC CLÉ ---\n", + "\n", + "def extraire_message_cle(chemin_image, cle):\n", + " img = Image.open(chemin_image).convert(\"L\")\n", + " pixels_plats = np.array(img).flatten()\n", + "\n", + " sauts = [int(chiffre) for chiffre in str(cle)]\n", + " pos_actuelle = 0\n", + " index_saut = 0\n", + "\n", + " bits_extraits = \"\"\n", + " message_decode = \"\"\n", + "\n", + " # On parcourt l'image en sautant de pixel en pixel selon la clé\n", + " while pos_actuelle < len(pixels_plats):\n", + " saut = sauts[index_saut % len(sauts)]\n", + " if saut == 0: saut = 1\n", + " pos_actuelle += saut\n", + "\n", + " if pos_actuelle >= len(pixels_plats):\n", + " break\n", + "\n", + " # On extrait le bit\n", + " bits_extraits += str(pixels_plats[pos_actuelle] & 1)\n", + " index_saut += 1\n", + "\n", + " # Tous les 8 bits, on convertit en texte\n", + " if len(bits_extraits) == 8:\n", + " message_decode += chr(int(bits_extraits, 2))\n", + " bits_extraits = \"\"\n", + "\n", + " # On s'arrête si on trouve le délimiteur\n", + " if message_decode.endswith(DELIMITEUR):\n", + " return message_decode[:-len(DELIMITEUR)]\n", + "\n", + " return \"No hidden message found.\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pf1ydHiSpkno", + "outputId": "3bf962b6-0169-4ad8-a168-2971c308174c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hidden message found with key '1369' !\n", + "Test right key : Try out keys!\n", + "Test wrong key : No hidden message found.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/qx/qc20ksl50kb3r1gbtqwgqm2h0000gn/T/ipykernel_3336/840764186.py:42: DeprecationWarning: 'mode' parameter is deprecated and will be removed in Pillow 13 (2026-10-15)\n", + " img_modifiee = Image.fromarray(pixels_plats.reshape(np.array(img).shape), mode='L')\n" + ] + } + ], + "source": [ + "image_originale = \"image_test_8bits.bmp\"\n", + "image_stego_cle = \"image_test_stego_cle.bmp\"\n", + "mon_message = \"Try out keys!\"\n", + "ma_cle = 1369\n", + "\n", + "# 1. On cache\n", + "cacher_message_cle(image_originale, mon_message, ma_cle, image_stego_cle)\n", + "\n", + "# 2. On extrait avec la BONNE clé\n", + "print(\"Test right key :\", extraire_message_cle(image_stego_cle, 1369))\n", + "\n", + "# 3. On extrait avec une MAUVAISE clé (ça devrait sortir n'importe quoi ou échouer)\n", + "print(\"Test wrong key :\", extraire_message_cle(image_stego_cle, 4444))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "studies (3.13.9)", + "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.13.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/M2/Cybersecurity/image_secrete.bmp b/M2/Cybersecurity/image_secrete.bmp new file mode 100644 index 0000000..5be97ba Binary files /dev/null and b/M2/Cybersecurity/image_secrete.bmp differ diff --git a/M2/Cybersecurity/image_test_8bits.bmp b/M2/Cybersecurity/image_test_8bits.bmp new file mode 100644 index 0000000..aa5643f Binary files /dev/null and b/M2/Cybersecurity/image_test_8bits.bmp differ diff --git a/README.md b/README.md index e6ea484..661dc91 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ |--------|-------------| | `Advanced Machine Learning` | Advanced ML techniques | | `Clustering In Practice` | Unsupervised learning and clustering | +| `Cybersecurity` | Data security and analysis | | `Data Visualisation` | Data visualization principles and tools | | `Deep Learning` | Neural networks and deep architectures | | `Enjeux Climatiques` | Climate issues and data analysis |