Skip to content
Extraits de code Groupes Projets
Valider 1635ac56 rédigé par Yannick Chistel's avatar Yannick Chistel
Parcourir les fichiers

mise à jour de cryptographie

parent 8b559f5b
Branches main
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Pipeline #91725 réussi
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyhpPUvYfLLTXRae61KyrtxGeJQKzkeN333xPWbN0lz/hFgQ6
63CJI2jW2YdcMYS75whPcabPqEUwI56a1Pc/5H/5+qfxXwoP3BYo9NBiKfcevZW2
yCvdyx/QyNd7VEPs+tQfXtH79fyvQ88Q9V+q3Z0TCBWS5bz1E3YgGDapoa4vzKqo
BTR3WZ0FGXj2nJzNuzc8sQfa9X6LWm5WJ44MRO2UMuFTGYfa6+aUExQ+eeFlEFh9
7XeBXpPKTiVzKH5SMG/xU78+8gW/q1NZ5C2sD7NTBO45dPwz+AAUlpOVNYdSgBoS
VDhm+fnEci/VsWx1LRo30DIrYdLEADENHlxvtwIDAQABAoIBADwShfGK5slLF5HE
wWvlx0SrH+6wVt/OVRtAv/VRuh4bBrScnUbONHUp/HK8IVM2uQN7HOITSzYhGqX7
xtn2hC9POuaedMhjHUO18oaSShtfMOv5TFNDdrGhy1Vnd2kcp5wG4Sw2DkaXzSDC
s6+7t/YXcki84OUYvWADhJat6M39iTsE6ebl+S2QCivrO7W0ZyGi2XOwMb/blqM5
CuBPIUw+M34GXwJZiJamqqWnKOZkqHb6Fmg8AWdy1lvmpwQ1J/nSu8hJ3VsV1xxE
XjQtdyxiJowSsRZcpPZGEkAsfJ7w+rnYA3pInzHIrn6dFWWTI1NzllVkGJQ8evh2
d8qw6cECgYEA29pe1Wl6ka9js345RNVYrMl18whbfTcZ1F7kyCETn+bPrwJ5l6uV
l8TqWP6MjfGm6/zXh314jVtc0ClzQ9hMUrMx5XVTXRNE5Gn91X8h6T4d5kW/kxK+
j3+C4VU3b1ynj0gds9UKjACQKXTqZSo/hj5vmBh/W5EN3t9lewP8d+UCgYEA61TU
pEyq3K6fnfyIB/m6jPE0DYqwSjAuzRODD74Dz8eSfeR5bvzrtJbAf3cfGc2LIBXj
ZuZYMKERyedWXW3kq4BBcS2DQL2YJBXDWWNQyida7pwoEFgtg2ufd4KPLgClZD7+
ZuCVf18UBetZ/jaH95Jfo+j5Yg1Cb1BL73JB12sCgYEAifWlDtxquqLJuKfbfhM2
2u5son47Ev8RqU+G1wLSksO+zX6LGJ7md19tAz1wq93ZNjrqcK5OiL2tJz7rgsZn
Vnn2NJwEHOLrlz3fuCpX+EovbwGTrtHTXK7STV4xNCN7ThEd+mwUezgbPriMIcF6
LV5enp24xZfnkVS0FJayxfUCgYEAmJWnTmR7gJ0k124O0YUFhS87vfAHwAKfxc55
8zIUDJvtCv2iEumg9rWsWLlnC/bu1z359RUzZ0x4WT5LDEcdtmlxhS2qZcbIp9UI
laPElV6RIhdUDsztrcGRYw7fQUef9XC2yQOjSzPdqrzf2+mFnWtl4cRENmQ8iCo7
IiUmNcMCgYBud0xkrCmaFNNUlsA4acYQfzuZWD+AMIpbJlxdlU1b9Nua9PRH7Pd8
G0us6ktHZROcUZ4OUYky5ezpOBN63rrkiX/gSaO6qSs1Hp9oJwzO2aU33rE5sioq
Jj7T7AL/iN68kmfMn9rIECECqR+7abrZK4PMmlVpvSTKJTohTblfsw==
-----END RSA PRIVATE KEY-----
\ No newline at end of file
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyhpPUvYfLLTXRae61Kyr
txGeJQKzkeN333xPWbN0lz/hFgQ663CJI2jW2YdcMYS75whPcabPqEUwI56a1Pc/
5H/5+qfxXwoP3BYo9NBiKfcevZW2yCvdyx/QyNd7VEPs+tQfXtH79fyvQ88Q9V+q
3Z0TCBWS5bz1E3YgGDapoa4vzKqoBTR3WZ0FGXj2nJzNuzc8sQfa9X6LWm5WJ44M
RO2UMuFTGYfa6+aUExQ+eeFlEFh97XeBXpPKTiVzKH5SMG/xU78+8gW/q1NZ5C2s
D7NTBO45dPwz+AAUlpOVNYdSgBoSVDhm+fnEci/VsWx1LRo30DIrYdLEADENHlxv
twIDAQAB
-----END PUBLIC KEY-----
\ No newline at end of file
===============================
TP : Chiffrement et Signature
===============================
Objectifs :
-----------
Ce TP a pour but de comprendre et manipuler :
- Le chiffrement symétrique avec **AES**
- Le chiffrement asymétrique avec **RSA**
- La signature numérique avec RSA
- La différence entre **chiffrement et signature**
.. warning::
- Avoir Python installé avec `pycryptodome`
- Comprendre le principe des clés publiques et privées
Ce TP est réalisé sur un notebook de capytale qui comprend la classe ``Crypto`` du fichier annexe ``_cryptographie.py``.
Interface de la classe Crypto
-------------------------------
La classe ``Crypto`` permet de construire un objet avec 2 attributs:
- L'attribut ``mode`` qui définit le type de chiffrement. Un chiffrement symétrique (par défaut) si le mode est défini avec la valeur ``AES`` ou asymétrique si le mode est défini avec la valeur ``RSA``.
- L'attribut ``key`` qui contient la clé de chiffrement.
La classe ``Crypto`` contient différentes méthodes:
- ``chiffrer(message)`` : Chiffre un message.
- ``dechiffrer(message)`` : Déchiffre un message.
- ``signer_message(message)`` : Signe un message (RSA uniquement).
- ``verifier_signature(message, signature)`` : Vérifie une signature (RSA uniquement).
- ``afficher_cle()`` : affiche la clé de chiffrement encodé en base64.
- ``save_key(filename, private=True)`` : Sauvegarde une clé RSA.
- ``load_key(filename, private=True)`` : Charge une clé RSA.
On rappelle que l'instruction Python ``help(Crypto)`` affiche l'aide de la classe ``Crypto`` qui a été ajoutée dans les différentes **docstring** de la classe.
Chiffrement symétrique avec AES
---------------------------------
#. Créez une instance de la classe ``Crypto`` en mode ``AES``.
#. Affichez la clé de chiffrement symétrique.
#. Quelle est la longueur de la clé de chiffrement ?
#. Créez une variable ``msg`` qui contient un message en clair à chiffrer.
#. Créez la variable ``msg_chiffre`` qui contient le message ``msg`` chiffré.
#. Déchiffrer le message et vérifier que celui-ci est correct.
Chiffrement asymétrique avec RSA
---------------------------------
#. Créez une instance de la classe ``Crypto`` en mode ``RSA``.
#. Afficher la clé de chiffrement créée en utilisant l'attribut ``key``.
#. Quels sont les différentes valeurs contenues dans la clé ?
#. La méthode ``get_private_key()`` permet d'obtenir la clé privée ? Quelle est la valeur obtenue ?
#. La méthode ``get_public_key()`` permet d'obtenir la clé publique ? Quelle est la valeur obtenue ?
#. Afficher l'aide sur la méthode ``save_key()`` puis enregistrer vos clés (privé et publique) dans 2 fichiers différents.
#. Afficher dans un éditeur de texte vos clés et comparer les contenus.
Chiffrer et déchiffrer un message
----------------------------------
#. Créez une variable ``msg`` qui contient un message en clair à chiffrer.
#. Créez la variable ``msg_chiffre`` qui contient le message ``msg`` chiffré.
#. Avec quelle clé le message est-il chiffré ?
#. Déchiffrer le message et vérifier que celui-ci est correct.
#. Avec quelle clé le message est-il déchiffré ?
Signature numérique
---------------------
#. Signer le message ``msg`` en l'enregitrant dans la variable ``msg_signe``.
#. La signature et le message chiffré sont-ils les mêmes ? Justifier.
#. Vérifier que la signature est correcte ?
#. Que se passe-t-il si on modifie le message après la signature ?
.. admonition:: En conclusion
- AES est **rapide** mais nécessite le **partage sécurisé** de la clé.
- RSA permet de **chiffrer et signer**, mais est **plus lent**.
- Une signature **prouve l'authenticité** d'un message sans le masquer.
TP : Cryptographie RSA
======================
TP LINUX : Cryptographie RSA
=============================
**OpenSSL** est un logiciel de cryptographie qui possède de nombreux algorithmes de chiffrement. OpenSSL est disponible sur les systèmes **windows/linux/mac** et s'utilise en ligne de commandes.
......
......@@ -39,5 +39,6 @@ On donne ci-dessous quelques définitions.
content/code_vigenere.rst
content/cryptographie_symetrique.rst
content/cryptographie_asymetrique.rst
content/tp_crypto_aes_rsa.rst
content/tp_rsa.rst
content/tp_diffie_hellman.rst
%% Cell type:markdown id: tags:
# TP : Chiffrement et Signature avec Python
## Objectifs
Dans ce TP, vous allez manipuler la cryptographie avec Python en utilisant la bibliothèque `pycryptodome`.
Vous apprendrez à :
- Chiffrer et déchiffrer un message avec **AES** (chiffrement symétrique)
- Chiffrer et déchiffrer un message avec **RSA** (chiffrement asymétrique)
- Signer un message avec RSA et vérifier la signature
- Comprendre la différence entre **signature et chiffrement**
%% Cell type:code id: tags:
``` python
# Installation de la bibliothèque si nécessaire
!pip install pycryptodome
```
%% Cell type:markdown id: tags:
## Exercice 1 : Génération des clés
Nous allons commencer par créer des clés AES et RSA.
%% Cell type:code id: tags:
``` python
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
import base64
class Crypto:
def __init__(self, mode='AES'):
self.mode = mode
if self.mode == 'AES':
self.cle = AES.get_random_bytes(16)
else:
self.cle = RSA.generate(2048)
def get_public_key(self):
if self.mode == 'RSA':
return self.cle.publickey().export_key()
def get_private_key(self):
if self.mode == 'RSA':
return self.cle.export_key()
# Génération des clés
crypto_aes = Crypto(mode='AES')
print('Clé AES :', base64.b64encode(crypto_aes.cle).decode())
crypto_rsa = Crypto(mode='RSA')
print('Clé publique RSA :', crypto_rsa.get_public_key().decode())
print('Clé privée RSA :', crypto_rsa.get_private_key().decode())
```
%% Cell type:markdown id: tags:
## Exercice 2 : Chiffrement et Déchiffrement avec AES
Nous allons chiffrer et déchiffrer un message avec AES.
%% Cell type:code id: tags:
``` python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
class Crypto:
def __init__(self, mode='AES'):
self.mode = mode
if self.mode == 'AES':
self.cle = AES.get_random_bytes(16)
def chiffrer_aes(self, message):
cipher = AES.new(self.cle, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(pad(message.encode(), 16))).decode()
def dechiffrer_aes(self, message_chiffre):
cipher = AES.new(self.cle, AES.MODE_ECB)
return unpad(cipher.decrypt(base64.b64decode(message_chiffre)), 16).decode()
# Test du chiffrement AES
crypto_aes = Crypto(mode='AES')
message = 'Bonjour NSI'
chiffre = crypto_aes.chiffrer_aes(message)
print('Message chiffré :', chiffre)
clair = crypto_aes.dechiffrer_aes(chiffre)
print('Message déchiffré :', clair)
```
%% Cell type:markdown id: tags:
## Exercice 3 : Signature numérique
Nous allons signer un message et vérifier la signature.
%% Cell type:code id: tags:
``` python
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
class Crypto:
def __init__(self, mode='RSA'):
if mode == 'RSA':
self.cle = RSA.generate(2048)
def signer(self, message):
h = SHA256.new(message.encode())
return base64.b64encode(pkcs1_15.new(self.cle).sign(h)).decode()
def verifier_signature(self, message, signature):
h = SHA256.new(message.encode())
try:
pkcs1_15.new(self.cle.publickey()).verify(h, base64.b64decode(signature))
return 'Signature valide'
except ValueError:
return 'Signature invalide'
# Test de la signature
crypto_rsa = Crypto(mode='RSA')
message = 'Je suis un élève NSI'
signature = crypto_rsa.signer(message)
print('Signature :', signature)
verification = crypto_rsa.verifier_signature(message, signature)
print('Vérification :', verification)
```
%% Cell type:markdown id: tags:
## Conclusion
- AES est rapide mais nécessite le partage sécurisé de la clé.
- RSA permet de chiffrer et signer mais est plus lent.
- Une signature numérique permet de garantir l'authenticité d'un message.
%% Cell type:code id: tags:
``` python
import json
# Structure du notebook
notebook = {
"cells": [
# Cellule Markdown d'introduction
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TP : Chiffrement et Signature en Terminale NSI\n",
"\n",
"Dans ce TP, nous allons découvrir :\n",
"- Le chiffrement symétrique avec AES\n",
"- Le chiffrement asymétrique avec RSA\n",
"- La signature numérique\n"
]
},
# Cellule de code pour l'importation des bibliothèques
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"from Crypto.PublicKey import RSA\n",
"from Crypto.Cipher import PKCS1_OAEP, AES\n",
"from Crypto.Signature import pkcs1_15\n",
"from Crypto.Hash import SHA256\n",
"import base64\n"
]
},
# Cellule Markdown expliquant la classe Crypto
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Définition de la classe `Crypto`\n",
"Nous allons utiliser une classe `Crypto` pour gérer les clés, le chiffrement et la signature."
]
},
# Cellule de code contenant la classe Crypto
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"class Crypto:\n",
" def __init__(self, mode='AES'):\n",
" self.mode = mode\n",
" if self.mode == 'AES':\n",
" self.cle = AES.get_random_bytes(16)\n",
" else:\n",
" self.cle = RSA.generate(2048)\n",
" \n",
" def get_public_key(self):\n",
" if self.mode == 'RSA':\n",
" return self.cle.publickey().export_key()\n",
" \n",
" def get_private_key(self):\n",
" if self.mode == 'RSA':\n",
" return self.cle.export_key()\n"
]
},
# Cellule Markdown expliquant le chiffrement AES
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Chiffrement symétrique avec AES\n",
"Nous allons maintenant chiffrer un message avec AES."
]
},
# Cellule de code pour tester AES
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"crypto_aes = Crypto(mode='AES')\n",
"print(\"Clé AES générée :\", base64.b64encode(crypto_aes.cle).decode())"
]
},
# Cellule Markdown expliquant la signature numérique
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Signature numérique avec RSA\n",
"Nous allons signer un message avec une clé privée RSA et vérifier la signature avec la clé publique."
]
},
# Cellule de code pour tester la signature
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"crypto_rsa = Crypto(mode='RSA')\n",
"message = \"La cryptographie est importante !\"\n",
"h = SHA256.new(message.encode())\n",
"signature = pkcs1_15.new(crypto_rsa.cle).sign(h)\n",
"print(\"Signature générée :\", base64.b64encode(signature).decode())"
]
}
],
"metadata": {
"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.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
# Sauvegarde du notebook
with open("tp_cryptographie.ipynb", "w", encoding="utf-8") as f:
json.dump(notebook, f, indent=4)
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:markdown id: tags:
# TP : Chiffrement et Signature en Terminale NSI
Dans ce TP, nous allons découvrir :
- Le chiffrement symétrique avec AES
- Le chiffrement asymétrique avec RSA
- La signature numérique
%% Cell type:code id: tags:
``` python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import base64
```
%% Cell type:markdown id: tags:
## Définition de la classe `Crypto`
Nous allons utiliser une classe `Crypto` pour gérer les clés, le chiffrement et la signature.
%% Cell type:code id: tags:
``` python
class Crypto:
def __init__(self, mode='AES'):
self.mode = mode
if self.mode == 'AES':
self.cle = AES.get_random_bytes(16)
else:
self.cle = RSA.generate(2048)
def get_public_key(self):
if self.mode == 'RSA':
return self.cle.publickey().export_key()
def get_private_key(self):
if self.mode == 'RSA':
return self.cle.export_key()
```
%% Cell type:markdown id: tags:
## Chiffrement symétrique avec AES
Nous allons maintenant chiffrer un message avec AES.
%% Cell type:code id: tags:
``` python
crypto_aes = Crypto(mode='AES')
print("Clé AES générée :", base64.b64encode(crypto_aes.cle).decode())
```
%% Cell type:markdown id: tags:
## Signature numérique avec RSA
Nous allons signer un message avec une clé privée RSA et vérifier la signature avec la clé publique.
%% Cell type:code id: tags:
``` python
crypto_rsa = Crypto(mode='RSA')
message = "La cryptographie est importante !"
h = SHA256.new(message.encode())
signature = pkcs1_15.new(crypto_rsa.cle).sign(h)
print("Signature générée :", base64.b64encode(signature).decode())
```
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import base64
import os
class Crypto:
"""
Classe permettant le chiffrement, déchiffrement et signature des messages en utilisant AES ou RSA.
- Mode `AES` : Chiffrement symétrique avec clé aléatoire (16 octets).
- Mode `RSA` : Chiffrement asymétrique avec clé privée/publique (2048 bits par défaut).
Méthodes principales :
- chiffrer(message) : Chiffre un message.
- dechiffrer(message) : Déchiffre un message.
- signer_message(message) : Signe un message (RSA uniquement).
- verifier_signature(message, signature) : Vérifie une signature (RSA uniquement).
- save_key(filename, private=True) : Sauvegarde une clé RSA.
- load_key(filename, private=True) : Charge une clé RSA.
"""
def __init__(self, mode='AES', key_size=2048):
"""
Initialise un objet de chiffrement en mode AES ou RSA.
:param mode: 'AES' pour le chiffrement symétrique, 'RSA' pour l'asymétrique.
:param key_size: Taille de la clé RSA en bits (2048 par défaut).
:raises ValueError: Si un mode invalide est fourni.
"""
self.mode = mode
if self.mode == 'AES':
self.key = get_random_bytes(16)
elif self.mode == 'RSA':
self.key = RSA.generate(key_size)
else:
raise ValueError("Mode invalide ! Choisissez 'AES' ou 'RSA'.")
print(f"Une clé de chiffrement {self.mode} créée !")
def get_private_key(self):
"""Retourne la clé privée RSA."""
if self.mode == 'RSA':
return self.key
raise ValueError("La clé privée n'est disponible qu'en mode RSA.")
def get_public_key(self):
"""Retourne la clé publique RSA."""
if self.mode == 'RSA':
return self.key.publickey()
raise ValueError("La clé publique n'est disponible qu'en mode RSA.")
def save_key(self, filename, private=True):
"""
Sauvegarde une clé RSA dans un fichier.
:param filename: Nom du fichier où enregistrer la clé.
:param private: True pour la clé privée, False pour la clé publique.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La sauvegarde des clés est uniquement disponible pour RSA.")
key_data = self.get_private_key().export_key() if private else self.get_public_key().export_key()
with open(filename, "wb") as key_file:
key_file.write(key_data)
def load_key(self, filename, private=True):
"""
Charge une clé RSA depuis un fichier.
:param filename: Nom du fichier contenant la clé.
:param private: True pour charger une clé privée, False pour une clé publique.
:raises FileNotFoundError: Si le fichier n'existe pas.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("Le chargement des clés est uniquement disponible pour RSA.")
if not os.path.exists(filename):
raise FileNotFoundError(f"Le fichier {filename} n'existe pas.")
with open(filename, "rb") as key_file:
key = RSA.import_key(key_file.read())
if private:
self.key = key
else:
return key
def chiffrer(self, message):
"""
Chiffre un message avec AES ou RSA.
:param message: Chaîne de caractères à chiffrer.
:return: Message chiffré en base64.
"""
if self.mode == 'AES':
cipher = AES.new(self.key, AES.MODE_ECB)
ciphertext = cipher.encrypt(self._pad(message.encode()))
return base64.b64encode(ciphertext).decode()
elif self.mode == 'RSA':
public_key = self.get_public_key()
cipher_rsa = PKCS1_OAEP.new(public_key)
encrypted_bytes = cipher_rsa.encrypt(message.encode())
return base64.b64encode(encrypted_bytes).decode()
def dechiffrer(self, message):
"""
Déchiffre un message avec AES ou RSA.
:param message: Chaîne de caractères chiffrée en base64.
:return: Message déchiffré en clair.
"""
if self.mode == 'AES':
decoded_ciphertext = base64.b64decode(message)
cipher_dec = AES.new(self.key, AES.MODE_ECB)
decrypted_message = self._unpad(cipher_dec.decrypt(decoded_ciphertext))
return decrypted_message.decode()
elif self.mode == 'RSA':
private_key = self.get_private_key()
cipher_rsa = PKCS1_OAEP.new(private_key)
decrypted_bytes = cipher_rsa.decrypt(base64.b64decode(message))
return decrypted_bytes.decode()
def signer_message(self, message):
"""
Signe un message avec RSA.
:param message: Chaîne de caractères à signer.
:return: Signature en base64.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La signature est uniquement disponible pour RSA.")
private_key = self.get_private_key()
hash_message = SHA256.new(message.encode())
signature = pkcs1_15.new(private_key).sign(hash_message)
return base64.b64encode(signature).decode()
def verifier_signature(self, message, signature):
"""
Vérifie la signature d'un message RSA.
:param message: Chaîne de caractères originale.
:param signature: Signature en base64.
:return: True si la signature est valide, False sinon.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La vérification de signature est uniquement disponible pour RSA.")
public_key = self.get_public_key()
hash_message = SHA256.new(message.encode())
signature_bytes = base64.b64decode(signature)
try:
pkcs1_15.new(public_key).verify(hash_message, signature_bytes)
return True
except (ValueError, TypeError):
return False
def afficher_cle(self):
"""
Affiche la clé AES en base64.
:return: Clé AES encodée en base64.
:raises ValueError: Si la méthode est appelée en mode RSA.
"""
if self.mode == 'AES':
return base64.b64encode(self.key).decode()
raise ValueError("L'affichage de la clé n'est disponible qu'en mode AES.")
def _pad(self, data):
"""Ajoute du padding pour AES (bloc de 16 octets)."""
padding_length = 16 - (len(data) % 16)
return data + bytes([padding_length] * padding_length)
def _unpad(self, data):
"""Supprime le padding après déchiffrement AES."""
return data[:-data[-1]]
if __name__ == '__main__':
# 🔹 Test avec AES
crypto_aes = Crypto(mode='AES')
message = "Bonjour NSI !"
print("Clé AES :", crypto_aes.afficher_cle())
message_chiffre = crypto_aes.chiffrer(message)
print("Message chiffré (AES) :", message_chiffre)
message_dechiffre = crypto_aes.dechiffrer(message_chiffre)
print("Message déchiffré (AES) :", message_dechiffre)
# 🔹 Test avec RSA
crypto_rsa = Crypto(mode='RSA')
message = "Sécurisation des données avec RSA"
crypto_rsa.save_key("private.pem", private=True)
crypto_rsa.save_key("public.pem", private=False)
message_chiffre = crypto_rsa.chiffrer(message)
print("Message chiffré (RSA) :", message_chiffre)
message_dechiffre = crypto_rsa.dechiffrer(message_chiffre)
print("Message déchiffré (RSA) :", message_dechiffre)
# 🔹 Signature et vérification
signature = crypto_rsa.signer_message(message)
print("Signature :", signature)
verification = crypto_rsa.verifier_signature(message, signature)
print("Signature valide ?", verification)
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import base64
import os
class Crypto:
"""
Classe permettant le chiffrement, déchiffrement et signature des messages en utilisant AES ou RSA.
- Mode `AES` : Chiffrement symétrique avec clé aléatoire (16 octets).
- Mode `RSA` : Chiffrement asymétrique avec clé privée/publique (2048 bits par défaut).
Méthodes principales :
- chiffrer(message) : Chiffre un message.
- dechiffrer(message) : Déchiffre un message.
- signer_message(message) : Signe un message (RSA uniquement).
- verifier_signature(message, signature) : Vérifie une signature (RSA uniquement).
- save_key(filename, private=True) : Sauvegarde une clé RSA.
- load_key(filename, private=True) : Charge une clé RSA.
"""
def __init__(self, mode='AES', key_size=2048):
"""
Initialise un objet de chiffrement en mode AES ou RSA.
:param mode: 'AES' pour le chiffrement symétrique, 'RSA' pour l'asymétrique.
:param key_size: Taille de la clé RSA en bits (2048 par défaut).
:raises ValueError: Si un mode invalide est fourni.
"""
self.mode = mode
if self.mode == 'AES':
self.key = get_random_bytes(16)
elif self.mode == 'RSA':
self.key = RSA.generate(key_size)
else:
raise ValueError("Mode invalide ! Choisissez 'AES' ou 'RSA'.")
print(f"Une clé de chiffrement {self.mode} créée !")
def get_private_key(self):
"""Retourne la clé privée RSA."""
if self.mode == 'RSA':
return self.key
raise ValueError("La clé privée n'est disponible qu'en mode RSA.")
def get_public_key(self):
"""Retourne la clé publique RSA."""
if self.mode == 'RSA':
return self.key.publickey()
raise ValueError("La clé publique n'est disponible qu'en mode RSA.")
def save_key(self, filename, private=True):
"""
Sauvegarde une clé RSA dans un fichier.
:param filename: Nom du fichier où enregistrer la clé.
:param private: True pour la clé privée, False pour la clé publique.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La sauvegarde des clés est uniquement disponible pour RSA.")
key_data = self.get_private_key().export_key() if private else self.get_public_key().export_key()
with open(filename, "wb") as key_file:
key_file.write(key_data)
def load_key(self, filename, private=True):
"""
Charge une clé RSA depuis un fichier.
:param filename: Nom du fichier contenant la clé.
:param private: True pour charger une clé privée, False pour une clé publique.
:raises FileNotFoundError: Si le fichier n'existe pas.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("Le chargement des clés est uniquement disponible pour RSA.")
if not os.path.exists(filename):
raise FileNotFoundError(f"Le fichier {filename} n'existe pas.")
with open(filename, "rb") as key_file:
key = RSA.import_key(key_file.read())
if private:
self.key = key
else:
return key
def chiffrer(self, message):
"""
Chiffre un message avec AES ou RSA.
:param message: Chaîne de caractères à chiffrer.
:return: Message chiffré en base64.
"""
if self.mode == 'AES':
cipher = AES.new(self.key, AES.MODE_ECB)
ciphertext = cipher.encrypt(self._pad(message.encode()))
return base64.b64encode(ciphertext).decode()
elif self.mode == 'RSA':
public_key = self.get_public_key()
cipher_rsa = PKCS1_OAEP.new(public_key)
encrypted_bytes = cipher_rsa.encrypt(message.encode())
return base64.b64encode(encrypted_bytes).decode()
def dechiffrer(self, message):
"""
Déchiffre un message avec AES ou RSA.
:param message: Chaîne de caractères chiffrée en base64.
:return: Message déchiffré en clair.
"""
if self.mode == 'AES':
decoded_ciphertext = base64.b64decode(message)
cipher_dec = AES.new(self.key, AES.MODE_ECB)
decrypted_message = self._unpad(cipher_dec.decrypt(decoded_ciphertext))
return decrypted_message.decode()
elif self.mode == 'RSA':
private_key = self.get_private_key()
cipher_rsa = PKCS1_OAEP.new(private_key)
decrypted_bytes = cipher_rsa.decrypt(base64.b64decode(message))
return decrypted_bytes.decode()
def signer_message(self, message):
"""
Signe un message avec RSA.
:param message: Chaîne de caractères à signer.
:return: Signature en base64.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La signature est uniquement disponible pour RSA.")
private_key = self.get_private_key()
hash_message = SHA256.new(message.encode())
signature = pkcs1_15.new(private_key).sign(hash_message)
return base64.b64encode(signature).decode()
def verifier_signature(self, message, signature):
"""
Vérifie la signature d'un message RSA.
:param message: Chaîne de caractères originale.
:param signature: Signature en base64.
:return: True si la signature est valide, False sinon.
:raises ValueError: Si la méthode est appelée en mode AES.
"""
if self.mode != 'RSA':
raise ValueError("La vérification de signature est uniquement disponible pour RSA.")
public_key = self.get_public_key()
hash_message = SHA256.new(message.encode())
signature_bytes = base64.b64decode(signature)
try:
pkcs1_15.new(public_key).verify(hash_message, signature_bytes)
return True
except (ValueError, TypeError):
return False
def affiche_cle(self):
"""
Affiche la clé AES en base64.
:return: Clé AES encodée en base64.
:raises ValueError: Si la méthode est appelée en mode RSA.
"""
if self.mode == 'AES':
return base64.b64encode(self.key).decode()
raise ValueError("L'affichage de la clé n'est disponible qu'en mode AES.")
def _pad(self, data):
"""Ajoute du padding pour AES (bloc de 16 octets)."""
padding_length = 16 - (len(data) % 16)
return data + bytes([padding_length] * padding_length)
def _unpad(self, data):
"""Supprime le padding après déchiffrement AES."""
return data[:-data[-1]]
if __name__ == '__main__':
# Génération d'une clé secrète AES-128 (16 octets)
codeAES = Crypto()
# on affiche la clé !
print(codeAES.affiche_cle())
# Message à chiffrer
message = "Cryptographie en NSI est passionnante et les élèves aiment ça !"
print("Message original :", message)
message_chiffre = codeAES.chiffrer(message)
print(f"Message chiffré : {message_chiffre}")
message_dechiffre = codeAES.dechiffrer(message_chiffre)
print(f"Message déchiffré : {message_dechiffre}")
codeRSA = Crypto(mode='RSA')
private_key = codeRSA.get_private_key()
#print(private_key)
public_key = codeRSA.get_public_key()
#print(public_key)
# Message à chiffrer
message = "La cryptographie en NSI est passionnante ça c'est évident!"
print("Message original :", message)
# Chiffrement
encrypted_message = codeRSA.chiffrer(message)
print("🔹 Message chiffré :", encrypted_message)
# Déchiffrement
decrypted_message = codeRSA.dechiffrer(encrypted_message)
print("🔹 Message déchiffré :", decrypted_message)
# Message à signer
message = "La cryptographie en NSI est passionnante !"
print("Message original :", message)
# Signature du message
signature = codeRSA.signer_message(message)
print("🔹 Signature générée :", signature)
# Vérification de la signature
is_valid = codeRSA.verifier_signature(message, signature)
print("🔹 Signature valide ?", is_valid)
\ No newline at end of file
import json
# Structure du notebook
notebook = {
"cells": [
# Cellule Markdown d'introduction
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TP : Chiffrement et Signature en Terminale NSI\n",
"\n",
"Dans ce TP, nous allons découvrir :\n",
"- Le chiffrement symétrique avec AES\n",
"- Le chiffrement asymétrique avec RSA\n",
"- La signature numérique\n"
]
},
# Cellule de code pour l'importation des bibliothèques
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"from Crypto.PublicKey import RSA\n",
"from Crypto.Cipher import PKCS1_OAEP, AES\n",
"from Crypto.Signature import pkcs1_15\n",
"from Crypto.Hash import SHA256\n",
"import base64\n"
]
},
# Cellule Markdown expliquant la classe Crypto
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Définition de la classe `Crypto`\n",
"Nous allons utiliser une classe `Crypto` pour gérer les clés, le chiffrement et la signature."
]
},
# Cellule de code contenant la classe Crypto
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"class Crypto:\n",
" def __init__(self, mode='AES'):\n",
" self.mode = mode\n",
" if self.mode == 'AES':\n",
" self.cle = AES.get_random_bytes(16)\n",
" else:\n",
" self.cle = RSA.generate(2048)\n",
" \n",
" def get_public_key(self):\n",
" if self.mode == 'RSA':\n",
" return self.cle.publickey().export_key()\n",
" \n",
" def get_private_key(self):\n",
" if self.mode == 'RSA':\n",
" return self.cle.export_key()\n"
]
},
# Cellule Markdown expliquant le chiffrement AES
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Chiffrement symétrique avec AES\n",
"Nous allons maintenant chiffrer un message avec AES."
]
},
# Cellule de code pour tester AES
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"crypto_aes = Crypto(mode='AES')\n",
"print(\"Clé AES générée :\", base64.b64encode(crypto_aes.cle).decode())"
]
},
# Cellule Markdown expliquant la signature numérique
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Signature numérique avec RSA\n",
"Nous allons signer un message avec une clé privée RSA et vérifier la signature avec la clé publique."
]
},
# Cellule de code pour tester la signature
{
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": [
"crypto_rsa = Crypto(mode='RSA')\n",
"message = \"La cryptographie est importante !\"\n",
"h = SHA256.new(message.encode())\n",
"signature = pkcs1_15.new(crypto_rsa.cle).sign(h)\n",
"print(\"Signature générée :\", base64.b64encode(signature).decode())"
]
}
],
"metadata": {
"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.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
# Sauvegarde du notebook
with open("tp_cryptographie.ipynb", "w", encoding="utf-8") as f:
json.dump(notebook, f, indent=4)
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter