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]
