Je vous présente ici une méthode de chiffrement personnel d’images avec Python. Pour se faire, nous allons prendre une image quelconque, par exemple celle-ci:

chiffrement images python

Un chiffrement personnel d’images avec python: préliminaires

Une image est une matrice de triplets ou quadruplets (selon les formats). Pour notre exemple, l’image est au format JPG, donc chaque pixel qui la compose est un triplet (R,B,V).

Il faut donc avant tout récupérer ces triplets à l’aide de Python. Pour cela, nous allons avoir besoin des modules pillow et numpy.

Installation des modules

Si vous avez une distribution standard de Python, vous pouvez les installer à l’aide de “pip”.

pip install pillow numpy

Si vous êtes sous Anaconda, ce sera:

conda install pillow numpy

Récupérations des données de l’images

from PIL import Image
import numpy as np

# Charger l'image
image_path = 'ruban.jpg'
image = Image.open(image_path)

# Convertir l'image en matrice numpy
image_matrix = np.array(image)

# Afficher la matrice
print(image_matrix)

np.array(image) va nous donner une matrice. La matrice commence par:

[[[10 16 28]
  [ 3  9 21]
  [ 6 13 23]
  ...
  [ 6  9 16]
  [ 9  9 17]
  [ 9  9 17]]

Cela signifie que:

  • Le premier pixel en haut à gauche est codé par le RVB : (10,16,28) ➙ 10% de Rouge, 16% de Vert et 28% de Bleu;
  • Le pixel qui est juste à droite du premier est codé par le RVB : (3,9,21);
  • Le pixel qui est juste en-dessous du premier est codé par (6,9,16);
  • etc.

Mieux comprendre la matrice de l’image

Pour simplifier, si notre image faisait 3 pixels sur 3, la matrice pourrait être par exemple:

image_matrix = np.array([
    [[255, 0, 0], [0, 255, 0], [0, 0, 255]],  # Première ligne de pixels
    [[255, 255, 0], [0, 255, 255], [255, 0, 255]],  # Deuxième ligne de pixels
    [[128, 128, 128], [255, 255, 255], [0, 0, 0]]  # Troisième ligne de pixels
])

Le chiffrement de l’image avec python

Maintenant, il est temps de chiffrer chaque nombre qui compose cette matrice. Là, nous avons le choix:

Je vais utiliser un chiffrement par permutation. Pour des raisons de sécurité, il est nécessaire d’ajouter une clé, afin que le déchiffrement ne soit pas possible sans.

from PIL import Image
import numpy as np

# Charger l'image
image_path = 'ruban.jpg'
image = Image.open(image_path)

# Convertir l'image en matrice numpy
image_matrix = np.array(image)

# Fonction pour générer une permutation déterministe à partir d'une clé
def generate_permutation(size, key):
    np.random.seed(key)
    return np.random.permutation(size)

# Appliquer la permutation
def apply_permutation(image_matrix, permutation):
    flat_matrix = image_matrix.flatten()
    permuted_matrix = flat_matrix[permutation]
    return permuted_matrix.reshape(image_matrix.shape)

# Inverser la permutation
def inverse_permutation(permutation):
    inverse = np.zeros_like(permutation)
    inverse[permutation] = np.arange(len(permutation))
    return inverse

# Clé de chiffrement
key = 12345  # Vous pouvez utiliser n'importe quelle valeur comme clé

# Générer une permutation pour l'image à partir de la clé
permutation = generate_permutation(image_matrix.size, key)

# Appliquer la permutation pour chiffrer l'image
encrypted_matrix = apply_permutation(image_matrix, permutation)

# Convertir la matrice chiffrée en image
encrypted_image = Image.fromarray(encrypted_matrix.astype('uint8'), 'RGB')

# Sauvegarder l'image chiffrée
encrypted_image.save('ruban_chiffre_permutation.jpg')

# Inverser la permutation pour déchiffrer l'image
inverse_permutation = inverse_permutation(permutation)
decrypted_matrix = apply_permutation(encrypted_matrix, inverse_permutation)

# Convertir la matrice déchiffrée en image
decrypted_image = Image.fromarray(decrypted_matrix.astype('uint8'), 'RGB')

# Sauvegarder l'image déchiffrée
decrypted_image.save('ruban_dechiffre_permutation.jpg')

L’image ainsi chiffrée est:

On peut maintenant se servir de ce code pour créer une interface graphique qui demande à l’utilisateur une image, puis une clé, puis un répertoire de sauvegarde.

Là, il a fallu adapter le code précédent car la méthode de chiffrement n’était pas compatible. Je change aussi quelques petits trucs concernant la clé de chiffrement qui, sur les codes précédents, ne peuvent être que des chaînes numériques. J’aimerais que la clé puisse être alphanumérique.

import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import numpy as np
import hashlib

# Convertir une chaine de caractères en entier
def key_from_string(key_string):
    # Convertir la chaîne en une valeur de hachage (MD5)
    hashed_key = hashlib.md5(key_string.encode()).hexdigest()
    # Convertir la valeur hexadécimale en entier
    key_int = int(hashed_key, 16)
    # Réduire la valeur pour qu'elle soit compatible avec np.random.seed
    return key_int % (2**32)  # Limiter à 32 bits


# Fonction pour générer une permutation déterministe à partir d'une clé
def generate_permutation(size, key):
    np.random.seed(key)
    return np.random.permutation(size)

# Fonction pour appliquer la permutation
def apply_permutation(image_matrix, permutation):
    # Si l'image est en 3D (RGB), appliquer la permutation sur chaque canal
    if len(image_matrix.shape) == 3:
        permuted_matrix = np.zeros_like(image_matrix)
        for channel in range(image_matrix.shape[2]):  # Parcourir R, G, B
            flat_channel = image_matrix[:, :, channel].flatten()
            permuted_channel = flat_channel[permutation]
            permuted_matrix[:, :, channel] = permuted_channel.reshape(image_matrix.shape[:2])
        return permuted_matrix
    else:  # Si l'image est en niveaux de gris (2D)
        flat_matrix = image_matrix.flatten()
        permuted_matrix = flat_matrix[permutation]
        return permuted_matrix.reshape(image_matrix.shape)


# Fonction pour inverser la permutation
def inverse_permutation(permutation):
    inverse = np.zeros_like(permutation)
    inverse[permutation] = np.arange(len(permutation))
    return inverse

# Fonction pour chiffrer l'image
def encrypt_image(image_path, key, save_path):
    image = Image.open(image_path)
    image_matrix = np.array(image)

    # Si la clé est une chaîne, la convertir en entier
    if isinstance(key, str):
        key = key_from_string(key)

    # Générer une permutation
    permutation = generate_permutation(image_matrix.shape[0] * image_matrix.shape[1], key)

    # Appliquer la permutation
    encrypted_matrix = apply_permutation(image_matrix, permutation)

    # Sauvegarder l'image chiffrée
    encrypted_image = Image.fromarray(encrypted_matrix.astype('uint8'))
    encrypted_image.save(save_path)
    messagebox.showinfo("Succès", "L'image a été chiffrée et sauvegardée avec succès.")

# Fonction pour déchiffrer l'image
def decrypt_image(image_path, key, save_path):
    image = Image.open(image_path)
    image_matrix = np.array(image)

    # Si la clé est une chaîne, la convertir en entier
    if isinstance(key, str):
        key = key_from_string(key)

    # Générer la permutation et son inverse
    permutation = generate_permutation(image_matrix.shape[0] * image_matrix.shape[1], key)
    inverse_perm = inverse_permutation(permutation)

    # Appliquer l'inverse de la permutation
    decrypted_matrix = apply_permutation(image_matrix, inverse_perm)

    # Sauvegarder l'image déchiffrée
    decrypted_image = Image.fromarray(decrypted_matrix.astype('uint8'))
    decrypted_image.save(save_path)
    messagebox.showinfo("Succès", "L'image a été déchiffrée et sauvegardée avec succès.")


# Fonction pour sélectionner une image
def select_image():
    file_path = filedialog.askopenfilename(title="Sélectionner une image", filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.gif")])
    if file_path:
        image_path_entry.delete(0, tk.END)
        image_path_entry.insert(0, file_path)

# Fonction pour sélectionner un répertoire de sauvegarde
def select_save_directory():
    dir_path = filedialog.askdirectory(title="Sélectionner un répertoire de sauvegarde")
    if dir_path:
        save_dir_entry.delete(0, tk.END)
        save_dir_entry.insert(0, dir_path)

# Fonction pour chiffrer l'image
def encrypt():
    image_path = image_path_entry.get()
    key = key_entry.get() 
    save_dir = save_dir_entry.get()
    save_path = f"{save_dir}/encrypted_image.jpg"
    encrypt_image(image_path, key, save_path)

def decrypt():
    image_path = image_path_entry.get()
    key = key_entry.get() 
    save_dir = save_dir_entry.get()
    save_path = f"{save_dir}/decrypted_image.jpg"
    decrypt_image(image_path, key, save_path)


# Créer la fenêtre principale
root = tk.Tk()
root.title("Chiffrement et Déchiffrement d'Image")

# Créer les widgets
image_path_label = tk.Label(root, text="Chemin de l'image:")
image_path_label.grid(row=0, column=0, padx=10, pady=10)

image_path_entry = tk.Entry(root, width=50)
image_path_entry.grid(row=0, column=1, padx=10, pady=10)

image_path_button = tk.Button(root, text="Sélectionner une image", command=select_image)
image_path_button.grid(row=0, column=2, padx=10, pady=10)

key_label = tk.Label(root, text="Clé de chiffrement:")
key_label.grid(row=1, column=0, padx=10, pady=10)

key_entry = tk.Entry(root, width=50)
key_entry.grid(row=1, column=1, padx=10, pady=10)

save_dir_label = tk.Label(root, text="Répertoire de sauvegarde:")
save_dir_label.grid(row=2, column=0, padx=10, pady=10)

save_dir_entry = tk.Entry(root, width=50)
save_dir_entry.grid(row=2, column=1, padx=10, pady=10)

save_dir_button = tk.Button(root, text="Sélectionner un répertoire", command=select_save_directory)
save_dir_button.grid(row=2, column=2, padx=10, pady=10)

encrypt_button = tk.Button(root, text="Chiffrer l'image", command=encrypt)
encrypt_button.grid(row=3, column=1, padx=10, pady=10)

decrypt_button = tk.Button(root, text="Déchiffrer l'image", command=decrypt)
decrypt_button.grid(row=3, column=2, padx=10, pady=10)

# Lancer la boucle principale
root.mainloop()

Et voilà! ça fonctionne nickel!

Catégories : InformatiquePython

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
2 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Rackette

Très intéressant. Il est à noter que les fichiers originaux ‘ruban.jpg’ et ‘ruban_dechiffre_permutation.jpg’ diffèrent. Ce dernier n’a plus de métadonnées, et surtout, la compression JPEG modifie la matrice de l’image. Ci-joint une image où les points rouges montrent les pixels différents et les points noirs les pixels identiques. Ce problème n’apparaît pas lorsqu’on utilise un format PNG.

# chiffrement_image.py


from PIL import Image
import numpy as np


# Charger l'image originale
image_path = 'ruban.jpg'
image = Image.open(image_path)


# Convertir l'image en matrice numpy
image_matrix = np.array(image)


# Fonction pour générer une permutation déterministe à partir d'une clé
def generate_permutation(size, key):
    np.random.seed(key)
    return np.random.permutation(size)


# Appliquer la permutation
def apply_permutation(image_matrix, permutation):
    flat_matrix = image_matrix.flatten()
    permuted_matrix = flat_matrix[permutation]
    return permuted_matrix.reshape(image_matrix.shape)


# Inverser la permutation
def inverse_permutation(permutation):
    inverse = np.zeros_like(permutation)
    inverse[permutation] = np.arange(len(permutation))
    return inverse


# Clé de chiffrement
key = 12345


# Générer une permutation pour l'image à partir de la clé
permutation = generate_permutation(image_matrix.size, key)


# Appliquer la permutation pour chiffrer l'image
encrypted_matrix = apply_permutation(image_matrix, permutation)


# Convertir la matrice chiffrée en image
encrypted_image = Image.fromarray(encrypted_matrix.astype('uint8'), 'RGB')


# Sauvegarder l'image chiffrée
encrypted_image.save('ruban_chiffre_permutation.jpg')


# Inverser la permutation pour déchiffrer l'image
inverse_perm = inverse_permutation(permutation)
decrypted_matrix = apply_permutation(encrypted_matrix, inverse_perm)


# Convertir la matrice déchiffrée en image
decrypted_image = Image.fromarray(decrypted_matrix.astype('uint8'), 'RGB')


# Sauvegarder l'image déchiffrée
decrypted_image.save('ruban_dechiffre_permutation.jpg')


# --- Comparaison et détection des différences ---


# Recharger l'image déchiffrée depuis le fichier JPEG
reloaded_image = Image.open('ruban_dechiffre_permutation.jpg')
reloaded_matrix = np.array(reloaded_image)


# Comparer la matrice rechargée avec la matrice originale
if np.array_equal(image_matrix, reloaded_matrix):
    print("La matrice rechargée est identique à la matrice originale.")
else:
    print("La matrice rechargée diffère de la matrice originale.")


    # Calculer la différence absolue entre les matrices
    difference = np.abs(reloaded_matrix.astype(int) - image_matrix.astype(int))


    # Compter le nombre de pixels où il y a une différence
    diff_pixels = np.count_nonzero(difference)
    print(f"Nombre de pixels différents : {diff_pixels}")
    print(f"Différence minimale : {difference.min()}, Différence maximale : {difference.max()}")


    # --- Création d'une image PNG marquant les différences en rouge ---
    height, width, channels = image_matrix.shape
    # Créer une image noire de la même taille
    overlay = np.zeros((height, width, 3), dtype=np.uint8)
    # Créer un masque pour les pixels où il y a au moins une différence
    diff_mask = np.any(difference != 0, axis=2)
    # Marquer en rouge les pixels différents
    overlay[diff_mask] = [255, 0, 0]
    # Sauvegarder l'image des différences
    diff_image = Image.fromarray(overlay)
    diff_image.save('differences.png')
    print("Image des différences sauvegardée sous 'differences.png'.")
differences
2
0
Nous aimerions avoir votre avis, veuillez laisser un commentaire.x
0
    0
    Votre panier
    Votre panier est vide