M3102/td3-code/toolbox.py

251 lines
7.9 KiB
Python
Raw Normal View History

2022-05-16 15:00:09 +02:00
#!/usr/bin/env python3
# Avoir une lib avec des briques prêtes
# Avoir un script qui crée les fichiers de password SHA/PB/etc. pour pouvoir les manipuler en texte
# TD : associer les briques pour évaluer les attaques sur un pass / une base
# mettre un « except ImportError » et ressayer avec « Cryptodome » a la place de « Crypto »
import re
import time
import random
import hashlib
# tweak to (try to) handle different crypto lib naming across systems (Linux, Mac, Win)
try:
from Crypto.Cipher import AES
from Crypto import Random
except ImportError:
try:
from crypto.Cipher import AES
from crypto import Random
except ImportError:
from Cryptodome.Cipher import AES
from Cryptodome import Random
import base64
import os
import urllib.request
import string
# returns an array of a dictionary of passwords
def getPassDict(nbpasswords):
try:
f = open("files/passwords.txt")
except FileNotFoundError:
print("Downloading a passwords list...")
urllib.request.urlretrieve("https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt?raw=true", "files/passwords.txt")
print("Done !")
f = open("files/passwords.txt")
passwords = []
#nbpasswords = 10000
passtogen = nbpasswords
for password in f:
passwords.append(password.strip())
passtogen-=1
if passtogen == 0:
break
return passwords
def genRandomPassword():
length = 6
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for i in range(length))
# reads/writes shadow-style files
def readfile(filename):
f = open("files/"+filename)
res = []
for line in f:
output = line.strip().split(":")
res.append(output)
return res
def writeFile(filename, array):
f = open("files/"+filename,'w')
for line in array:
towrite = ""
for item in line:
towrite+=item + ":"
towrite = towrite[:-1]
f.write(towrite)
f.write('\n')
# Plain storage
def genplain(nblogins,nbpasswords):
passwords = getPassDict(nbpasswords)
logins = []
for i in range(0,nblogins):
login = "user" + str(i)
if (random.randint(0,10) < 4):
logins.append((login,passwords[random.randint(0,len(passwords)-1)]))
else:
logins.append((login,genRandomPassword()))
return logins
def authplain(login, passwd, database):
for i in database:
if i[0] == login:
current = i[1]
return (current == passwd)
# Encrypted storage
def genencrypted(logins):
encdb = []
key = Random.new().read(16)
iv = Random.new().read(AES.block_size)
f = open("files/enckey",'wb')
f.write((base64.b64encode(key)))
f.write(b":")
#f = open("files/enciv",'wb')
f.write((base64.b64encode(iv)))
for i in logins:
cipher = AES.new(key, AES.MODE_CFB, iv)
enc = (base64.b64encode(cipher.encrypt(i[1].encode('utf-8')))).decode("utf-8")
encdb.append((i[0],enc))
#print(enc)
return encdb
def authencrypted(login, passwd, database):
for i in database:
if i[0] == login:
current = i[1]
keyiv = readfile("enckey")[0]
key = base64.b64decode(keyiv[0])
iv = base64.b64decode(keyiv[1])
#key = base64.b64decode(readfile("enckey")[0][0])
#iv = base64.b64decode(readfile("enciv")[0][0])
cipher = AES.new(key, AES.MODE_CFB, iv)
return (passwd == cipher.decrypt(base64.b64decode(current)).decode('utf-8'))
def decrypt(keyiv,data):
key = base64.b64decode(keyiv[0])
iv = base64.b64decode(keyiv[1])
cipher = AES.new(key, AES.MODE_CFB, iv)
return cipher.decrypt(base64.b64decode(data)).decode('utf-8')
# SHA storage
def gensha(logins):
db = []
for i in logins:
csum = hashlib.sha256(i[1].encode('utf-8')).hexdigest()
db.append((i[0],csum))
return db
def authsha(login, passwd, database):
for i in database:
if i[0] == login:
current = i[1]
return (current == hashlib.sha256(passwd.encode('utf-8')).hexdigest())
def genshahashes(passwords):
hashes = []
for passwd in passwords:
hashes.append([hashlib.sha256(passwd.encode('utf-8')).hexdigest(),passwd])
return hashes
def getpassfromshahash(hashes, hash):
for j in hashes:
if j[0] == hash:
return j[1]
return None
# Salted SHA storage
def gensaltedsha(logins):
db = []
for i in logins:
salt = str(random.randint(0,65535))
csum = hashlib.sha256((i[1]+salt).encode('utf-8')).hexdigest()
db.append((i[0],csum,salt))
return db
def authsaltedsha(login, passwd, database):
for i in database:
if i[0] == login:
current = i[1]
salt = i[2]
return (current == hashlib.sha256((passwd+salt).encode('utf-8')).hexdigest())
def salthash(password,salt):
return hashlib.sha256((password+str(salt)).encode('utf-8')).hexdigest()
# PBKDF2 storage
def genpbkdf2(logins,nbiterations):
db = []
for i in logins:
salt = str(random.randint(0,65535))
csum = base64.b64encode(hashlib.pbkdf2_hmac('sha256',i[1].encode('utf-8'),str(salt).encode('utf-8'),nbiterations)).decode('utf-8')
db.append((i[0],csum,salt,str(nbiterations)))
return db
def authpbkdf2(login, passwd, database):
for i in database:
if i[0] == login:
current = i[1]
salt = i[2]
nbiterations = int(i[3])
return (base64.b64decode(current) == hashlib.pbkdf2_hmac('sha256',passwd.encode('utf-8'),str(salt).encode('utf-8'),nbiterations))
def pbkdf2(password,salt,nbiterations):
nbiterations = int(nbiterations)
return base64.b64encode(hashlib.pbkdf2_hmac('sha256',password.encode('utf-8'),str(salt).encode('utf-8'),nbiterations)).decode('utf-8')
# Generate shadow-style files
def initworkspace(nblogins,nbpasswords,nbiterations):
print("Generating " + str(nblogins) + " logins and " + str(nbpasswords) + " passwords")
try :
os.mkdir("files")
except FileExistsError:
pass
plaindb = genplain(nblogins,nbpasswords)
writeFile("plain", plaindb)
encdb = genencrypted(plaindb)
writeFile("enc", encdb)
shadb = gensha(plaindb)
writeFile("sha", shadb)
saltedshadb = gensaltedsha(plaindb)
writeFile("saltedsha", saltedshadb)
pbkdf2db = genpbkdf2(plaindb,nbiterations)
writeFile("pbkdf2", pbkdf2db)
# Unit tests
if __name__ == '__main__':
# create shadow files
initworkspace(10,100,1000)
print("======\nUnit tests of the toolbox, you must work in skeleton.py\n=========")
# test plain DB
print("\n============\nPlain storage:")
plaindb = readfile("plain")
print("Plain DB is : " + str(plaindb))
print("Authenticating with plain DB : " + str(authplain(plaindb[0][0],plaindb[0][1],plaindb)))
#test encrypted db
print("\n============\nEncrypted storage:")
encdb = readfile("enc")
print("Encrypted DB is " + str(encdb))
print("Authenticating with encrypted DB : " + str(authencrypted(plaindb[1][0],plaindb[1][1],encdb)))
#test SHA db
print("\n============\nSHA storage:")
shadb = readfile("sha")
print("SHA DB is " + str(shadb))
print("Authenticating with SHA DB : " + str(authsha(plaindb[0][0],plaindb[0][1],shadb)))
#test Salted SHA db
print("\n============\nSalted SHA storage:")
saltedshadb = readfile("saltedsha")
print("Salted SHA DB is " + str(saltedshadb))
print("Authenticating with Salted SHA DB : " + str(authsaltedsha(plaindb[0][0],plaindb[0][1],saltedshadb)))
# test PBKDF2 DB
print("\n============\nPBKDF2 storage:")
pbkdf2db = readfile("pbkdf2")
print("PBKDF2 DB is " + str(pbkdf2db))
print("Authenticating with PBKDF2 DB : " + str(authpbkdf2(plaindb[0][0],plaindb[0][1],pbkdf2db)))
print("\n======\nUnit tests of the toolbox, you must work in skeleton.py\n=========")