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.

 

 

[reveal heading= »%image% Serveur »]
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]

 

 

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.