Coffre fort
Professeur référent :
M FAURY (ISN)
Coffre fort
Ardechiri Fanny, Guignon Romain, Jaccaud Yann
Année scolaire 2017/2018 – Classe de TS5
Crypter une clé privée bitcoin pour la récupérer en cas d’oublie ou de perte. Il faut faire un formulaire dans lequel la personne indique les informations personnelles (date de naissance…) qui permet de générer un hash. Si le hash est le même que celui généré quand il a démarré le programme pour la première fois, cela envoie la clé privée à la personne par mail.
Compétences requises : chiffrement / hashage / structure et présentation
Dimension algorithmique : Organisation d’un programme alliant chiffrement et hashage pour récupérer un mot de passe
Éléments de programmation : htlm et python
Utilisation des réseaux : Compte Bitcoin (accès depuis n’importe quel ordinateur)
Intégration de la robotique : autonomie du programme à générer un hash et traiter les données de l’utilisateur à partir de l’information « mot de passe perdu »
Architecture des ordinateurs : non
Représentation de l’information : l’information apparaît aux yeux de l’utilisateur comme son mot de passe pour récupérer sa clé privée ; en revanche elle apparaît dans le programme sous forme de données chiffrées ainsi que d’un hash
Droits et responsabilité : confidentialité
Contraintes pour la mise en place de ce projet : apprentissage de différents langages (htlm, python…) et de techniques de hashage et de chiffrement
Objectif : permettre à tout possesseur d’un compte Bitcoin de récupérer sa clé privée en cas de perte ou d’oubli de son mot de passe. Ainsi, l’utilisateur ne perd pas son argent en cas de problème.
import socket import ast from Crypto.Hash import SHA512 import os import mysql.connector import binascii import smtplib from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socket.bind(('', 15555)) def send_mail(mail, password): #Fonction d'envoie d'un mail msg = MIMEMultipart() msg['From'] = 'Service de recuperation de Coffre-Fort' msg['To'] = '%s' % mail msg['Subject'] = 'Mot de passe de recuperation' message = 'Hello,\nVotre mot de passe de recuperation : %s' % password msg.attach(MIMEText(message)) mailserver = smtplib.SMTP('smtp.gmail.com', 587) mailserver.ehlo() mailserver.starttls() mailserver.ehlo() mailserver.login('recoveryvaultisn@gmail.com', 'eN4md/c3+d@y&1uaRi6mpU$BuHn?b7cmIF#to54f') #login, password mailserver.sendmail('recoveryvaultisn@gmail.com', '%s' % mail, msg.as_string()) mailserver.quit() def config_recovery_pwd(mail, favorite_music, favorite_movie, recovery_password): #Fonction de configuration de la recuperation de mot de passe initialPersonalData = mail + favorite_music + favorite_movie #On reunit les informations personnelles de l'utilisateur initialHash = SHA512.new(initialPersonalData.encode()).hexdigest() data = (mail, recovery_password, initialHash) try: cursor.execute("""INSERT INTO data (mail, password, hash) VALUES(%s, %s, %s)""", data) #On entre les donnees dans la base de donnees conn.commit() client.sendall("\nCoffre-fort de recuperation cree avec succes.\n") #On envoie une information au client except: client.sendall("\nCoffre-fort de recuperation deja cree.\n") conn.rollback() finally: conn.close() def recovery_pwd(mail, favorite_music, favorite_movie): #Fonction de recuperation de mot de passe inputPersonalData = mail + favorite_music + favorite_movie inputHash = SHA512.new(inputPersonalData.encode()).hexdigest() initialHash = 0 #On initialise la variable initialHash cursor.execute("""SELECT hash FROM data WHERE mail = %s""", (mail,)) #On lit le hash de l'utilisateur a partir de son mail j = cursor.fetchall() for i in j: initialHash = i[0] #On lit le hash initial if initialHash == inputHash: #On compare les deux hash cursor.execute("""SELECT password FROM data WHERE hash = %s""", (inputHash,)) #On recupere le mot de passe de l'utilisateur j = cursor.fetchall() for i in j: password = i[0] send_mail(mail, password)#On envoie un mail a l'utilisateur client.sendall("\nNous vous avons envoye un mail contenant votre mot de passe de recuperation\n") elif initialHash == 0: client.sendall("\nVous n'avez pas cree de coffre-fort de recuperation avec ce mail.\n") elif initialHash != inputHash: client.sendall("\nVos donnees personnelles ne correspond pas avec celle enregistree. Utilisation du service impossible\n") conn.close() #main while True: conn = mysql.connector.connect(host="buzzromain.com", port=3307,user="web",password="ZbhTTi8szcKfaryk", database="isn") cursor = conn.cursor() socket.listen(5) client, address = socket.accept() print("{} connected".format(address)) userData = client.recv(255) userData = userData.decode() #On recupere les donnees en provenance du client userData = ast.literal_eval(userData) mode = userData['mode'] mail = userData['mail'] favorite_music = userData['favorite_music'] favorite_movie = userData['favorite_movie'] recovery_password = userData['password'] if mode == 1: config_recovery_pwd(mail, favorite_music, favorite_movie, recovery_password) elif mode == 2: recovery_pwd(mail, favorite_music, favorite_movie) print("Close") client.close() socket.close()
[/reveal] [reveal heading= »%image% Client »]
#!/usr/bin/env python # -*- coding: utf-8 -*- from Crypto.Cipher import AES from Crypto import Random from Crypto.Hash import SHA512 import getpass import os import binascii import sys import ast import socket if sys.version_info > (3, 0): #Sert a adapter le programme en fonction de la version de python v = 3 else: v = 2 #On definit les constantes du programme BLOCK_SIZE = 16 #Taille des blocks du chiffrement AES vault_directory = os.path.dirname( __file__ ) hote = "buzzromain.com" port = 15555 #Fonction #Cette fonction permet d'ajouter des informations a la fin du texte pour que celui-ci soit compose de blocks de 16 octets chacun #La fonction de chiffrement AES necessite de chiffrer un texte dont la taille est un multiple de 16 octets def pad(data): length = BLOCK_SIZE - (len(data) % BLOCK_SIZE) if v == 3: return data + (chr(length)*length).encode("utf-8") else : data += chr(length)*length return data def unpad(data): return data[:-ord(data[len(data)-1:])] def get_recovery_form(): #Fonction qui affiche le formulaire de recuperation de mot de passe print("\nSaisissez vos donnees personnelles : \n") mail = raw_input("Adresse mail : ") favorite_music = raw_input("Musique preferee: ") favorite_movie = raw_input("Film prefere : ") return mail, favorite_music, favorite_movie def check_password(pwd_input, pwd_check): #Fonction qui verifie si le mot de passe est correct if pwd_check == pwd_input.decode(): return True else: return False def create_recovery_vault(plaintext): #Fonction qui creer le coffre-fort de recuperation recovery_password = binascii.hexlify(Random.get_random_bytes(16)) ciphertext, p = encrypt(plaintext, recovery_password) vault = open(vault_directory + "/coffre_fort_de_recuperation.txt" , "w") vault.write(ciphertext) vault.close() try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((hote, port)) mail, favorite_music, favorite_movie = get_recovery_form() userData = {'mail': mail, 'favorite_music': favorite_music, 'favorite_movie': favorite_movie, 'password': recovery_password, 'mode': 1} userData = str(userData).decode("utf-8") s.send(userData) print(s.recv(255)) #On affiche ce qu'envoie le serveur s.close() except: print("Connexion impossible au serveur.") def open_recovery_vault(): #Fonction qui ouvre le coffre-fort de recuperation vault = open(vault_directory + "/coffre_fort_de_recuperation.txt") ciphertext = vault.read() vault.close() mail, favorite_music, favorite_movie = get_recovery_form() try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((hote, port)) mail, favorite_music, favorite_movie = get_form() userData = {'mail': mail, 'favorite_music': favorite_music, 'favorite_movie': favorite_movie, 'mode': 2} userData = str(userData).decode("utf-8") s.send(userData) print(s.recv(255)) #On affiche ce qu'envoie le serveur s.close() if v == 2: plaintext = raw_input("Votre mot de passe de récupération : ") else: plaintext = input("Votre mot de passe de récupération : ") plaintext = decrypt(ciphertext, password) return plaintext except: print("Cannot connect to the server.") def create_main_vault(plaintext, password): #Fonction qui creer le coffre-fort principal ciphertext, pwd_check = encrypt(plaintext, password) if os.path.exists(vault_directory + "/coffre_fort.txt") == True: #Si le coffre-fort existe deja print("\nVoulez-vous effacer le coffre-fort deja existant ?") print("1. Oui") print("2. Non") if v == 2: delVault = int(raw_input("Votre choix : ")) else: delVault = int(input("Votre choix : ")) if delVault == 1: vault = open(vault_directory + "/coffre_fort.txt", "w") vault.write("{'ciphertext': '%s', 'pwd_check': '%s'}" % (ciphertext, pwd_check.decode("utf-8"))) vault.close() print("\nCoffre-fort cree avec succes") else: print("\nArret du programme") else: vault = open(vault_directory + "/coffre_fort.txt", "w") vault.write("{'ciphertext': '%s', 'pwd_check': '%s'}" % (ciphertext, pwd_check.decode("utf-8"))) vault.close() print("\nCoffre-fort cree avec succes") def open_main_vault(password): #Fonction qui creer le coffre-fort principal vault = open(vault_directory + "/coffre_fort.txt") readVault = ast.literal_eval(vault.read()) vault.close() plaintext = decrypt(readVault['ciphertext'], password, readVault['pwd_check']) if plaintext == False: return open_recovery_vault() else: return plaintext def encrypt(plaintext, password): #Fonction de chiffrement du coffre-fort password_hash = SHA512.new(password.encode()).digest() #On genere le hash du mot de passe derived_key = password_hash[:32] #La cle derive correspond au 32 premiers bits pwd_check = binascii.hexlify(password_hash[32:]) #La cle derive correspond au 32 derniers bits iv = Random.get_random_bytes(16) #On genere un IV aleatoire pour la fonction AES cipher = AES.new(derived_key, AES.MODE_CBC, iv) if v == 3: plaintext = pad(plaintext.encode("utf-8")) else: plaintext = pad(plaintext) ciphertext = iv + cipher.encrypt(plaintext) ciphertext = binascii.hexlify(ciphertext).decode("utf-8") return ciphertext, pwd_check def decrypt(ciphertext, password, pwd_check=None): #Fonction de dechiffrement de coffre-fort password_hash = SHA512.new(password.encode()).digest() if pwd_check == None or check_password(pwd_check, binascii.hexlify(password_hash[32:])) == True: derived_key = password_hash[:32] ciphertext = binascii.unhexlify(ciphertext) iv = ciphertext[:BLOCK_SIZE] cipher = AES.new(derived_key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext[BLOCK_SIZE:])) return plaintext else: return False #main print("1. Configurer coffre-fort") print("2. Acceder au coffre-fort") if v == 2: mainChoice = int(raw_input("Votre choix : ")) else: mainChoice = int(input("Votre choix : ")) if mainChoice == 1: password = getpass.getpass("\nChoisissez un mot de passe : ") if v == 2: plaintext = raw_input("Cle privee Bitcoin : ") else: plaintext = input("Cle privee Bitcoin : ") create_main_vault(plaintext, password) #On cree le coffre-fort principale create_recovery_vault(plaintext) #On cree le coffre-fort de recuperation elif mainChoice == 2: password = getpass.getpass("\nSaisissez votre mot de passe : ") print("Cle privee Bitcoin : %s" % open_main_vault(password))[/reveal] [reveal heading= »%image% Interface graphique »]
#!/usr/bin/env python # -*- coding: utf-8 -*- #import du module Tkinter from tkinter import * # programme pour créer la deuxieme fenetre def creation_fenetre1(): global mdp fenetre1 = Toplevel(fenetre) titre1 = Label(fenetre1, text = "Clé privée Bitcoin: ") titre1.grid() fenetre1.title("Coffre fort") #Je voudrai afficher ce texte (ligne 8-9-10) entreeT1 = Entry(fenetre1, textvariable = mdp, width = 30) entreeT1.grid() MdpCoffre = Label(fenetre1, text = "Mot de passe du coffre:") MdpCoffre.grid() expressionMdpCoffre = StringVar() entreeMdpCoffre = Entry(fenetre1, textvariable = expressionMdpCoffre, width = 30) entreeMdpCoffre.grid() fenetre1.minsize(400,300) DP = Label(fenetre1, text = "Données Personnelles (en minuscule et sans espace)") DP.grid() DP1 = Label(fenetre1, text = "Musique préféré:") DP1.grid() expressionDP1 = StringVar() entreeDP1= Entry(fenetre1, textvariable = expressionDP1, width = 30) entreeDP1.grid() DP2 = Label(fenetre1, text = "Livre préféré:") DP2.grid() expressionDP2 = StringVar() entreeDP2= Entry(fenetre1, textvariable = expressionDP2, width = 30) entreeDP2.grid() DP3 = Label(fenetre1, text = "Film préféré:") DP3.grid() expressionDP3 = StringVar() entreeDP3= Entry(fenetre1, textvariable = expressionDP3, width = 30) entreeDP3.grid() email = Label(fenetre1 , text = "Email:") email.grid() expressionEmail = StringVar() entreeEmail = Entry(fenetre1, textvariable = expressionEmail, width = 30) entreeEmail.grid() return #création de la 3eme fenetre def creation_fenetre2(): fenetre2 = Toplevel(fenetre) titre2 = Label(fenetre2, text = "Entrer votre mot de passe :") titre2.grid() fenetre2.title("Coffre fort") fenetre2.minsize(250,200) expressionfenetre2 = StringVar() entreefenetre2 = Entry(fenetre2, textvariable = expressionfenetre2, width = 30) entreefenetre2.grid() return #création de la 4eme fenetre def creation_fenetre3(): fenetre3 = Toplevel(fenetre) titre3 = Label(fenetre3, text = "Données Personnel (en minuscule et sans espace):" ) titre3.grid() fenetre3.title("Coffre fort") fenetre3.minsize(400,300) DP1 = Label(fenetre3, text = "Musique préféré:") DP1.grid() expressionDP1 = StringVar() entreeDP1= Entry(fenetre3, textvariable = expressionDP1, width = 30) entreeDP1.grid() DP2 = Label(fenetre3, text = "Livre préféré:") DP2.grid() expressionDP2 = StringVar() entreeDP2= Entry(fenetre3, textvariable = expressionDP2, width = 30) entreeDP2.grid() DP3 = Label(fenetre3, text = "Film préféré:") DP3.grid() expressionDP3 = StringVar() entreeDP3= Entry(fenetre3, textvariable = expressionDP3, width = 30) entreeDP3.grid() email = Label(fenetre3 , text = "Email:") email.grid() expressionEmail = StringVar() entreeEmail = Entry(fenetre3, textvariable = expressionEmail, width = 30) entreeEmail.grid() return # création de la 5eme fenetre # Je voudrais y afficher dans cette fenêtre def creation_fenetre4(): global mdp fenetre4 = Toplevel(fenetre) titre4 = Label(fenetre4 , text =" Votre clé privée est :") titre4.grid() mot_de_passe = Label(fenetre4 , text = mdp.get()) mot_de_passe.grid() return # création de la fenetre principale fenetre = Tk() fenetre.title("Coffre fort") titre = Label(fenetre, text = "Bienvenue sur le Coffre-fort !") titre.grid() # Variables globales du programme mdp = StringVar() # Mot de passe ? # Dimensions fenetre.minsize(300,200) # Création d'un cadre cadre = Frame(fenetre) cadre.grid() # Couleur titre.configure(fg = 'black') # Création d'un bouton bouton = Button(cadre, text = "Accès au coffre-fort", command = creation_fenetre2) bouton.grid() bouton.configure(fg = 'red') bouton2= Button(cadre, text ="Configuration", command = creation_fenetre1) bouton2.grid() boutontest = Button(cadre, text = "Test", command = creation_fenetre3) boutontest.grid() boutontest2 = Button(cadre, text = "Test2", command = creation_fenetre4) boutontest2.grid() # arrangement des widgets titre.grid(column=0 , row=0 , sticky = N) bouton.grid(row = 2 , column=6) bouton2.grid(row=2 , column=3 ) boutontest.grid(row = 4, column = 4 ) def quitter(): fenetre.destroy() fenetre.protocol('WM_DELETE_WINDOW', quitter) # permet de démarrer l'application fenetre.mainloop()
[/reveal]