ajout de tous les cours et TP préparés cet été
This commit is contained in:
138
Sécurité/CORRIGE_EXERCICES.md
Normal file
138
Sécurité/CORRIGE_EXERCICES.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Corrigé des exercices — Sécurité
|
||||
|
||||
---
|
||||
|
||||
## Exercice : Algorithme ROT13
|
||||
|
||||
### Rappel
|
||||
|
||||
L'algorithme ROT13 décale chaque lettre de 13 positions dans l'alphabet. Comme l'alphabet a 26 lettres, appliquer ROT13 deux fois revient au message original.
|
||||
|
||||
### Solution
|
||||
|
||||
```python
|
||||
def chiffrement_rot13_mot(mot):
|
||||
"""
|
||||
Chiffre un mot avec l'algorithme ROT13.
|
||||
|
||||
:param mot: (str) Le mot à chiffrer (en minuscules)
|
||||
:return: (str) Le mot chiffré
|
||||
"""
|
||||
resultat = ""
|
||||
for lettre in mot.lower():
|
||||
if 'a' <= lettre <= 'z':
|
||||
# Calculer la nouvelle position
|
||||
code = ord(lettre) - ord('a') # Position 0-25
|
||||
nouveau_code = (code + 13) % 26 # Décalage de 13
|
||||
nouvelle_lettre = chr(nouveau_code + ord('a'))
|
||||
resultat += nouvelle_lettre
|
||||
else:
|
||||
# Garder les caractères non alphabétiques
|
||||
resultat += lettre
|
||||
return resultat
|
||||
|
||||
|
||||
def chiffrement_rot13(message):
|
||||
"""
|
||||
Chiffre un message complet avec l'algorithme ROT13.
|
||||
|
||||
:param message: (str) Le message à chiffrer
|
||||
:return: (str) Le message chiffré
|
||||
"""
|
||||
mots = message.split()
|
||||
mots_chiffres = [chiffrement_rot13_mot(mot) for mot in mots]
|
||||
return " ".join(mots_chiffres)
|
||||
```
|
||||
|
||||
### Version alternative (plus concise)
|
||||
|
||||
```python
|
||||
def rot13(message):
|
||||
"""Version concise du chiffrement ROT13."""
|
||||
resultat = ""
|
||||
for car in message.lower():
|
||||
if 'a' <= car <= 'z':
|
||||
resultat += chr((ord(car) - ord('a') + 13) % 26 + ord('a'))
|
||||
else:
|
||||
resultat += car
|
||||
return resultat
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```python
|
||||
>>> chiffrement_rot13("bonjour")
|
||||
'obawbhe'
|
||||
|
||||
>>> chiffrement_rot13("python")
|
||||
'clguba'
|
||||
|
||||
>>> chiffrement_rot13("Vive les numériques et sciences informatiques")
|
||||
'ivir yrf ahzrevdhrf rg fpvraprf vasbezngvdhrf'
|
||||
```
|
||||
|
||||
### Exemples de chiffrement de noms
|
||||
|
||||
| Prénom/Nom | ROT13 |
|
||||
|------------|-------|
|
||||
| Alice | nyvpr |
|
||||
| Bob | obo |
|
||||
| Florian | sybevna |
|
||||
| Mathieu | znguvrh |
|
||||
|
||||
### Propriété remarquable
|
||||
|
||||
ROT13 est son propre inverse : appliquer ROT13 deux fois redonne le message original.
|
||||
|
||||
```python
|
||||
>>> rot13(rot13("bonjour"))
|
||||
'bonjour'
|
||||
```
|
||||
|
||||
Cela s'explique car 13 + 13 = 26, soit un tour complet de l'alphabet.
|
||||
|
||||
### Généralisation : Chiffre de César
|
||||
|
||||
On peut généraliser avec un décalage variable (chiffre de César) :
|
||||
|
||||
```python
|
||||
def cesar(message, decalage):
|
||||
"""
|
||||
Chiffre un message avec le chiffre de César.
|
||||
|
||||
:param message: (str) Le message à chiffrer
|
||||
:param decalage: (int) Le décalage (clé)
|
||||
:return: (str) Le message chiffré
|
||||
"""
|
||||
resultat = ""
|
||||
for car in message.lower():
|
||||
if 'a' <= car <= 'z':
|
||||
resultat += chr((ord(car) - ord('a') + decalage) % 26 + ord('a'))
|
||||
else:
|
||||
resultat += car
|
||||
return resultat
|
||||
|
||||
|
||||
def decesar(message, decalage):
|
||||
"""Déchiffre un message chiffré avec César."""
|
||||
return cesar(message, -decalage)
|
||||
```
|
||||
|
||||
```python
|
||||
>>> cesar("bonjour", 3) # Décalage de 3 (César classique)
|
||||
'erqmrxu'
|
||||
|
||||
>>> decesar("erqmrxu", 3)
|
||||
'bonjour'
|
||||
|
||||
>>> cesar("bonjour", 13) # ROT13
|
||||
'obawbhe'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
457
Sécurité/Corrige_TP_Gestionnaire_MDP.py
Normal file
457
Sécurité/Corrige_TP_Gestionnaire_MDP.py
Normal file
@@ -0,0 +1,457 @@
|
||||
"""
|
||||
Corrigé du TP Gestionnaire de mots de passe
|
||||
"""
|
||||
|
||||
import random
|
||||
import string
|
||||
import hashlib
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 1 : Chiffrement XOR
|
||||
# =============================================================================
|
||||
|
||||
def xor_chiffrement(message, cle):
|
||||
"""
|
||||
Chiffre ou déchiffre un message avec XOR.
|
||||
|
||||
:param message: (str) Le message à traiter
|
||||
:param cle: (str) La clé de chiffrement
|
||||
:return: (str) Le message chiffré/déchiffré
|
||||
"""
|
||||
resultat = ""
|
||||
for i, caractere in enumerate(message):
|
||||
# Récupérer le caractère de la clé (cyclique)
|
||||
cle_char = cle[i % len(cle)]
|
||||
# Appliquer XOR
|
||||
nouveau_char = chr(ord(caractere) ^ ord(cle_char))
|
||||
resultat += nouveau_char
|
||||
return resultat
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 2 : Classe MotDePasse
|
||||
# =============================================================================
|
||||
|
||||
class MotDePasse:
|
||||
"""Représente un identifiant stocké."""
|
||||
|
||||
def __init__(self, site, identifiant, mot_de_passe):
|
||||
"""
|
||||
Initialise une entrée.
|
||||
|
||||
:param site: (str) Nom du site/service
|
||||
:param identifiant: (str) Nom d'utilisateur ou email
|
||||
:param mot_de_passe: (str) Mot de passe en clair
|
||||
"""
|
||||
self.site = site
|
||||
self.identifiant = identifiant
|
||||
self.mot_de_passe = mot_de_passe
|
||||
|
||||
def __repr__(self):
|
||||
return f"MotDePasse({self.site}, {self.identifiant}, ****)"
|
||||
|
||||
def to_string(self):
|
||||
"""Convertit en chaîne pour le stockage."""
|
||||
return f"{self.site}|{self.identifiant}|{self.mot_de_passe}"
|
||||
|
||||
@staticmethod
|
||||
def from_string(chaine):
|
||||
"""Crée un objet depuis une chaîne."""
|
||||
parties = chaine.split("|")
|
||||
if len(parties) == 3:
|
||||
return MotDePasse(parties[0], parties[1], parties[2])
|
||||
return None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 3 : Gestionnaire principal
|
||||
# =============================================================================
|
||||
|
||||
class GestionnaireMDP:
|
||||
"""Gestionnaire de mots de passe sécurisé."""
|
||||
|
||||
def __init__(self, mot_de_passe_maitre):
|
||||
"""
|
||||
Initialise le gestionnaire.
|
||||
|
||||
:param mot_de_passe_maitre: (str) Clé principale de chiffrement
|
||||
"""
|
||||
self.cle = mot_de_passe_maitre
|
||||
self.coffre = []
|
||||
|
||||
def ajouter(self, site, identifiant, mot_de_passe):
|
||||
"""
|
||||
Ajoute un nouveau mot de passe au coffre.
|
||||
|
||||
:param site: (str) Nom du site
|
||||
:param identifiant: (str) Identifiant
|
||||
:param mot_de_passe: (str) Mot de passe
|
||||
"""
|
||||
# Vérifier si le site existe déjà
|
||||
for mdp in self.coffre:
|
||||
if mdp.site.lower() == site.lower():
|
||||
# Mettre à jour l'entrée existante
|
||||
mdp.identifiant = identifiant
|
||||
mdp.mot_de_passe = mot_de_passe
|
||||
return
|
||||
|
||||
# Sinon, créer une nouvelle entrée
|
||||
nouvelle_entree = MotDePasse(site, identifiant, mot_de_passe)
|
||||
self.coffre.append(nouvelle_entree)
|
||||
|
||||
def rechercher(self, site):
|
||||
"""
|
||||
Recherche un mot de passe par site.
|
||||
|
||||
:param site: (str) Nom du site à rechercher
|
||||
:return: (MotDePasse ou None) L'entrée trouvée
|
||||
"""
|
||||
for mdp in self.coffre:
|
||||
if mdp.site.lower() == site.lower():
|
||||
return mdp
|
||||
return None
|
||||
|
||||
def supprimer(self, site):
|
||||
"""
|
||||
Supprime une entrée du coffre.
|
||||
|
||||
:param site: (str) Nom du site à supprimer
|
||||
:return: (bool) True si supprimé, False sinon
|
||||
"""
|
||||
for i, mdp in enumerate(self.coffre):
|
||||
if mdp.site.lower() == site.lower():
|
||||
self.coffre.pop(i)
|
||||
return True
|
||||
return False
|
||||
|
||||
def lister_sites(self):
|
||||
"""
|
||||
Liste tous les sites enregistrés.
|
||||
|
||||
:return: (list) Liste des noms de sites
|
||||
"""
|
||||
return [mdp.site for mdp in self.coffre]
|
||||
|
||||
def sauvegarder(self, fichier):
|
||||
"""
|
||||
Sauvegarde le coffre dans un fichier chiffré.
|
||||
|
||||
:param fichier: (str) Chemin du fichier
|
||||
"""
|
||||
if not self.coffre:
|
||||
contenu = ""
|
||||
else:
|
||||
contenu = "\n".join([mdp.to_string() for mdp in self.coffre])
|
||||
|
||||
contenu_chiffre = xor_chiffrement(contenu, self.cle)
|
||||
|
||||
with open(fichier, 'w', encoding='utf-8') as f:
|
||||
f.write(contenu_chiffre)
|
||||
|
||||
def charger(self, fichier):
|
||||
"""
|
||||
Charge le coffre depuis un fichier chiffré.
|
||||
|
||||
:param fichier: (str) Chemin du fichier
|
||||
"""
|
||||
with open(fichier, 'r', encoding='utf-8') as f:
|
||||
contenu_chiffre = f.read()
|
||||
|
||||
if not contenu_chiffre:
|
||||
self.coffre = []
|
||||
return
|
||||
|
||||
contenu = xor_chiffrement(contenu_chiffre, self.cle)
|
||||
lignes = contenu.split("\n")
|
||||
|
||||
self.coffre = []
|
||||
for ligne in lignes:
|
||||
if ligne:
|
||||
mdp = MotDePasse.from_string(ligne)
|
||||
if mdp:
|
||||
self.coffre.append(mdp)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 4 : Génération de mots de passe
|
||||
# =============================================================================
|
||||
|
||||
def generer_mot_de_passe(longueur=16, majuscules=True, chiffres=True, speciaux=True):
|
||||
"""
|
||||
Génère un mot de passe aléatoire robuste.
|
||||
|
||||
:param longueur: (int) Longueur du mot de passe
|
||||
:param majuscules: (bool) Inclure des majuscules
|
||||
:param chiffres: (bool) Inclure des chiffres
|
||||
:param speciaux: (bool) Inclure des caractères spéciaux
|
||||
:return: (str) Mot de passe généré
|
||||
"""
|
||||
caracteres = string.ascii_lowercase
|
||||
|
||||
if majuscules:
|
||||
caracteres += string.ascii_uppercase
|
||||
if chiffres:
|
||||
caracteres += string.digits
|
||||
if speciaux:
|
||||
caracteres += "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
||||
|
||||
# Générer le mot de passe
|
||||
mot_de_passe = ''.join(random.choice(caracteres) for _ in range(longueur))
|
||||
|
||||
return mot_de_passe
|
||||
|
||||
|
||||
def evaluer_robustesse(mot_de_passe):
|
||||
"""
|
||||
Évalue la robustesse d'un mot de passe.
|
||||
|
||||
:param mot_de_passe: (str) Le mot de passe à évaluer
|
||||
:return: (str) Niveau de robustesse
|
||||
"""
|
||||
score = 0
|
||||
|
||||
# Longueur
|
||||
if len(mot_de_passe) >= 8:
|
||||
score += 1
|
||||
if len(mot_de_passe) >= 12:
|
||||
score += 1
|
||||
if len(mot_de_passe) >= 16:
|
||||
score += 1
|
||||
|
||||
# Variété de caractères
|
||||
if any(c.islower() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c.isupper() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c.isdigit() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in mot_de_passe):
|
||||
score += 1
|
||||
|
||||
# Retourner le niveau
|
||||
if score <= 2:
|
||||
return "Faible"
|
||||
elif score <= 4:
|
||||
return "Moyen"
|
||||
elif score <= 5:
|
||||
return "Fort"
|
||||
else:
|
||||
return "Très fort"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 5 : Interface utilisateur
|
||||
# =============================================================================
|
||||
|
||||
def menu_principal():
|
||||
"""Affiche le menu principal."""
|
||||
print("\n" + "=" * 40)
|
||||
print(" GESTIONNAIRE DE MOTS DE PASSE")
|
||||
print("=" * 40)
|
||||
print("1. Ajouter un mot de passe")
|
||||
print("2. Rechercher un mot de passe")
|
||||
print("3. Générer un mot de passe")
|
||||
print("4. Lister les sites")
|
||||
print("5. Supprimer une entrée")
|
||||
print("6. Sauvegarder")
|
||||
print("7. Quitter")
|
||||
print("=" * 40)
|
||||
return input("Votre choix : ")
|
||||
|
||||
|
||||
def application():
|
||||
"""Lance l'application."""
|
||||
print("Bienvenue dans le gestionnaire de mots de passe !")
|
||||
mdp_maitre = input("Entrez votre mot de passe maître : ")
|
||||
|
||||
gestionnaire = GestionnaireMDP(mdp_maitre)
|
||||
|
||||
try:
|
||||
gestionnaire.charger("coffre.dat")
|
||||
print("Coffre chargé avec succès.")
|
||||
except FileNotFoundError:
|
||||
print("Nouveau coffre créé.")
|
||||
|
||||
while True:
|
||||
choix = menu_principal()
|
||||
|
||||
if choix == "1":
|
||||
site = input("Site : ")
|
||||
identifiant = input("Identifiant : ")
|
||||
mdp = input("Mot de passe (laisser vide pour générer) : ")
|
||||
if mdp == "":
|
||||
mdp = generer_mot_de_passe()
|
||||
print(f"Mot de passe généré : {mdp}")
|
||||
gestionnaire.ajouter(site, identifiant, mdp)
|
||||
print("Ajouté !")
|
||||
|
||||
elif choix == "2":
|
||||
site = input("Site à rechercher : ")
|
||||
resultat = gestionnaire.rechercher(site)
|
||||
if resultat:
|
||||
print(f"Site : {resultat.site}")
|
||||
print(f"Identifiant : {resultat.identifiant}")
|
||||
print(f"Mot de passe : {resultat.mot_de_passe}")
|
||||
else:
|
||||
print("Site non trouvé.")
|
||||
|
||||
elif choix == "3":
|
||||
try:
|
||||
longueur = int(input("Longueur (défaut 16) : ") or "16")
|
||||
except ValueError:
|
||||
longueur = 16
|
||||
mdp = generer_mot_de_passe(longueur)
|
||||
print(f"Mot de passe généré : {mdp}")
|
||||
print(f"Robustesse : {evaluer_robustesse(mdp)}")
|
||||
|
||||
elif choix == "4":
|
||||
sites = gestionnaire.lister_sites()
|
||||
if sites:
|
||||
print("Sites enregistrés :")
|
||||
for s in sites:
|
||||
print(f" - {s}")
|
||||
else:
|
||||
print("Aucun site enregistré.")
|
||||
|
||||
elif choix == "5":
|
||||
site = input("Site à supprimer : ")
|
||||
if gestionnaire.supprimer(site):
|
||||
print("Supprimé !")
|
||||
else:
|
||||
print("Site non trouvé.")
|
||||
|
||||
elif choix == "6":
|
||||
gestionnaire.sauvegarder("coffre.dat")
|
||||
print("Coffre sauvegardé.")
|
||||
|
||||
elif choix == "7":
|
||||
gestionnaire.sauvegarder("coffre.dat")
|
||||
print("Au revoir !")
|
||||
break
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 6 : Améliorations (Bonus)
|
||||
# =============================================================================
|
||||
|
||||
def hasher(mot_de_passe):
|
||||
"""Retourne le hash SHA-256 du mot de passe."""
|
||||
return hashlib.sha256(mot_de_passe.encode()).hexdigest()
|
||||
|
||||
|
||||
class GestionnaireMDPSecurise(GestionnaireMDP):
|
||||
"""Version améliorée avec hashage du mot de passe maître."""
|
||||
|
||||
def __init__(self, mot_de_passe_maitre):
|
||||
# Utiliser le hash comme clé (plus long = plus sécurisé)
|
||||
cle_derivee = hasher(mot_de_passe_maitre)
|
||||
super().__init__(cle_derivee)
|
||||
self.hash_maitre = hasher(mot_de_passe_maitre + "salt_verification")
|
||||
|
||||
def verifier_mot_de_passe(self, mot_de_passe):
|
||||
"""Vérifie si le mot de passe maître est correct."""
|
||||
return hasher(mot_de_passe + "salt_verification") == self.hash_maitre
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# RÉPONSES AUX QUESTIONS
|
||||
# =============================================================================
|
||||
|
||||
"""
|
||||
RÉPONSES AUX QUESTIONS DE SYNTHÈSE
|
||||
|
||||
1. Pourquoi ne jamais stocker un mot de passe en clair ?
|
||||
- Si un attaquant accède à la base de données, il obtient tous les mots de passe
|
||||
- Les utilisateurs réutilisent souvent leurs mots de passe sur plusieurs sites
|
||||
- C'est une violation des bonnes pratiques de sécurité (RGPD, etc.)
|
||||
|
||||
2. Différence entre chiffrement et hashage :
|
||||
- Chiffrement : opération réversible avec une clé (on peut retrouver le message)
|
||||
- Hashage : opération irréversible (on ne peut pas retrouver le message original)
|
||||
- On chiffre les données confidentielles, on hashe les mots de passe
|
||||
|
||||
3. Pourquoi le mot de passe maître doit être robuste ?
|
||||
- C'est la seule protection de tous vos mots de passe
|
||||
- Une attaque par force brute pourrait le trouver si trop faible
|
||||
- Compromis = tous les mots de passe compromis
|
||||
|
||||
4. Risques si quelqu'un obtient coffre.dat ?
|
||||
- Il peut tenter une attaque par force brute sur le mot de passe maître
|
||||
- XOR est vulnérable à certaines attaques (ex: known-plaintext attack)
|
||||
- C'est pourquoi les vrais gestionnaires utilisent AES-256
|
||||
|
||||
5. Comment les vrais gestionnaires améliorent la sécurité ?
|
||||
- Chiffrement AES-256 au lieu de XOR
|
||||
- Dérivation de clé (PBKDF2, Argon2) pour ralentir les attaques
|
||||
- Authentification à deux facteurs
|
||||
- Chiffrement de bout en bout
|
||||
- Audit de sécurité par des experts
|
||||
"""
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TESTS
|
||||
# =============================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
print("=" * 60)
|
||||
print("TEST 1 : CHIFFREMENT XOR")
|
||||
print("=" * 60)
|
||||
|
||||
message = "Bonjour le monde !"
|
||||
cle = "secret"
|
||||
chiffre = xor_chiffrement(message, cle)
|
||||
print(f"Message original : {message}")
|
||||
print(f"Clé : {cle}")
|
||||
print(f"Message chiffré : {repr(chiffre)}")
|
||||
dechiffre = xor_chiffrement(chiffre, cle)
|
||||
print(f"Message déchiffré : {dechiffre}")
|
||||
print(f"Vérification : {message == dechiffre}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 2 : GÉNÉRATION DE MOT DE PASSE")
|
||||
print("=" * 60)
|
||||
|
||||
for _ in range(5):
|
||||
mdp = generer_mot_de_passe(16)
|
||||
robustesse = evaluer_robustesse(mdp)
|
||||
print(f"{mdp} -> {robustesse}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 3 : GESTIONNAIRE")
|
||||
print("=" * 60)
|
||||
|
||||
gestionnaire = GestionnaireMDP("mon_mot_de_passe_maitre")
|
||||
|
||||
gestionnaire.ajouter("Gmail", "alice@gmail.com", "mdp_gmail_123")
|
||||
gestionnaire.ajouter("Facebook", "alice", "fb_password!")
|
||||
gestionnaire.ajouter("Netflix", "alice@gmail.com", "netflix2024")
|
||||
|
||||
print("Sites enregistrés :", gestionnaire.lister_sites())
|
||||
|
||||
resultat = gestionnaire.rechercher("gmail")
|
||||
if resultat:
|
||||
print(f"Gmail -> {resultat.identifiant} : {resultat.mot_de_passe}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 4 : SAUVEGARDE/CHARGEMENT")
|
||||
print("=" * 60)
|
||||
|
||||
gestionnaire.sauvegarder("test_coffre.dat")
|
||||
print("Coffre sauvegardé.")
|
||||
|
||||
nouveau_gestionnaire = GestionnaireMDP("mon_mot_de_passe_maitre")
|
||||
nouveau_gestionnaire.charger("test_coffre.dat")
|
||||
print("Coffre chargé.")
|
||||
print("Sites récupérés :", nouveau_gestionnaire.lister_sites())
|
||||
|
||||
# Nettoyage
|
||||
import os
|
||||
os.remove("test_coffre.dat")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Pour lancer l'application interactive :")
|
||||
print(" application()")
|
||||
print("=" * 60)
|
||||
167
Sécurité/EVALUATION.md
Normal file
167
Sécurité/EVALUATION.md
Normal file
@@ -0,0 +1,167 @@
|
||||
## Évaluation
|
||||
|
||||
### Sujet
|
||||
|
||||
Le ROT47 est un cas particulier du chiffre de César, où la clé vaut 47. Les caractères d'un texte sont associés à leur valeur ASCII. On n'applique le décalage qu'aux caractères ayant une valeur comprise entre [33, 126], les autres caractères restent inchangés.
|
||||
|
||||
Par exemple, le caractère ! devient P :
|
||||
|
||||
```python
|
||||
>>> chr(33)
|
||||
'!'
|
||||
>>> chr(33 +47)
|
||||
'p'
|
||||
```
|
||||
|
||||
Lorsque l'on dépasse 126, on retourne à 33. La lettre S, par exemple, qui a pour code ASCII 83. Avec la rotation 47, cela donne 83 + 47 = 130 = 127 + 3. Donc S est codé en chr(33 + 3) = $
|
||||
|
||||
1. Écrire une fonction python qui permet de chiffrer en ROT47. Déterminer alors le chiffrement de "Bonjour le monde ! "
|
||||
|
||||
2. Comment déchiffrer un message dont on sait qu'il a été chiffré avec ROT47 ? Quelle est sa particularité ?
|
||||
|
||||
3. On intercepte le fichier [rotXcrypte.txt](rotXcrypte.txt), codé en ROTx, avec x un nombre inconnu. On sait juste que cette fois, on utilise les points de code de ***0x21*** à ***0x1F0DF*** compris. Il ne s'agit donc plus d'ASCII mais le principe reste le même. Seule la limite maximum passe de 126 (***Ox7e***) à ***0x1f0df***
|
||||
|
||||
1. Comment procéder à une attaque de force brute ? Combien d'essais devrait-on effectuer au pire ?
|
||||
|
||||
2. Comment effectuer une attaque statistique sachant que le texte original est en français ?
|
||||
|
||||
3. Comparons donc avec un texte en français, les Trois Mousquetaires d'Alexandre Dumas:
|
||||
|
||||
```python
|
||||
from urllib.request import urlretrieve
|
||||
url_mousq = "https://www.gutenberg.org/cache/epub/13951/pg13951.txt"
|
||||
urlretrieve(url_mousq, 'mousq.txt')
|
||||
fic: str = open('mousq.txt', 'r').read()
|
||||
```
|
||||
|
||||
Créer une fonction de signature:
|
||||
|
||||
```python
|
||||
def stat(mes: str) -> list
|
||||
```
|
||||
|
||||
Qui prend une chaîne de caractères en paramètre et renvoie la liste des caractères rangés par ordre décroissant de fréquence
|
||||
|
||||
|
||||
|
||||
4. On suppose disposer d'un tableau de fréquence pour le message à déchiffrer. Créer la fonction
|
||||
|
||||
```python
|
||||
def remplace (origine: str, etalon: str) -> str
|
||||
```
|
||||
|
||||
qui va remplacer chaque lettre dans le message chiffré par la lettre du message "etalon" (ici les Trois Mousquetaires) en suivant l'ordre d'apparition des lettres.
|
||||
|
||||
Obtient-on une bonne traduction ? Pourquoi ?
|
||||
|
||||
5. On découvre qu'il s'agit d'un chiffrement par décalage. Quelle autre stratégie peut-on employer pour découvrir ce décalage si l'on connaît le caractère le plus fréquent dans le message à déchiffrer et dans le texte étalon ?
|
||||
|
||||
6. Créer une fonction de même signature que la précédente mais qui utilise les nouveaux renseignements pour déchiffrer plus efficacement. Expliquer votre fonction.
|
||||
|
||||
7. Quelle pourrait être l'utilisation moderne de ROT47 dans le contexte d'Internet ?
|
||||
|
||||
--------
|
||||
|
||||
#### Corrigé
|
||||
|
||||
1. ```python
|
||||
def rot47(clair: str) -> str:
|
||||
chif =""
|
||||
dec = 33
|
||||
amp = 127 - dec
|
||||
for car in clair:
|
||||
new_code = dec + ((ord( car) - dec + 47) % amp)
|
||||
chif += chr(new_code) if 33 <= ord(car) <= 126 else car
|
||||
return chif
|
||||
|
||||
```
|
||||
|
||||
On obtient donc :
|
||||
|
||||
```python
|
||||
>>> rot47("Bonjour le monde !")
|
||||
'q@?;@FC =6 >@?56 P'
|
||||
```
|
||||
|
||||
2. Le nombre de caractères décalables vaut 127 - 33 = 94. Il faut donc appliquer un décalage de -47 pour déchiffrer, sauf que... On remarque que si on applique un décalage de 47 après un premier décalage de 47, on effectue donc un décalage de 94 qui revient au point de départ. On peut imaginer le ROT47 comme un déplacement sur une roue ayant 94 graduations.
|
||||
|
||||
On n'a donc pas besoin de nouvelle fonction : la fonction de chiffrement est aussi la fonction de déchiffrement.
|
||||
|
||||
3. - 0x1f0df - 0x21 = 127166. Il y a donc autant de clés possible à essayer.
|
||||
|
||||
- Dans un chiffrement par décalage, chaque lettre est toujours chiffrée de la même manière donc la fréquence d'un caractère, par exemple le e, dans le texte clair, sera la même que la fréquence de son caractère associé dans le texte chiffré.
|
||||
|
||||
Il suffit donc de classer les caractères du texte chiffré selon leurs fréquences d'apparition et de comparer aux fréquences d'apparition usuelles des caractères de la langue française.
|
||||
|
||||
- On parcourt le texte. On regarde chaque caractère. S'il est dans le dictionnaire, on ajoute 1 à la valeur associée, sinon on crée une entrée avec pour valeur 1. On renvoie le dictionnaire trié par fréquence décroissante.
|
||||
|
||||
```python
|
||||
def stat(mes: str) -> list:
|
||||
dico = {}
|
||||
for lettre in mes:
|
||||
if lettre in dico:
|
||||
dico[lettre] += 1
|
||||
else:
|
||||
dico[lettre] = 1
|
||||
return sorted(dico, key = lambda x: dico[x], reverse=True)
|
||||
```
|
||||
|
||||
On veut que le i-ième caractère du texte chiffré soit remplacé par le i-ième caractère du texte français de référence. Ces listes de fréquences n'étant pas a priori de même taille, on prend la précaution de récupérer la taille minimum.
|
||||
|
||||
4.
|
||||
|
||||
```python
|
||||
def remplace (origine: str, etalon: str) -> str:
|
||||
s_origine = stat(origine) #frequence du message
|
||||
s_etalon = stat(etalon) # frequence du texte de référence
|
||||
mini = min(len(s_origine), len(s_etalon)) # taille minimum
|
||||
dic = {} # dictionnaire de correspondance chiffré -> référence
|
||||
for i in range(mini):
|
||||
dic[ s_origine[i] ] = s_etalon[i]
|
||||
# on parcourt chaque caractère et on le remplace par sa traduction
|
||||
trad = ""
|
||||
for lettre in origine:
|
||||
trad += dic[lettre]
|
||||
return trad
|
||||
```
|
||||
|
||||
Mais cela ne donne pas la meilleure traduction.
|
||||
|
||||
5. On repère le caractère le plus fréquent dans les deux textes ce qui nous donne le décalage probable en effectuant la différence des points de code de chacun.
|
||||
|
||||
```python
|
||||
def guess(origine: str, etalon: str) -> str:
|
||||
s_origine = stat(origine)
|
||||
s_etalon = stat(etalon)
|
||||
dec = ord(s_origine[0]) - ord(s_etalon[0])
|
||||
return rotx(origine, -dec)
|
||||
```
|
||||
|
||||
6. Sans oublier de créer la fonction rotx qui généralise rot47:
|
||||
|
||||
```
|
||||
def rotx(clair: str, cle : int) -> str:
|
||||
chif =""
|
||||
dec = 0x20
|
||||
amp = 0x1f0e0 - dec
|
||||
for car in clair:
|
||||
new_code = dec + ((ord(car) - dec + cle) % amp)
|
||||
chif += chr(new_code) if 0x20 <= ord(car) <= 0x1f0df else car
|
||||
return chif
|
||||
```
|
||||
|
||||
|
||||
|
||||
Cette fois ci, c'est bon.
|
||||
|
||||
7. ROT47 et ROT13 sont souvent disponibles sur les navigateurs web car ils permettent de brouiller des textes pour les divers robots interceptant les données entrées par un utilisateur afin de faire de l'analyse de texte...
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
|
||||
|
||||
@@ -29,4 +29,12 @@ Quelques conseils :
|
||||
|
||||
|
||||
|
||||
Chiffrez vos noms, prénoms, ainsi que le message 'Vive les numeriques et sciences informatiques'
|
||||
Chiffrez vos noms, prénoms, ainsi que le message 'Vive les numériques et sciences informatiques'
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
<img src="assets/bo.png" alt="bo" style="zoom:50%;" />
|
||||
|
||||
> Avec l'avancée technologique ainsi que les échanges sur Internet (**Environ 319,6 milliards d'e-mails étaient envoyés et reçus chaque jour en 2021**) il est devenu indispensable de sécuriser nos échanges. En effet, entre la santé, l'économie, l'administratif...de nombreux services passent aujourd'hui intégralement par le réseau mondial, sans parler des messages professionnels pouvant relever du confidentiel, de nos données qui valent des millions d'€, il devient donc impératif de savoir se protéger, ainsi que d'utiliser des services étant eux mêmes protégés.
|
||||
> Avec l'avancée technologique ainsi que les échanges sur Internet (**Environ 319,6 milliards d'e-mails étaient envoyés et reçus chaque jour en 2021**) il est devenu indispensable de sécuriser nos échanges. En effet, entre la santé, l'économie, l'administratif...de nombreux services passent aujourd'hui intégralement par le réseau mondial, sans parler des messages professionnels pouvant relever du confidentiel, de nos données qui valent des millions d'€, il devient donc impératif de savoir se protéger, ainsi que d'utiliser des services étant eux-mêmes protégés.
|
||||
|
||||
### 1. Qu'est ce que le chiffrement ?
|
||||
### 1. Qu'est-ce que le chiffrement ?
|
||||
|
||||
Contrairement aux idées reçues, le ***chiffrement*** *n'a pas pour but de rendre invisible vos données ou vos messages*. Cela est beaucoup trop compliqué dans une société hyper connectée comme la notre. Par contre, *il permet de rendre les données et échanges incompréhensibles aux yeux de tous et toutes* : seule la personne destinée à recevoir votre message pourra le comprendre.
|
||||
Contrairement aux idées reçues, le ***chiffrement*** *n'a pas pour but de rendre invisible vos données ou vos messages*. Cela est beaucoup trop compliqué dans une société hyper connectée comme la nôtre. Par contre, *il permet de rendre les données et échanges incompréhensibles aux yeux de tous et toutes* : seule la personne destinée à recevoir votre message pourra le comprendre.
|
||||
|
||||
Un bon algorithme de chiffrement a besoin de certains pré-requis pour être efficace :
|
||||
|
||||
@@ -17,7 +17,7 @@ Un bon algorithme de chiffrement a besoin de certains pré-requis pour être eff
|
||||
|
||||
> Un algorithme de chiffrement est une suite d'opérations destinées à chiffrer un message.
|
||||
>
|
||||
> Un algorithme de déchiffrement est une suite d'opération destinées à déchiffrer le message.
|
||||
> Un algorithme de déchiffrement est une suite d'opérations destinées à déchiffrer le message.
|
||||
>
|
||||
> Certains algorithmes font les deux.
|
||||
|
||||
@@ -33,9 +33,9 @@ L'Agence Nationale de la Sécurité des Services d'Informations (ANSSI) qualifi
|
||||
|
||||
### 2. Un peu d'histoire
|
||||
|
||||
Si le chiffrement est aujourd'hui associé aux échanges numériques, il ne faut pas croire que cette méthode est récente : l'humain cherche à sécuriser ses communications depuis l'Antiquité, notamment dans le domaine militaire. Un des premiers code est d'ailleurs celui inventé par Jules César : Le chiffre de César. Il s'agissait de décaler chaque lettre de l'aphabet de trois rangs (car la lettre C est la troisième). A devenant D, B devenant E, etc. Ce chiffrement a été utilisé par les égyptiens en -2000.
|
||||
Si le chiffrement est aujourd'hui associé aux échanges numériques, il ne faut pas croire que cette méthode est récente : l'humain cherche à sécuriser ses communications depuis l'Antiquité, notamment dans le domaine militaire. Un des premiers codes est d'ailleurs celui inventé par Jules César : le chiffre de César. Il s'agissait de décaler chaque lettre de l'alphabet de trois rangs (car la lettre C est la troisième). A devenant D, B devenant E, etc. Ce chiffrement a été utilisé par les égyptiens en -2000.
|
||||
|
||||
Évidemment, une telle clé est facilement attaquable aujourd'hui (dans le cas d'un chiffrement par décalage, il existe donc vingt-cinq clés possible, ce qu'une attaque par **bruteforce** peut trouver en quelques secondes avec les machines actuelles.)
|
||||
Évidemment, une telle clé est facilement attaquable aujourd'hui (dans le cas d'un chiffrement par décalage, il existe donc vingt-cinq clés possibles, ce qu'une attaque par **bruteforce** peut trouver en quelques secondes avec les machines actuelles.)
|
||||
|
||||
Plus sophistiqué, ***le chiffre de Vigénère*** utilise un décalage alphabétique également, mais avec une clé de plusieurs lettres répétée. Si la clé est NSI, la première et la quatrième lettre du message seront décalées de 14, la deuxième et la cinquième de 19, la troisième et la sixième de 9 etc. Ce chiffre a résisté longtemps au décryptage, et a été utilisé jusque pendant la guerre de Sécession.
|
||||
|
||||
@@ -47,17 +47,17 @@ Enfin, le fameux code ***Enigma*** utilisé par l’Allemagne nazie pendant la
|
||||
|
||||
Un chiffrement est dit symétrique lorsque la clé utilisée pour chiffrer le message permet également de le déchiffrer.
|
||||
|
||||
On parle alors de ***clé secrète*** commune à l'ensemble des interlocuteurs d'une conversation, et va permettre de chiffrer les données lors de l'envoie, puis de les déchiffrer à leur réception.
|
||||
On parle alors de ***clé secrète*** commune à l'ensemble des interlocuteurs d'une conversation, et va permettre de chiffrer les données lors de l'envoi, puis de les déchiffrer à leur réception.
|
||||
|
||||
<img src="assets/chiffrement_sym.png" alt="chiffrement_sym" style="zoom: 50%;" />
|
||||
|
||||
> Évidemment, il est necessaire de générer la clé et de la partager aux personnes / machines concernées par la communication, avant de commencer les échanges. Chaque machine pourra, dès lors, emettre ou recevoir des message chiffrés avec cette clé.
|
||||
> Évidemment, il est nécessaire de générer la clé et de la partager aux personnes / machines concernées par la communication, avant de commencer les échanges. Chaque machine pourra, dès lors, émettre ou recevoir des messages chiffrés avec cette clé.
|
||||
>
|
||||
> Il est donc primordiale de passer par un canal de communication déjà sécurisé afin de transmettre la clé, le chiffrement symétrique étant donc impossible à utiliser pour initialiser une communication chiffré.
|
||||
> Il est donc primordial de passer par un canal de communication déjà sécurisé afin de transmettre la clé, le chiffrement symétrique étant donc impossible à utiliser pour initialiser une communication chiffrée.
|
||||
|
||||
#### Pour la culture
|
||||
|
||||
Aujourd'hui, le standard utilisé en matière de chiffrement symétrique est l'[AES](https://fr.wikipedia.org/wiki/Advanced_Encryption_Standard) (Advanced Encryption Standard) qui utilise une clé pouvant aller jusqu'à 256 bits de longueur, ce qui laisse "juste" 2<sup>256</sup> possibilitées, soit 10<sup>77</sup> clés à tester.
|
||||
Aujourd'hui, le standard utilisé en matière de chiffrement symétrique est l'[AES](https://fr.wikipedia.org/wiki/Advanced_Encryption_Standard) (Advanced Encryption Standard) qui utilise une clé pouvant aller jusqu'à 256 bits de longueur, ce qui laisse "juste" 2<sup>256</sup> possibilités, soit 10<sup>77</sup> clés à tester.
|
||||
|
||||
La meilleure méthode pour le casser restant, à ce jour, la force brute.
|
||||
|
||||
@@ -74,7 +74,7 @@ Créé très récemment (1976 !) par Whitfield Diffie et Martin Hellman, il port
|
||||
- Partie privée (**clé privée** et notée *s* pour secret) que chaque personne conserve précieusement.
|
||||
- Partie publique (**clé publique**, notée *p* pour publique) qui peut être révélée à tout le monde.
|
||||
|
||||
Pour faire simple, un message chiffré avec une partie d'une clé necessite l'utilisation de l'autre partie de la clé pour être déchiffré.
|
||||
Pour faire simple, un message chiffré avec une partie d'une clé nécessite l'utilisation de l'autre partie de la clé pour être déchiffré.
|
||||
|
||||
Prenons Alice et Bob, deux personnes qui cherchent à communiquer de manière sécurisée. Cela se passera en trois étapes :
|
||||
|
||||
@@ -97,14 +97,15 @@ Avec ce type de chiffrement, la clé publique peut être partagée de manière o
|
||||
|
||||
Le chiffrement asymétrique utilise des fonctions mathématiques à sens unique.
|
||||
|
||||
Une fonction à sens unique est une fonction mathématique $f$ dont la réciproque $f^-1$ est très difficile à trouver (plusieurs milliers / millions d'années de calcul)
|
||||
Cependant, une brèche secrète est toujours crée afin de pouvoir trouver cette réciproque.
|
||||
Une fonction à sens unique est une fonction mathématique $f$ dont la réciproque $f^{-1}$ est très difficile à trouver (plusieurs milliers / millions d'années de calcul).
|
||||
|
||||
Cependant, une brèche secrète est toujours créée afin de pouvoir trouver cette réciproque.
|
||||
|
||||
Ici, la fonction est *p*, la clé publique. Et la brèche secrète, *s*, la clé privée.
|
||||
|
||||
Le chiffrement [RSA](https://fr.wikipedia.org/wiki/Chiffrement_RSA) est latechnologie la plus utilisée en matière de chiffrement asymétrique : crée en 1978 par Ronald Rivest, Adi Shamir et Leonard Adleman, ce protocole utilise des théorèmes arithmétiques connus (voir celui de Fermat en maths expertes)
|
||||
Le chiffrement [RSA](https://fr.wikipedia.org/wiki/Chiffrement_RSA) est la technologie la plus utilisée en matière de chiffrement asymétrique : créé en 1978 par Ronald Rivest, Adi Shamir et Leonard Adleman, ce protocole utilise des théorèmes arithmétiques connus (voir celui de Fermat en maths expertes).
|
||||
|
||||
Ce chiffrement necessite une plus grand force de calcul ainsi que des clés de très grandes longueurs pour garantir la sécurité.
|
||||
Ce chiffrement nécessite une plus grande force de calcul ainsi que des clés de très grandes longueurs pour garantir la sécurité.
|
||||
|
||||
#### Quels usages ?
|
||||
|
||||
@@ -114,16 +115,16 @@ Les signatures numériques, les échanges de clés secrètes afin de pouvoir ini
|
||||
|
||||
### 5. Le HTTPS
|
||||
|
||||
Le protocole HTTP ( Hyper Text Transfert Protocol) est celui utilisé pour le partage de pages web via Internet. Il transmet les requetes de pages et assure leur transport entre le client et le serveur.
|
||||
Le protocole HTTP (Hyper Text Transfer Protocol) est celui utilisé pour le partage de pages web via Internet. Il transmet les requêtes de pages et assure leur transport entre le client et le serveur.
|
||||
|
||||
Mais ces échanges ne sont pas sécurisés. Il est donc necessaire de mettre en place des outils permettant de chiffrer les transmissions de requetes ainsi que les réponses, surtout en ce qui concerne les échanges monétaires et d'authentification.
|
||||
Mais ces échanges ne sont pas sécurisés. Il est donc nécessaire de mettre en place des outils permettant de chiffrer les transmissions de requêtes ainsi que les réponses, surtout en ce qui concerne les échanges monétaires et d'authentification.
|
||||
|
||||
Deux principaux problèmes étaient pointés du doigt:
|
||||
|
||||
- Données qui transitent en clair et peuvent être lues par une tierce personne ([Man in the middle](https://fr.wikipedia.org/wiki/Attaque_de_l'homme_du_milieu))
|
||||
- Une tierce personne peut se faire passer pour le serveur et recevoir vos données ([Fishing - Hameçonnage](https://fr.wikipedia.org/wiki/Hame%C3%A7onnage))
|
||||
|
||||
Deux protocoles ont emergé, **SSL** (Secure Sockets Layer) tout d'abord, puis son évolution, **TLS** (Transport Layer Security).
|
||||
Deux protocoles ont émergé, **SSL** (Secure Sockets Layer) tout d'abord, puis son évolution, **TLS** (Transport Layer Security).
|
||||
|
||||
Couplé au HTTP, ils prennent le nom d'HTTPS ([Hyper Text Transfert Protocol Secure](https://fr.wikipedia.org/wiki/HyperText_Transfer_Protocol_Secure))
|
||||
|
||||
@@ -144,7 +145,7 @@ Ces protocoles agissent au niveau de la couche 5 du modèle OSI
|
||||
|
||||
--------
|
||||
|
||||
#### Souces
|
||||
#### Sources
|
||||
|
||||
<a href="https://www.flaticon.com/free-icons/computer" title="computer icons">Computer icons created by Freepik - Flaticon</a>
|
||||
|
||||
|
||||
427
Sécurité/TP_Gestionnaire_MDP.md
Normal file
427
Sécurité/TP_Gestionnaire_MDP.md
Normal file
@@ -0,0 +1,427 @@
|
||||
# TP : Gestionnaire de mots de passe
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous développez un gestionnaire de mots de passe simplifié, similaire à **Bitwarden**, **1Password** ou **KeePass**. Ce type d'application permet de stocker de manière sécurisée tous ses identifiants en les chiffrant avec un mot de passe maître.
|
||||
|
||||
L'objectif est de comprendre les mécanismes de chiffrement symétrique et les bonnes pratiques de sécurité.
|
||||
|
||||
---
|
||||
|
||||
## Objectifs
|
||||
|
||||
- Implémenter un chiffrement symétrique simple
|
||||
- Comprendre le rôle du mot de passe maître
|
||||
- Stocker et récupérer des données chiffrées
|
||||
- Générer des mots de passe robustes
|
||||
|
||||
---
|
||||
|
||||
## Partie 1 : Chiffrement XOR
|
||||
|
||||
### 1.1. Principe du XOR
|
||||
|
||||
L'opération XOR (ou exclusif) est fondamentale en cryptographie. Elle possède une propriété intéressante :
|
||||
|
||||
```
|
||||
A XOR B XOR B = A
|
||||
```
|
||||
|
||||
Autrement dit, appliquer deux fois XOR avec la même clé redonne le message original.
|
||||
|
||||
### 1.2. Implémentation
|
||||
|
||||
Implémenter la fonction de chiffrement XOR :
|
||||
|
||||
```python
|
||||
def xor_chiffrement(message, cle):
|
||||
"""
|
||||
Chiffre ou déchiffre un message avec XOR.
|
||||
|
||||
:param message: (str) Le message à traiter
|
||||
:param cle: (str) La clé de chiffrement
|
||||
:return: (str) Le message chiffré/déchiffré
|
||||
"""
|
||||
resultat = ""
|
||||
for i, caractere in enumerate(message):
|
||||
# Récupérer le caractère de la clé (cyclique)
|
||||
cle_char = cle[i % len(cle)]
|
||||
# Appliquer XOR
|
||||
nouveau_char = chr(ord(caractere) ^ ord(cle_char))
|
||||
resultat += nouveau_char
|
||||
return resultat
|
||||
```
|
||||
|
||||
**Test** :
|
||||
```python
|
||||
>>> message = "Bonjour le monde"
|
||||
>>> cle = "secret"
|
||||
>>> chiffre = xor_chiffrement(message, cle)
|
||||
>>> print(chiffre) # Caractères illisibles
|
||||
>>> xor_chiffrement(chiffre, cle) # Déchiffrement
|
||||
'Bonjour le monde'
|
||||
```
|
||||
|
||||
### 1.3. Questions
|
||||
|
||||
1. Pourquoi la clé est-elle utilisée de manière cyclique ?
|
||||
2. Que se passe-t-il si la clé est aussi longue que le message ?
|
||||
3. Pourquoi XOR seul n'est-il pas suffisamment sécurisé ?
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 : Classe MotDePasse
|
||||
|
||||
### 2.1. Structure d'une entrée
|
||||
|
||||
Créer une classe pour représenter un mot de passe stocké :
|
||||
|
||||
```python
|
||||
class MotDePasse:
|
||||
"""Représente un identifiant stocké."""
|
||||
|
||||
def __init__(self, site, identifiant, mot_de_passe):
|
||||
"""
|
||||
Initialise une entrée.
|
||||
|
||||
:param site: (str) Nom du site/service
|
||||
:param identifiant: (str) Nom d'utilisateur ou email
|
||||
:param mot_de_passe: (str) Mot de passe en clair
|
||||
"""
|
||||
self.site = site
|
||||
self.identifiant = identifiant
|
||||
self.mot_de_passe = mot_de_passe
|
||||
|
||||
def __repr__(self):
|
||||
# Ne pas afficher le mot de passe en clair !
|
||||
return f"MotDePasse({self.site}, {self.identifiant}, ****)"
|
||||
|
||||
def to_string(self):
|
||||
"""Convertit en chaîne pour le stockage."""
|
||||
return f"{self.site}|{self.identifiant}|{self.mot_de_passe}"
|
||||
|
||||
@staticmethod
|
||||
def from_string(chaine):
|
||||
"""Crée un objet depuis une chaîne."""
|
||||
parties = chaine.split("|")
|
||||
return MotDePasse(parties[0], parties[1], parties[2])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 : Gestionnaire principal
|
||||
|
||||
### 3.1. Classe GestionnaireMDP
|
||||
|
||||
Implémenter le gestionnaire complet :
|
||||
|
||||
```python
|
||||
class GestionnaireMDP:
|
||||
"""Gestionnaire de mots de passe sécurisé."""
|
||||
|
||||
def __init__(self, mot_de_passe_maitre):
|
||||
"""
|
||||
Initialise le gestionnaire.
|
||||
|
||||
:param mot_de_passe_maitre: (str) Clé principale de chiffrement
|
||||
"""
|
||||
self.cle = mot_de_passe_maitre
|
||||
self.coffre = [] # Liste des MotDePasse
|
||||
|
||||
def ajouter(self, site, identifiant, mot_de_passe):
|
||||
"""
|
||||
Ajoute un nouveau mot de passe au coffre.
|
||||
|
||||
:param site: (str) Nom du site
|
||||
:param identifiant: (str) Identifiant
|
||||
:param mot_de_passe: (str) Mot de passe
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def rechercher(self, site):
|
||||
"""
|
||||
Recherche un mot de passe par site.
|
||||
|
||||
:param site: (str) Nom du site à rechercher
|
||||
:return: (MotDePasse ou None) L'entrée trouvée
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def supprimer(self, site):
|
||||
"""
|
||||
Supprime une entrée du coffre.
|
||||
|
||||
:param site: (str) Nom du site à supprimer
|
||||
:return: (bool) True si supprimé, False sinon
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def lister_sites(self):
|
||||
"""
|
||||
Liste tous les sites enregistrés (sans les mots de passe).
|
||||
|
||||
:return: (list) Liste des noms de sites
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
### 3.2. Sauvegarde chiffrée
|
||||
|
||||
Ajouter les méthodes de sauvegarde et chargement :
|
||||
|
||||
```python
|
||||
def sauvegarder(self, fichier):
|
||||
"""
|
||||
Sauvegarde le coffre dans un fichier chiffré.
|
||||
|
||||
:param fichier: (str) Chemin du fichier
|
||||
"""
|
||||
# Convertir toutes les entrées en une chaîne
|
||||
contenu = "\n".join([mdp.to_string() for mdp in self.coffre])
|
||||
# Chiffrer le contenu
|
||||
contenu_chiffre = xor_chiffrement(contenu, self.cle)
|
||||
# Écrire dans le fichier
|
||||
with open(fichier, 'w', encoding='utf-8') as f:
|
||||
f.write(contenu_chiffre)
|
||||
|
||||
def charger(self, fichier):
|
||||
"""
|
||||
Charge le coffre depuis un fichier chiffré.
|
||||
|
||||
:param fichier: (str) Chemin du fichier
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 : Génération de mots de passe
|
||||
|
||||
### 4.1. Générateur simple
|
||||
|
||||
Créer une fonction de génération de mots de passe robustes :
|
||||
|
||||
```python
|
||||
import random
|
||||
import string
|
||||
|
||||
def generer_mot_de_passe(longueur=16, majuscules=True, chiffres=True, speciaux=True):
|
||||
"""
|
||||
Génère un mot de passe aléatoire robuste.
|
||||
|
||||
:param longueur: (int) Longueur du mot de passe
|
||||
:param majuscules: (bool) Inclure des majuscules
|
||||
:param chiffres: (bool) Inclure des chiffres
|
||||
:param speciaux: (bool) Inclure des caractères spéciaux
|
||||
:return: (str) Mot de passe généré
|
||||
"""
|
||||
caracteres = string.ascii_lowercase
|
||||
|
||||
if majuscules:
|
||||
caracteres += string.ascii_uppercase
|
||||
if chiffres:
|
||||
caracteres += string.digits
|
||||
if speciaux:
|
||||
caracteres += "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
||||
|
||||
# À compléter : générer le mot de passe
|
||||
pass
|
||||
```
|
||||
|
||||
### 4.2. Vérification de robustesse
|
||||
|
||||
Implémenter une fonction d'évaluation :
|
||||
|
||||
```python
|
||||
def evaluer_robustesse(mot_de_passe):
|
||||
"""
|
||||
Évalue la robustesse d'un mot de passe.
|
||||
|
||||
:param mot_de_passe: (str) Le mot de passe à évaluer
|
||||
:return: (str) Niveau de robustesse (Faible, Moyen, Fort, Très fort)
|
||||
"""
|
||||
score = 0
|
||||
|
||||
# Longueur
|
||||
if len(mot_de_passe) >= 8:
|
||||
score += 1
|
||||
if len(mot_de_passe) >= 12:
|
||||
score += 1
|
||||
if len(mot_de_passe) >= 16:
|
||||
score += 1
|
||||
|
||||
# Variété de caractères
|
||||
if any(c.islower() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c.isupper() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c.isdigit() for c in mot_de_passe):
|
||||
score += 1
|
||||
if any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in mot_de_passe):
|
||||
score += 1
|
||||
|
||||
# À compléter : retourner le niveau selon le score
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Interface utilisateur
|
||||
|
||||
### 5.1. Menu interactif
|
||||
|
||||
Créer une interface en ligne de commande :
|
||||
|
||||
```python
|
||||
def menu_principal():
|
||||
"""Affiche le menu principal."""
|
||||
print("\n" + "=" * 40)
|
||||
print(" GESTIONNAIRE DE MOTS DE PASSE")
|
||||
print("=" * 40)
|
||||
print("1. Ajouter un mot de passe")
|
||||
print("2. Rechercher un mot de passe")
|
||||
print("3. Générer un mot de passe")
|
||||
print("4. Lister les sites")
|
||||
print("5. Supprimer une entrée")
|
||||
print("6. Sauvegarder")
|
||||
print("7. Quitter")
|
||||
print("=" * 40)
|
||||
return input("Votre choix : ")
|
||||
|
||||
|
||||
def application():
|
||||
"""Lance l'application."""
|
||||
print("Bienvenue dans le gestionnaire de mots de passe !")
|
||||
mdp_maitre = input("Entrez votre mot de passe maître : ")
|
||||
|
||||
gestionnaire = GestionnaireMDP(mdp_maitre)
|
||||
|
||||
# Tenter de charger un coffre existant
|
||||
try:
|
||||
gestionnaire.charger("coffre.dat")
|
||||
print("Coffre chargé avec succès.")
|
||||
except FileNotFoundError:
|
||||
print("Nouveau coffre créé.")
|
||||
|
||||
while True:
|
||||
choix = menu_principal()
|
||||
|
||||
if choix == "1":
|
||||
# Ajouter
|
||||
site = input("Site : ")
|
||||
identifiant = input("Identifiant : ")
|
||||
mdp = input("Mot de passe (laisser vide pour générer) : ")
|
||||
if mdp == "":
|
||||
mdp = generer_mot_de_passe()
|
||||
print(f"Mot de passe généré : {mdp}")
|
||||
gestionnaire.ajouter(site, identifiant, mdp)
|
||||
print("Ajouté !")
|
||||
|
||||
elif choix == "2":
|
||||
# Rechercher
|
||||
site = input("Site à rechercher : ")
|
||||
resultat = gestionnaire.rechercher(site)
|
||||
if resultat:
|
||||
print(f"Site : {resultat.site}")
|
||||
print(f"Identifiant : {resultat.identifiant}")
|
||||
print(f"Mot de passe : {resultat.mot_de_passe}")
|
||||
else:
|
||||
print("Site non trouvé.")
|
||||
|
||||
elif choix == "3":
|
||||
# Générer
|
||||
longueur = int(input("Longueur (défaut 16) : ") or "16")
|
||||
mdp = generer_mot_de_passe(longueur)
|
||||
print(f"Mot de passe généré : {mdp}")
|
||||
print(f"Robustesse : {evaluer_robustesse(mdp)}")
|
||||
|
||||
elif choix == "4":
|
||||
# Lister
|
||||
sites = gestionnaire.lister_sites()
|
||||
print("Sites enregistrés :")
|
||||
for s in sites:
|
||||
print(f" - {s}")
|
||||
|
||||
elif choix == "5":
|
||||
# Supprimer
|
||||
site = input("Site à supprimer : ")
|
||||
if gestionnaire.supprimer(site):
|
||||
print("Supprimé !")
|
||||
else:
|
||||
print("Site non trouvé.")
|
||||
|
||||
elif choix == "6":
|
||||
# Sauvegarder
|
||||
gestionnaire.sauvegarder("coffre.dat")
|
||||
print("Coffre sauvegardé.")
|
||||
|
||||
elif choix == "7":
|
||||
gestionnaire.sauvegarder("coffre.dat")
|
||||
print("Au revoir !")
|
||||
break
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 6 : Améliorations (Bonus)
|
||||
|
||||
### 6.1. Hashage du mot de passe maître
|
||||
|
||||
Au lieu de stocker le mot de passe maître directement, utiliser un hash :
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
|
||||
def hasher(mot_de_passe):
|
||||
"""Retourne le hash SHA-256 du mot de passe."""
|
||||
return hashlib.sha256(mot_de_passe.encode()).hexdigest()
|
||||
```
|
||||
|
||||
### 6.2. Dérivation de clé
|
||||
|
||||
Utiliser une fonction de dérivation de clé (PBKDF2) pour renforcer la sécurité.
|
||||
|
||||
### 6.3. Chiffrement AES
|
||||
|
||||
Remplacer XOR par AES pour un chiffrement professionnel (nécessite la bibliothèque `cryptography`).
|
||||
|
||||
---
|
||||
|
||||
## Questions de synthèse
|
||||
|
||||
1. Pourquoi ne faut-il **jamais** stocker un mot de passe en clair ?
|
||||
|
||||
2. Quelle est la différence entre **chiffrement** et **hashage** ?
|
||||
|
||||
3. Pourquoi le mot de passe maître doit-il être robuste ?
|
||||
|
||||
4. Quels sont les risques si quelqu'un obtient le fichier `coffre.dat` ?
|
||||
|
||||
5. Comment les vrais gestionnaires de mots de passe (Bitwarden, 1Password) améliorent-ils la sécurité ?
|
||||
|
||||
---
|
||||
|
||||
## Barème indicatif
|
||||
|
||||
| Partie | Points |
|
||||
|--------|--------|
|
||||
| Partie 1 : Chiffrement XOR | 3 |
|
||||
| Partie 2 : Classe MotDePasse | 2 |
|
||||
| Partie 3 : Gestionnaire | 5 |
|
||||
| Partie 4 : Génération | 4 |
|
||||
| Partie 5 : Interface | 4 |
|
||||
| Partie 6 : Bonus | 2 |
|
||||
| **Total** | **20** |
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
0
Sécurité/Untitled-1
Normal file
0
Sécurité/Untitled-1
Normal file
BIN
Sécurité/assets/TLS.jpeg
Normal file
BIN
Sécurité/assets/TLS.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
208
Sécurité/exemples/chiffrement_ECB.py
Executable file
208
Sécurité/exemples/chiffrement_ECB.py
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Jan 8 15:27:05 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
from numpy.random import permutation
|
||||
# Pour créer des permutations aléatoirement
|
||||
|
||||
class ECB:
|
||||
"""
|
||||
Classe dont les instances sont des cryptosystèmes dépendant de la donnée de leur clé
|
||||
sous la forme d'une permutation
|
||||
"""
|
||||
def __init__(self, taille = None, images = None):
|
||||
"""
|
||||
Un cryptosystème ECB est défini par la donnée d'une permutation
|
||||
Une permutation a pour attributs sa taille et la liste de ses images.
|
||||
Un des deux doit être donné au moment de l'instanciation.
|
||||
Une Permutation est si besoin créée aléatoirement en utilisant la fonction permutation
|
||||
du module numpy.random
|
||||
|
||||
>>> ECB(images = [1,0,2]).images
|
||||
[1, 0, 2]
|
||||
"""
|
||||
# si les images ne sont pas données, on les tire aléatoirement
|
||||
if images :
|
||||
liste_reference = [i for i in range(len(images))]
|
||||
images_ordonnees = images[:]
|
||||
images_ordonnees.sort()
|
||||
#print(f"liste_reference {liste_reference}-images_ordonnees {images_ordonnees}")
|
||||
if images_ordonnees==liste_reference:
|
||||
self.images = images
|
||||
else :
|
||||
self.images = list(permutation(range(taille)))
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
On représente les images de la permutation :
|
||||
|
||||
>>> ECB(images=[0, 3, 2, 4, 1])
|
||||
0 3 2 4 1
|
||||
"""
|
||||
return " ".join([str(image) for image in self.images])
|
||||
|
||||
def __invert__(self) :
|
||||
"""
|
||||
Permet d'obtenir la permutation réciproque de self avec ~
|
||||
|
||||
>>> mon_ecb = ECB(images = [1,3,0,2])
|
||||
>>> mon_ecb
|
||||
1 3 0 2
|
||||
>>> ~mon_ecb
|
||||
2 0 3 1
|
||||
"""
|
||||
ma_liste = []
|
||||
for i in range(len(self.images)):
|
||||
ma_liste.append(self.images.index(i))
|
||||
mon_ecb = ECB(images=ma_liste)
|
||||
return mon_ecb
|
||||
|
||||
@property
|
||||
def taille(self):
|
||||
"""
|
||||
>>> ECB(6).taille
|
||||
6
|
||||
"""
|
||||
# si la taille n'est pas donnée, c'est la longueur de la liste des images
|
||||
return len(self.images)
|
||||
|
||||
def permute(self, une_liste):
|
||||
"""
|
||||
Permute les éléments d'une liste donnée en argument
|
||||
Si xs = [xs[0], xs[1], xs[2],...] et si p est une permutation alors
|
||||
mon_ecb.permute(xs) = [xs[p(0)], xs[p(1)], xs[p(2)],...]
|
||||
|
||||
>>> mon_ecb = ECB(images=[0, 3, 2, 4, 1])
|
||||
>>> ma_liste = ['a', 'b', 'c', 'd', 'e']
|
||||
>>> mon_ecb.permute(ma_liste)
|
||||
['a', 'd', 'c', 'e', 'b']
|
||||
"""
|
||||
if len(une_liste)>=self.taille:
|
||||
return [une_liste[i] for i in self.images]
|
||||
|
||||
def chaine2texte(self, une_chaine):
|
||||
"""
|
||||
Prend une chaine de caractères uniquement composée de 0 et de 1
|
||||
Les cryptosystèmes manipulent des chaines de bits mais les humains veulent du texte
|
||||
Cette méthode permet de transformer une trame de caractères codés sur un octet
|
||||
en la chaîne de caractères correspondante.
|
||||
|
||||
>>> mon_ecb = ECB(images=[0, 3, 2, 4, 1])
|
||||
>>> mon_ecb.chaine2texte('11101001')
|
||||
'é'
|
||||
>>> mon_ecb.chaine2texte('111010011110100111101001')
|
||||
'ééé'
|
||||
|
||||
À comparer avec :
|
||||
|
||||
>>> chr(0b11101001)
|
||||
'é'
|
||||
"""
|
||||
ma_chaine = ''
|
||||
#car_a_completer = len(une_chaine)%8
|
||||
#if car_a_completer!=0:
|
||||
# une_chaine = '0'*(8-car_a_completer)+une_chaine
|
||||
for i in range(len(une_chaine)//8):
|
||||
ma_chaine += chr(int(une_chaine[8*i:8*(i+1)],2))
|
||||
return ma_chaine
|
||||
|
||||
def texte2chaine(self, une_chaine):
|
||||
"""
|
||||
On transforme une instance de Texte en la chaîne caractères uniquement composée de 0 et de 1.
|
||||
|
||||
>>> mon_ecb = ECB(images=[0, 3, 2, 4, 1])
|
||||
>>> mon_ecb.texte2chaine('ab')
|
||||
'0110000101100010'
|
||||
>>> mon_ecb.chaine2texte(mon_ecb.texte2chaine('azerty'))
|
||||
'azerty'
|
||||
"""
|
||||
while len(une_chaine)%len(self.images) != 0:
|
||||
une_chaine += ' '
|
||||
ma_chaine = ''
|
||||
for i in une_chaine :
|
||||
for j in "{:08b}".format(ord(i)):
|
||||
ma_chaine += j
|
||||
return ma_chaine
|
||||
|
||||
def decoupe_en_blocs(self, les_caracteres):
|
||||
"""
|
||||
Prend une chaîne de caractères et la transforme en chaînes de caractères de
|
||||
longueur celle de la permutation en complétant éventuellement par des '0'.
|
||||
Méthode à usage interne facilitant l'écriture de la fonction chiffre
|
||||
|
||||
>>> mon_ecb = ECB(images=[1,0,3,2])
|
||||
>>> mon_ecb.decoupe_en_blocs('123456789123456789')
|
||||
['12345', '67891', '23456', '78900']
|
||||
"""
|
||||
ma_liste = []
|
||||
car_a_completer = len(les_caracteres)%self.taille
|
||||
if car_a_completer!=0:
|
||||
les_caracteres = '0'*(self.taille-car_a_completer) + les_caracteres
|
||||
car_a_completer = len(les_caracteres)%8
|
||||
if car_a_completer!=0:
|
||||
les_caracteres = '0'*(8-car_a_completer) + les_caracteres
|
||||
nb_car_par_elem = len(les_caracteres)//self.taille
|
||||
for i in range(self.taille):
|
||||
ma_liste.append(les_caracteres[i*nb_car_par_elem:(i+1)*nb_car_par_elem])
|
||||
return ma_liste
|
||||
|
||||
def permute(self, les_caracteres):
|
||||
"""
|
||||
Renvoie la liste des permutations des blocs de longueur celle de la permutation
|
||||
construits à partir d'une chaîne de caracteres.
|
||||
|
||||
>>> mon_ecb = ECB(images=[1,0,3,2])
|
||||
>>> mon_ecb.permute('123456789123456789')
|
||||
'67891123457890023456'
|
||||
"""
|
||||
ma_liste_de_chaine = self.decoupe_en_blocs(les_caracteres)
|
||||
#print(f"{ma_liste_de_chaine} toto")
|
||||
ma_liste_de_chaine2 = []
|
||||
for indice in self.images :
|
||||
#print(f"{une_chaine}")
|
||||
#ma_chaine = Chaine(self.cle.permute(une_chaine.entiers))
|
||||
#print(f"{ma_chaine}")
|
||||
ma_liste_de_chaine2.append(ma_liste_de_chaine[indice])
|
||||
#print(f"{ma_liste_de_chaine} - {ma_liste_de_chaine2}")
|
||||
return "".join(ma_liste_de_chaine2)
|
||||
|
||||
def chiffre(self, message):
|
||||
"""
|
||||
Retourne le message chiffré sous forme de chaîne de caracères.
|
||||
Utilise les sous-méthodes précédentes.
|
||||
|
||||
>>> mon_ecb = ECB(images=[0, 1, 3, 4, 2])
|
||||
>>> chaine_0_1 = mon_ecb.texte2chaine('hello world')
|
||||
>>> chaine_0_1_code = mon_ecb.permute(chaine_0_1)
|
||||
>>> message_code = mon_ecb.chaine2texte(chaine_0_1_code)
|
||||
|
||||
"""
|
||||
chaine_0_1 = mon_ecb.texte2chaine(message)
|
||||
#print(f"{chaine_0_1}")
|
||||
chaine_0_1_code = mon_ecb.permute(chaine_0_1)
|
||||
#print(f"{chaine_0_1_code}")
|
||||
return mon_ecb.chaine2texte(chaine_0_1_code)
|
||||
|
||||
def dechiffre(self, message_code):
|
||||
ecb_inverse = ~self
|
||||
chaine_0_1 = ecb_inverse.texte2chaine(message_code)
|
||||
print(f"0 : {chaine_0_1}")
|
||||
chaine_0_1_code = ecb_inverse.permute(chaine_0_1)
|
||||
print(f"1 : {chaine_0_1_code}")
|
||||
|
||||
return ecb_inverse.chaine2texte(chaine_0_1_code)
|
||||
|
||||
|
||||
#mon_ecb = ECB(6)
|
||||
#print(mon_ecb)
|
||||
#print(mon_ecb.taille)
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
mon_ecb = ECB(25)
|
||||
toto = mon_ecb.chiffre("Et si quelquefois, sur les marches d'un palais, sur l'herbe verte d'un fossé, vous vous réveillez, l'ivresse déjà diminuée ou disparue, demandez au vent, à la vague, à l'étoile, à l'oiseau, à l'horloge; à tout ce qui fuit, à tout ce qui gémit, à tout ce qui roule, à tout ce qui chante, à tout ce qui parle, demandez quelle heure il est. Et le vent, la vague, l'étoile, l'oiseau, l'horloge, vous répondront, il est l'heure de s'enivrer ; pour ne pas être les esclaves martyrisés du temps, enivrez-vous, enivrez-vous sans cesse de vin, de poésie, de vertu, à votre guise")
|
||||
print(toto)
|
||||
titi = mon_ecb.dechiffre(toto)
|
||||
print(titi)
|
||||
67
Sécurité/exemples/chiffrement_rsa.py
Executable file
67
Sécurité/exemples/chiffrement_rsa.py
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Feb 3 12:41:14 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
CLE_PRIV_P = 53
|
||||
CLE_PRIV_Q = 97
|
||||
CLE_PUB_E = 7
|
||||
CLE_PUB_N = CLE_PRIV_P * CLE_PRIV_Q
|
||||
|
||||
|
||||
def conversion_message_en_nombre(chaine, bloc=3):
|
||||
nombre = ""
|
||||
for i in chaine :
|
||||
nombre += str(ord(i)-ord('A')+1)
|
||||
#print(nombre)
|
||||
while len(nombre)%bloc != 0 :
|
||||
nombre = '0' + nombre
|
||||
return nombre
|
||||
|
||||
def chiffrement(chaine_num, bloc=3, e=CLE_PUB_E, n=CLE_PUB_N):
|
||||
code = ""
|
||||
for i in range(len(chaine_num)//bloc):
|
||||
morceau_chaine_num = chaine_num[i*bloc:(i+1)*bloc]
|
||||
#print(morceau_chaine_num)
|
||||
morceau_chaine_num = int(morceau_chaine_num)
|
||||
morceau_chaine_num = morceau_chaine_num**e
|
||||
morceau_chaine_num = morceau_chaine_num%n
|
||||
morceau_chaine_num = str(morceau_chaine_num)
|
||||
code += morceau_chaine_num
|
||||
code += ' '
|
||||
return code[:-1]
|
||||
|
||||
def dechiffrement(chaine_num, bloc=2, e=CLE_PUB_E, n=CLE_PUB_N, p=CLE_PRIV_P, q=CLE_PRIV_Q):
|
||||
nombre = 1
|
||||
while nombre%e != 0 :
|
||||
nombre += (p-1)*(q-1)
|
||||
print(nombre)
|
||||
d = nombre//e
|
||||
liste_num = chaine_num.split(' ')
|
||||
print(liste_num)
|
||||
liste_decod = []
|
||||
for i in liste_num :
|
||||
decode = (int(i)**d) % n
|
||||
liste_decod.append(str(decode))
|
||||
print(liste_decod)
|
||||
chaine_decode = ''.join(liste_decod)
|
||||
print(chaine_decode)
|
||||
message = ""
|
||||
a_completer = len(chaine_decode)%bloc
|
||||
for i in range(a_completer):
|
||||
chaine_decode = '0' + chaine_decode
|
||||
for i in range(len(chaine_decode)//bloc):
|
||||
morceau_chaine_num = int(chaine_decode[i*bloc:(i+1)*bloc])
|
||||
message += chr(morceau_chaine_num+ord('A')-1)
|
||||
print(morceau_chaine_num, ' ',message)
|
||||
return message
|
||||
|
||||
ma_chaine_num = conversion_message_en_nombre('BONJOUR')
|
||||
print(ma_chaine_num)
|
||||
mon_code = chiffrement(ma_chaine_num)
|
||||
print(mon_code)
|
||||
mon_message = dechiffrement(mon_code)
|
||||
print('message : ', mon_message)
|
||||
114
Sécurité/exemples/chiffrement_rsa2.py
Executable file
114
Sécurité/exemples/chiffrement_rsa2.py
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Feb 3 12:41:14 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
BLOC_ASCII = 2
|
||||
CLE_PRIV_P = 53
|
||||
CLE_PRIV_Q = 97
|
||||
CLE_PUB_E = 11
|
||||
CLE_PUB_N = CLE_PRIV_P * CLE_PRIV_Q
|
||||
|
||||
|
||||
def car_to_fig(chaine : str) -> str:
|
||||
"""
|
||||
Transforme une chaine de caractères en une chaine de caractères
|
||||
correspondant à leurs numéros d' ordre.
|
||||
Attention ! Chaque numéro d' ordre est codé sur BLOC_ASCII chiffres
|
||||
Arguments : chaine, chaine à coder de type str
|
||||
Retourne : nombre, une chaine de caractères avec tous les numéros d' ordre
|
||||
>>> car_to_fig('A')
|
||||
'01'
|
||||
>>> car_to_fig('ABZ')
|
||||
'010226'
|
||||
"""
|
||||
nombre = ""
|
||||
liste = []
|
||||
for i in chaine :
|
||||
ordre = str(ord(i)-ord('A')+1)
|
||||
while len(ordre)%BLOC_ASCII != 0:
|
||||
ordre = '0'+ordre
|
||||
liste.append(ordre)
|
||||
#print(liste)
|
||||
nombre = "".join(liste)
|
||||
return nombre
|
||||
|
||||
def chiffrement(chaine, bloc=3, e=CLE_PUB_E, n=CLE_PUB_N):
|
||||
"""
|
||||
Transforme une chaine de caractères en une chaine de caractères
|
||||
correspondant à leurs numéros d' ordre codés.
|
||||
Chaque numéro est séparé par un espace
|
||||
Arguments : chaine, chaine à coder de type str
|
||||
Retourne : nombre, une chaine de caractères avec les numéros codés
|
||||
>>> chiffrement('A')
|
||||
'1689'
|
||||
>>> chiffrement('ABZ')
|
||||
'755 2705'
|
||||
"""
|
||||
chaine_num = car_to_fig(chaine)
|
||||
while len(chaine_num)%bloc != 0 :
|
||||
chaine_num = '0'+chaine_num
|
||||
print("code du message initial :\n",chaine_num)
|
||||
liste = []
|
||||
for i in range(len(chaine_num)//bloc):
|
||||
morceau_chaine_num = chaine_num[i*bloc:(i+1)*bloc]
|
||||
morceau_chaine_num = int(morceau_chaine_num)
|
||||
morceau_chaine_num = morceau_chaine_num**e
|
||||
morceau_chaine_num = morceau_chaine_num%n
|
||||
liste.append(str(morceau_chaine_num))
|
||||
code = " ".join(liste)
|
||||
print("code du message chiffre :\n", code)
|
||||
return code
|
||||
|
||||
def dechiffrement(chaine_num, bloc=3, e=CLE_PUB_E, n=CLE_PUB_N, p=CLE_PRIV_P, q=CLE_PRIV_Q):
|
||||
"""
|
||||
Transforme une chaine de caractères correspondant à leurs numéros d' ordre
|
||||
codés en message décodé.
|
||||
Arguments : chaine_num, chaine de codes de type str
|
||||
Retourne : message, une chaine de caractères avec le message décodé
|
||||
>>> dechiffrement(chiffrement('A'))
|
||||
'A'
|
||||
>>> dechiffrement(chiffrement('ABZ'))
|
||||
'ABZ'
|
||||
"""
|
||||
nombre = 1
|
||||
# PARTIE LA PLUS DIFFICILE
|
||||
# Il faut déterminer e tel que e.d = 1 mod [(p-1)(q-1)]
|
||||
# Mon astuce : On incrémente de (p-1)(q-1) jusqu' à obtenir un nombre
|
||||
# divisible par e
|
||||
while nombre%e != 0 :
|
||||
nombre += (p-1)*(q-1)
|
||||
d = nombre//e
|
||||
liste_num = chaine_num.split(' ')
|
||||
liste_decod = []
|
||||
for i in liste_num :
|
||||
decode = (int(i)**d) % n
|
||||
decode = str(decode)
|
||||
while len(decode)%bloc != 0:
|
||||
decode = '0'+decode
|
||||
liste_decod.append(decode)
|
||||
chaine_decode = ''.join(liste_decod)
|
||||
message = ""
|
||||
while len(chaine_decode)%BLOC_ASCII != 0:
|
||||
chaine_decode = '0' + chaine_decode
|
||||
print("code du message dechiffre : \n",chaine_decode)
|
||||
for i in range(len(chaine_decode)//BLOC_ASCII, 0, -1):
|
||||
morceau_chaine_num = chaine_decode[(i-1)*BLOC_ASCII:i*BLOC_ASCII]
|
||||
morceau_chaine_num = int(morceau_chaine_num)
|
||||
if morceau_chaine_num != 0:
|
||||
message = chr(morceau_chaine_num+ord('A')-1) + message
|
||||
print("Message dechiffre :\n", message)
|
||||
return message
|
||||
|
||||
if __name__=='__main__':
|
||||
if (CLE_PRIV_P-1)*(CLE_PRIV_Q-1)%CLE_PUB_E == 0:
|
||||
raise Exception("e n' est pas premier avec (p-1)(q-1)")
|
||||
chaine_depart = 'ABONJOURLESFRANCAISESETLESFRANCAIS'
|
||||
print("chaine de depart : ",chaine_depart)
|
||||
mon_code = chiffrement(chaine_depart, bloc=4)
|
||||
#print("code : ", mon_code)
|
||||
mon_message = dechiffrement(mon_code, bloc=4)
|
||||
print('message : ', mon_message)
|
||||
36
Sécurité/exemples/codage_binaire.py
Executable file
36
Sécurité/exemples/codage_binaire.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Feb 3 10:55:48 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
def codage_binaire(message : str, code : str) -> str:
|
||||
"""
|
||||
Fonction qui code un message à l' aide d' une clé. Le message codé resulte
|
||||
d' un OU exclusif bit à bit
|
||||
Argument :
|
||||
- message : Message à coder de type str
|
||||
- code : Clé de codage de type str
|
||||
Retourne :
|
||||
- res : Message codé bit à bit
|
||||
>>> codage_binaire(codage_binaire("Hello World!", "toto"), "toto")
|
||||
'Hello World!'
|
||||
"""
|
||||
i = 0
|
||||
res = ''
|
||||
for car in message :
|
||||
ord_car = ord(car)^ord(code[i%len(code)])
|
||||
#print(f"car : {ord(car):08b}\ncode : {ord(code[i%len(code)]):08b}\n => {ord_car:08b} \n")
|
||||
res += chr(ord_car)
|
||||
i += 1
|
||||
return res
|
||||
|
||||
#CORPS DE PROGRAMME
|
||||
if __name__=='__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
#message_code = codage_binaire('Hello World', 'toto')
|
||||
#input("Tapez Entree pour continuer")
|
||||
#message_decode = codage_binaire(message_code, 'toto')
|
||||
84
Sécurité/exemples/code_cesar.py
Executable file
84
Sécurité/exemples/code_cesar.py
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Jan 7 20:03:19 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
def code_cesar(texte, decalage):
|
||||
"""
|
||||
Fonction qui code un texte suivant la méthode de césar (chaque lettre est
|
||||
décalé).
|
||||
Arguments ::
|
||||
- texte : message à coder de type str
|
||||
- decalage : indice de décalage de type int
|
||||
Renvoie ::
|
||||
- texte_chiffre : le message codé de type str
|
||||
>>> code_cesar("VENI, VIDI, DICI", 3)
|
||||
YHQL, YLGL, GLFL
|
||||
"""
|
||||
texte_chiffre = ""
|
||||
for lettre in texte :
|
||||
if lettre in ('A','B','C','D','E','F','G','H','I','J','K','L','M','N',
|
||||
'O','P','Q','R','S','T','U','V','W','X','Y','Z'):
|
||||
ordre_dans_alphabet = ord(lettre)+decalage-ord('A')
|
||||
texte_chiffre += chr(ordre_dans_alphabet%26+ord('A'))
|
||||
else:
|
||||
texte_chiffre += lettre
|
||||
return texte_chiffre
|
||||
|
||||
def code_cesar2(texte, decalage):
|
||||
"""
|
||||
Fonction qui code un texte suivant la méthode de césar (chaque lettre est
|
||||
décalé).
|
||||
Variante proposée par C. Veillon
|
||||
Arguments ::
|
||||
- texte : message à coder de type str
|
||||
- decalage : indice de décalage de type int
|
||||
Renvoie ::
|
||||
- texte_chiffre : le message codé de type str
|
||||
>>> code_cesar("VENI, VIDI, DICI", 3)
|
||||
YHQL, YLGL, GLFL
|
||||
"""
|
||||
texte_chiffre = ""
|
||||
liste_avec_lettres = []
|
||||
for i in range(65, 91):
|
||||
liste_avec_lettres.append(chr(i))
|
||||
#print(liste_avec_lettres)
|
||||
for lettre in texte :
|
||||
if lettre in liste_avec_lettres:
|
||||
for i in range(len(liste_avec_lettres)):
|
||||
if lettre == liste_avec_lettres[i]:
|
||||
texte_chiffre += liste_avec_lettres[(i+decalage)%26]
|
||||
else :
|
||||
texte_chiffre += lettre
|
||||
return texte_chiffre
|
||||
|
||||
def decode_cesar(texte, decalage):
|
||||
"""
|
||||
Fonction qui décode un texte suivant la méthode de césar.
|
||||
Arguments ::
|
||||
- texte : message codé de type str
|
||||
- decalage : indice de décalage de type int
|
||||
Renvoie ::
|
||||
- le message décodé de type str
|
||||
>>> code_cesar("YHQL, YLGL, GLFL", 3)
|
||||
VENI, VIDI, DICI
|
||||
"""
|
||||
return code_cesar(texte, -decalage)
|
||||
|
||||
if __name__ == '__main__':
|
||||
#ACTION DE CODAGE
|
||||
toto=code_cesar('VENI, VIDI, DICI',3)
|
||||
print("message codé : ", toto)
|
||||
#ACTION DE DECODAGE
|
||||
toto=decode_cesar(toto,3)
|
||||
print("message décodé : ", toto)
|
||||
|
||||
#ACTION DE CODAGE
|
||||
toto=code_cesar2('VENI, VIDI, DICI',3)
|
||||
print("message codé (méthode C. Veillon) : ", toto)
|
||||
#ACTION DE DECODAGE
|
||||
toto=code_cesar2(toto,-3)
|
||||
print("message décodé (méthode C. Veillon) : ", toto)
|
||||
38
Sécurité/exemples/code_inverse.py
Executable file
38
Sécurité/exemples/code_inverse.py
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Jan 7 20:03:19 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
def codage_inverse(texte):
|
||||
"""
|
||||
Fonction qui code un texte suivant la méthode de codage inverse
|
||||
(A <=> Z, B <=> Y, C <=> X, ...).
|
||||
Arguments ::
|
||||
- texte : message à coder de type str
|
||||
Renvoie ::
|
||||
- texte_chiffre : le message codé de type str
|
||||
>>> codage_inverse('VENI, VIDI, DICI')
|
||||
FWNS, FSXS, XSYS
|
||||
>>> codage_inverse(codage_inverse('VENI, VIDI, DICI'))
|
||||
VENI, VIDI, DICI
|
||||
"""
|
||||
texte_chiffre = ""
|
||||
for lettre in texte :
|
||||
if lettre in ('A','B','C','D','E','F','G','H','I','J','K','L','M','N',
|
||||
'O','P','Q','R','S','T','U','V','W','X','Y','Z'):
|
||||
ordre_dans_alphabet = 26-ord(lettre)-ord('A')
|
||||
texte_chiffre += chr(ordre_dans_alphabet%26+ord('A'))
|
||||
else:
|
||||
texte_chiffre += lettre
|
||||
return texte_chiffre
|
||||
|
||||
if __name__ == '__main__':
|
||||
#ACTION DE CODAGE
|
||||
toto=codage_inverse('VENI, VIDI, DICI')
|
||||
print(toto)
|
||||
#ACTION DE CODAGE
|
||||
toto=codage_inverse(toto)
|
||||
print(toto)
|
||||
89
Sécurité/exemples/code_par_substitution.py
Executable file
89
Sécurité/exemples/code_par_substitution.py
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Jan 7 20:03:19 2021
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
from random import randint
|
||||
|
||||
def genere_table():
|
||||
"""
|
||||
Fonction qui génère aléatoirement une table de correspondance entre lettres
|
||||
Les clés correspondent à chaque lettre de l' alphabet et les valeurs à une
|
||||
autre lettre prise au hasard.
|
||||
Arguments :
|
||||
- Aucun
|
||||
Retourne :
|
||||
- dico_chiffrement de type dict
|
||||
>>> toto = list(genere_table().keys())
|
||||
>>> toto.sort()
|
||||
>>> print(toto)
|
||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
||||
>>> toto = list(genere_table().values())
|
||||
>>> toto.sort()
|
||||
>>> print(toto)
|
||||
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
||||
"""
|
||||
dico_chiffrement = {}
|
||||
toutes_les_lettres = ('A','B','C','D','E','F','G','H','I','J','K','L','M','N',
|
||||
'O','P','Q','R','S','T','U','V','W','X','Y','Z')
|
||||
liste_lettres = list(toutes_les_lettres)
|
||||
for lettre in toutes_les_lettres:
|
||||
position = randint(0, len(liste_lettres)-1)
|
||||
lettre_correspondante = liste_lettres[position]
|
||||
dico_chiffrement[lettre] = lettre_correspondante
|
||||
liste_lettres.remove(lettre_correspondante)
|
||||
return dico_chiffrement
|
||||
|
||||
|
||||
def code_par_substitution(texte, table):
|
||||
"""
|
||||
Fonction qui code un message grâce à une table de correspondance.
|
||||
Arguments :
|
||||
- texte : Message à coder de type str
|
||||
- table : Table de correspondance de type dict
|
||||
Retourne :
|
||||
- texte_chiffre : Message codé de type str
|
||||
>>> ma_table = {'A': 'H', 'B': 'A', 'C': 'F', 'D': 'M', 'E': 'D', 'F': 'T',\
|
||||
'G': 'Z', 'H': 'W', 'I': 'L', 'J': 'X', 'K': 'G', 'L': 'S', 'M': 'I',\
|
||||
'N': 'V', 'O': 'R', 'P': 'C', 'Q': 'O', 'R': 'E', 'S': 'N', 'T': 'Y',\
|
||||
'U': 'U', 'V': 'K', 'W': 'B', 'X': 'J', 'Y': 'Q', 'Z': 'P'}
|
||||
>>> code_par_substitution("BONJOUR TOUT LE MONDE", ma_table)
|
||||
'ARVXRUE YRUY SD IRVMD'
|
||||
"""
|
||||
texte_chiffre = ""
|
||||
for lettre in texte :
|
||||
if lettre in ('A','B','C','D','E','F','G','H','I','J','K','L','M','N',
|
||||
'O','P','Q','R','S','T','U','V','W','X','Y','Z'):
|
||||
texte_chiffre += table[lettre]
|
||||
else:
|
||||
texte_chiffre += lettre
|
||||
return texte_chiffre
|
||||
|
||||
def decode_par_substitution(texte, table):
|
||||
"""
|
||||
Fonction qui décode un message grâce à une table de correspondance.
|
||||
Arguments :
|
||||
- texte : Message codé de type str
|
||||
- table : Table de correspondance de type dict
|
||||
Retourne :
|
||||
- texte_chiffre : Message décodé de type str
|
||||
>>> ma_table = genere_table()
|
||||
>>> decode_par_substitution(code_par_substitution("BONJOUR TOUT LE MONDE", ma_table), ma_table)
|
||||
'BONJOUR TOUT LE MONDE'
|
||||
"""
|
||||
nouvelle_table = {}
|
||||
for cle, valeur in table.items():
|
||||
nouvelle_table[valeur]=cle
|
||||
return code_par_substitution(texte, nouvelle_table)
|
||||
|
||||
if __name__=='__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
#ma_table_chiffrement = genere_table()
|
||||
#print(ma_table_chiffrement)
|
||||
#message_code = code_par_substitution("BONJOUR TOUT LE MONDE", ma_table_chiffrement)
|
||||
#print(message_code)
|
||||
#message_decode = decode_par_substitution(message_code, ma_table_chiffrement)
|
||||
#print(message_decode)
|
||||
115
Sécurité/exemples/substitution_polyalphabetique.py
Executable file
115
Sécurité/exemples/substitution_polyalphabetique.py
Executable file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Wed Feb 16 12:30:05 2022
|
||||
|
||||
@author: pjoulaud
|
||||
"""
|
||||
|
||||
PREM_CARAC = ord('A') - 1
|
||||
DER_CARAC = ord('Z')
|
||||
#PREM_CARAC = 32
|
||||
#DER_CARAC = 126
|
||||
#PREM_CARAC = 0x21
|
||||
#DER_CARAC = 0x1f0df
|
||||
MODULO = DER_CARAC - PREM_CARAC
|
||||
|
||||
def codage_cle_chiffrement(chaine_a_coder, cle):
|
||||
"""
|
||||
Fonction de codage par substitution polyalphabetique
|
||||
Arguments :
|
||||
- chaine_a_coder : Message à coder de type str
|
||||
- cle : clé de chiffrement de type str
|
||||
Retourne :
|
||||
- chaine_chiffree : Message codé de type str
|
||||
>>> codage_cle_chiffrement("JE TIENS ENFIN LA GAULE", "SCIENCE")
|
||||
'CH CNSQX XQONB OF ZDDQS'
|
||||
"""
|
||||
chaine_chiffree = ""
|
||||
i = 0
|
||||
for car in chaine_a_coder :
|
||||
if car != " ":
|
||||
ord_car = ord(car) - PREM_CARAC
|
||||
ord_cle = ord(cle[i%len(cle)]) - PREM_CARAC
|
||||
sum_ord = ord_car + ord_cle
|
||||
#print(f"car : {car} - ord_car : {ord_car} - ord_cle : {ord_cle} - sum_ord : {sum_ord} - ")
|
||||
if sum_ord <= MODULO :
|
||||
car2 = chr(PREM_CARAC + sum_ord)
|
||||
else :
|
||||
car2 = chr(PREM_CARAC + sum_ord%MODULO)
|
||||
i += 1
|
||||
else :
|
||||
car2 = car
|
||||
chaine_chiffree += car2
|
||||
return chaine_chiffree
|
||||
|
||||
def car_to_num(c):
|
||||
return ord(c) - PREM_CARAC
|
||||
|
||||
def num_to_car(n):
|
||||
if n <= MODULO :
|
||||
return chr(PREM_CARAC + n)
|
||||
else :
|
||||
return chr(PREM_CARAC + n%MODULO)
|
||||
|
||||
def codage_cle_chiffrement2(chaine_a_coder, cle):
|
||||
"""
|
||||
Fonction de codage par substitution polyalphabetique - 2e version
|
||||
Passe par deux fonctions (car_to_num et num_to_car) pour convertir
|
||||
de caractères vers valeur numérique et vice-versa.
|
||||
Arguments :
|
||||
- chaine_a_coder : Message à coder de type str
|
||||
- cle : clé de chiffrement de type str
|
||||
Retourne :
|
||||
- chaine_chiffree : Message codé de type str
|
||||
>>> codage_cle_chiffrement2("JE TIENS ENFIN LA GAULE", "SCIENCE")
|
||||
'CH CNSQX XQONB OF ZDDQS'
|
||||
"""
|
||||
chaine_chiffree = ""
|
||||
i = 0
|
||||
for car in chaine_a_coder :
|
||||
if car != " ":
|
||||
ord_car = car_to_num(car)
|
||||
ord_cle = car_to_num(cle[i%len(cle)])
|
||||
sum_ord = ord_car + ord_cle
|
||||
#print(f"car : {car} - ord_car : {ord_car} - ord_cle : {ord_cle} - sum_ord : {sum_ord} - ")
|
||||
car2 = num_to_car(sum_ord)
|
||||
i += 1
|
||||
else :
|
||||
car2 = car
|
||||
chaine_chiffree += car2
|
||||
return chaine_chiffree
|
||||
|
||||
def decodage_cle_chiffrement(chaine_codee, cle):
|
||||
"""
|
||||
Fonction de décodage par substitution polyalphabetique
|
||||
Arguments :
|
||||
- chaine_codee : Message codé de type str
|
||||
- cle : clé de chiffrement de type str
|
||||
Retourne :
|
||||
- chaine_clair : Message décodé de type str
|
||||
>>> decodage_cle_chiffrement(codage_cle_chiffrement("JE TIENS ENFIN LA GAULE", "SCIENCE"), "SCIENCE")
|
||||
'JE TIENS ENFIN LA GAULE'
|
||||
"""
|
||||
chaine_clair = ""
|
||||
i = 0
|
||||
for car in chaine_codee :
|
||||
if car != " ":
|
||||
ord_car = ord(car) - PREM_CARAC
|
||||
ord_cle = ord(cle[i%len(cle)]) - PREM_CARAC
|
||||
sum_ord = ord_car - ord_cle + MODULO
|
||||
#print(f"car : {car} - ord_car : {ord_car} - ord_cle : {ord_cle} - sum_ord : {sum_ord} - ")
|
||||
if sum_ord <= MODULO :
|
||||
car2 = chr(PREM_CARAC + sum_ord)
|
||||
else :
|
||||
car2 = chr(PREM_CARAC + sum_ord%MODULO)
|
||||
i += 1
|
||||
else :
|
||||
car2 = car
|
||||
chaine_clair += car2
|
||||
return chaine_clair
|
||||
|
||||
#CORPS DE PROGRAMME
|
||||
if __name__=='__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
4
Sécurité/rotXcrypte.txt
Normal file
4
Sécurité/rotXcrypte.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
ȹɜȐɕɣɤȐɤɟɥɚɟɥɢɣȐɑɣɣɕɪȐɔ˙ɜəɓɑɤȐɔɕȐɦɟɥɜɟəɢȐɥɤəɜəɣɕɢȐɥɞɕȐɑɤɤɑɡɥɕȐɣɤɑɤəɣɤəɡɥɕȐːȐɜȗɑəɔɕȐɔȗɥɞȐɤɕɨɤɕȐɤɢɟɠȐɠɕɤəɤȞ
|
||||
ȽɑəɣȐɓɕɤȐɕɨɕɢɓəɓɕȐɞɕȐɣȗɑɔɢɕɣɣɕȐɠɑɣȐːȐɞȗəɝɠɟɢɤɕȐɡɥəȐȑȐȾɟɞȜȐɣəȐɦɟɥɣȐɓɘɕɢɓɘɕɪȐɓɕɤȐɕɨɕɢɓəɓɕȜȐɓȗɕɣɤȐɡɥɕȐɦɟɥɣȐɖɑəɤɕɣȐɠɑɢɤəɕȐɔɕȐɜȗ˙ɜəɤɕȞȐȿɥəȜȐɞɟɥɣȐɟɣɟɞɣȐɜɕȐɔəɢɕȐȪȐɦɟɥɣȐ˚ɤɕɣȐɜȗɕɣɠɟəɢȐɔɕȐɜȗɘɥɝɑɞəɤ˙ȐȑȐɆɟɥɣȐɑɦɕɪȐɓɘɟəɣəȐɔɕȐɠɟɥɢɣɥəɦɢɕȐɜȗ˙ɤɥɔɕȐɔɕȐɜȗəɞɖɟɢɝɑɤəɡɥɕȐɕɞȐɄɕɢɝəɞɑɜɕȞȐɁɥɕɜȐɞɟɒɜɕȐɓɘɟəɨȐȑȐȽɑəɞɤɕɞɑɞɤȐɚɕȐɔɟəɣȐ˙ɓɢəɢɕȐɥɞȐɠɕɥȐɓɕȐɡɥəȐɝɕȐɦəɕɞɣȐɠɑɢȐɜɑȐɤ˚ɤɕȐɠɟɥɢȐɢɕɝɠɜəɢȐɥɞȐɠɕɥȞȐɆɟɥɣȐɠɕɞɣəɕɪȐɣ˫ɢɕɝɕɞɤȐɤɢɟɥɦɕɢȐɥɞȐɤɕɨɤɕȐɠɜɥɣȐəɞɤ˙ɢɕɣɣɑɞɤȐːȐɜəɢɕȞȐ
|
||||
ȺɕȐɜɕȐɔ˙ɠɜɟɢɕȐɑɥɤɑɞɤȐɡɥɕȐɦɟɥɣȞȐȺɕȐɞȗɑəɝɕȐɠɑɣȐɠɑɢɜɕɢȐɠɟɥɢȐɞɕȐɢəɕɞȐɔəɢɕȞȐȿɞȐɠɟɥɢɢɑəɤȐɣɕȐɔəɢɕȐȪȐ˗ɑȐɩȐɕɣɤȐȑȐȹɜȐɑȐɕɞɖəɞȐɑɣɣɕɪȐ˙ɓɢəɤȐɓɟɝɝɕȐ˗ɑȞȐȹɜȐɦɑȐɤɢɟɥɦɕɢȐɜɕȐɤɕɝɠɣȐɜɟɞɗȞ
|
||||
ȽɑəɣȐɞɟɞȞȐȹɜȐɖɑəɤȐɠɟɥɢɤɑɞɤȐɒɕɑɥȐɔɕɘɟɢɣȐɕɞȐɓɕɤɤɕȐɠ˙ɢəɟɔɕȐɔɕȐɓɟɞɖəɞɕɝɕɞɤȞȐȽɑəɣȐɚɥɣɤɕɝɕɞɤȞȐɀɟɥɢɡɥɟəȐɦɟɥɜɟəɢȐɣɟɢɤəɢȞȐȴȗɑəɜɜɕɥɢɣȐɓȗɕɣɤȐəɝɠɟɣɣəɒɜɕȞȐȲɟɞȜȐɠɟɥɢȐɕɞȐɢɕɦɕɞəɢȐːȐɞɟɤɢɕȐɠɢɟɒɜ˘ɝɕȜȐəɜȐɞɕȐɖɑɥɤȐɠɑɣȐɞɟɞȐɠɜɥɣȐɣȗɑɤɤɕɞɔɢɕȐːȐɢɕɓɕɦɟəɢȐɔɕȐɜɟɞɗɣȐɝɕɣɣɑɗɕɣȐɔɟɞɓȐəɜȐɖɑɥɤȐɒəɕɞȐɤɢɟɥɦɕɢȐɥɞȐɝɟɩɕɞȐɠɟɥɢȐɑɖɖəɞɕɢȐɜȗɑɤɤɑɡɥɕȞȐȾȗɟɥɒɜəɟɞɣȐɠɑɣȐɡɥȗəɜȐɣȗɑɗəɤȐɔȗɥɞȐɓɘəɖɖɢɕɝɕɞɤȐːȐɔ˙ɓɑɜɑɗɕȞ
|
||||
9
Sécurité/test.py
Normal file
9
Sécurité/test.py
Normal file
@@ -0,0 +1,9 @@
|
||||
def rot47(clair: str) -> str:
|
||||
chif =""
|
||||
dec = 33
|
||||
amp = 127 - dec
|
||||
for car in clair:
|
||||
new_code = dec + ((ord( car) - dec + 47) % amp)
|
||||
chif += chr(new_code) if 33 <= ord(car) <= 126 else car
|
||||
return chif
|
||||
|
||||
Reference in New Issue
Block a user