#!/usr/bin/env python3
# coding: utf-8
# la 1e ligne indique au systéme que le programme est écrit en Python3, ce n'est pas un commentaire
# la 2e ligne permet de declarer le codage du texte, ce n'est pas un commentaire
version= "v0.2i+"
date_version= "14/12/2020 "
# paramétres par défaut
# nombre de mots en entrée:
NbrePsw=3
# définition de la langue par défaut:
lang="fr"
# "fr" : français
# "es" : espanol
# "en" : english
# prise en charge linguistique
# messages dédiés à une seule langue
description_fr="programme de fusion de mots de passe pour en obtenir un meilleur"
description_es="programa para fusionar password y tener un mejor"
description_en="melting password program to create a better one"
hlp_fr="en langue française"
hlp_es="en idioma espagnola"
hlp_en="in english"
# messages d'aide traduits en plusieurs langues
if lang=="fr":
description= description_fr
hlp_ver = "affiche la version"
hlp_vinfo = "affiche les notes de version"
hlp_stat = "affiche les statistiques"
hlp_stat0 = "n'affiche pas les statistiques"
hlp_stat1 = "affiche les statistiques (résumé)"
hlp_stat2 = "affiche les statistiques (complets)"
hlp_notice = "affiche la notice d'utilisation"
hlp_c2 = "mot de passe créé avec 2 mots en entrée"
hlp_c3 = "mot de passe créé avec 3 mots en entrée"
hlp_c5 = "mot de passe créé avec 5 mots en entrée"
elif lang=="es":
description= description_es+"\ntraduccion inconpleta"
hlp_ver = "muestra la version"
hlp_vinfo = "affiche les notes de version"
hlp_stat = "indica las statisticas"
hlp_stat0 = "no indica las statisticas"
hlp_stat1 = "indica las statisticas (resumen)"
hlp_stat2 = "indica las statisticas (todos)"
hlp_notice = "indica la noticia de utilisation"
hlp_c2 = "mot de passe créé avec 2 mots en entrée"
hlp_c3 = "mot de passe créé avec 3 mots en entrée"
hlp_c5 = "mot de passe créé avec 5 mots en entrée"
elif lang=="en":
description= description_en+"\ntranslation incomplet"
hlp_ver = "display version"
hlp_vinfo = "affiche les notes de version"
hlp_stat = "display statistics"
hlp_stat0 = "no indica las statisticas"
hlp_stat1 = "display statistics (resumen)"
hlp_stat2 = "display statistics (todos)"
hlp_notice = "display notice of use"
hlp_c2 = "password created with 2 word given"
hlp_c3 = "password created with 3 word given"
hlp_c5 = "password created with 5 word given"
# définition des modes de fonctionnement par défaut
# affichage des statistiques
# (0:non, 1:résumé, 2:complets):
stat=0
# affichage de l'évolution du mot de passe
# (1:oui, 0:non):
evol=1
# autorisation message humouristique
fun=1
# initialisation
import argparse
import sys
parser = argparse.ArgumentParser(description=description)
# la description est visible lors de l'utilisation de -h ou --help
parser.add_argument("-notice" , help=hlp_notice, action="store_true")
parser.add_argument("-c2" , help=hlp_c2 , action="store_true")
parser.add_argument("-c3" , help=hlp_c3 , action="store_true")
parser.add_argument("-c5" , help=hlp_c5 , action="store_true")
parser.add_argument("-fr" , help=hlp_fr , action="store_true")
parser.add_argument("-es" , help=hlp_es , action="store_true")
parser.add_argument("-en" , help=hlp_en , action="store_true")
parser.add_argument("-stat" , help=hlp_stat , action="store_true")
parser.add_argument("-stat0" , help=hlp_stat0, action="store_true")
parser.add_argument("-stat1" , help=hlp_stat1, action="store_true")
parser.add_argument("-stat2" , help=hlp_stat2, action="store_true")
parser.add_argument("-ver" , help=hlp_ver , action="store_true")
parser.add_argument("-verinfo", help=hlp_vinfo, action="store_true")
args = parser.parse_args()
# définition des messages, prise en charge linguistique
if not args.fr and not args.es and not args.en:
if lang=="fr": args.fr=1
elif lang=="es": args.es=1
elif lang=="en": args.en=1
if args.fr:
lang="fr"
description = description_fr
errFatal_msg="erreur fatale: arret du programme"
XPsolve_msg ="solution expérimentale non optimale"
if fun:
DdeIncoé_msg="bah, il faudrait se décider!"
else:
DdeIncoé_msg="demande incohérente"
elif args.es:
lang="es"
description = description_es
errFatal_msg="falta critica: asi para el programa"
XPsolve_msg ="tratamiento experimental non optimale"
if fun:
DdeIncoé_msg="bah, il faudrait se décider!"
else:
DdeIncoé_msg="demande incohérente"
elif args.en:
lang="en"
description = description_en
errFatal_msg="erreur fatale: end of program"
XPsolve_msg ="experimental way non optimal"
if fun:
DdeIncoé_msg="hey, what do you ask me?"
else:
DdeIncoé_msg="demande incohérente"
# message de démarrage
print(description)
print("FusePassWord", version,"du",date_version)
# affichage numéro de version et notes de version:
if args.ver or args.verinfo or args.notice:
# no version et date de la version déjà indiqués
if args.notice:
print("intérêt du programme:\n génére un mot de passe fort à partir de mots faciles à retenir")
print("attention l'ordre des mots compte! (pour l'instant)")
print(' option "-c2" => 2 mots 5 à 8=> 1 mot de 10 à >15 ~ >200 *10^ 6 combinaisons')
print(' option "-c3" => 3 mots 6 à 12=> 1 mot de 18 à >36 ~ >15 *10^12 combinaisons')
print(' option "-c5" => 5 mots 6 à 18=> 1 mot de 30 à >90 ~ > 9 *10^21 combinaisons')
# https://motsavec.fr/
#1: estimé sur la base de 15000 mots de 5 caractéres dans le dico français
#2: estimé sur la base de 25000 mots de 6 caractéres dans le dico français
print('Notes:\n -la longueur maximale du mot est évaluée sur le nombre de caractéres différents, pas sur le nombre total')
print(' -les espaces ne comptent pas, ils sont immédiatement supprimés')
print('conseils:\n -éviter les dates (sur 4 caractéres: 365 combinaisons, comparé à 7000 mots français)')
if args.verinfo:
if lang=="en": print("yes... the programateur is français, j'écris en français! :p ")
if lang=="es": print("hola amig@! perdoname no traducir este parafo...")
print("un + à la fin => évolution ajoutée à la version indiquée\n")
# print("un - à la fin => évolution pour préparer la version indiquée \n")
print("v0.1 : premiére version fonctionnelle (incompatible avec futures versions)")
print("v0.2 : amélioration méthode de fusion + création d'une gestion de mots en entrée de taille trés différentes")
print("v0.2a -> v0.2f: versions expérimentales, améliorations")
print("v0.2g: version expérimentale fonctionelle, mise en place de fonctions intégrées")
print("v0.2h: version expérimentale fonctionelle, sauvegarde avant mise en service d'une boucle")
print("v0.2i: version expérimentale fonctionelle, sauvegarde après mise en service d'une boucle")
sys.exit(1)
# sélection de l'affichage des infos statistiques
if args.stat or args.stat0 or args.stat1 or args.stat2:
if args.stat + args.stat0 + args.stat1 + args.stat2>1:
print(DdeIncoé_msg)
stat=2
elif args.stat:
stat=1
elif args.stat0:
stat=0
elif args.stat1:
stat=1
elif args.stat2:
stat=2
# sélection du nombre de mots en entrée
if args.c2 or args.c3 or args.c5:
if args.c2 + args.c3 + args.c5>1:
print(DdeIncoé_msg)
print(errFatal_msg)
sys.exit(1)
elif args.c2:
NbrePsw=2
elif args.c3:
NbrePsw=3
elif args.c5:
NbrePsw=5
if NbrePsw==2:
lenmotmin=5
lenmotmax=8
elif NbrePsw==3:
lenmotmin=6
lenmotmax=12
elif NbrePsw==5:
lenmotmin=6
lenmotmax=18
nombre ="0123456789"
majuscule="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
minuscule="abcedfghijklmnopqrstuvwxyz"
# symboles supprimés:
symbolSup=[" ",":","/","'",","]
# symboles conservés:
symbolCon=["@"]
# lettres accuentuées:
accentsFr="éèêà"
# codes internes
# modifier ces codes permettent de personnaliser le programme
# mais les mots de passe générés ne seront plus forcément les mêmes
Cin=[]
Cin.append("Gi8eclH3fd5")
Cin.append("dlcfixhj4g9")
Cin.append("16485273590")
Cin.append("hxGKEZNXFQLkdj")
Cin.append("mdebosicbqkkgwkdbs")
# matrice numérique type "sudoku":
# 9 suites de 10 chiffres différents
# aucune suite ne posséde un numéro à la même place qu'une autre suite
Cnum=[]
#Cnum.append(2586479310) #1
#Cnum.append(5014928731) #2
#Cnum.append(8627514093) #3
#Cnum.append(72493816 5) #4
#Cnum.append(6351705428) #5
#Cnum.append(1860932974) #6
#Cnum.append(4192863507) #7
#Cnum.append(9735147286) #8
#Cnum.append(3478690152) #9
#pas encore prêt...
# definition de la fonction de comptage
def compte_all(x):
Dif = [numDif, minDif , majDif]
Id = [numId , numId , majId ]
variable =[nombre, minuscule, majuscule]
for y in range (0,3):
if x>0:
Dif[y].append(0)
Id[y].append([0]) # crée une liste dans la liste (de la liste) -ça marche pas
for var in variable[y]:
if var in psw[x]:
Dif[y][x] +=1
identique = size[x] - len( str(psw[x]).replace(var,"") )
if identique>1:
if x>0: Id[y][x].append(identique)
# x>0 : création d'un nouvel élement dans la liste car ajout d'un mot
else : Id[y][x]=identique
# x=0 : bilan la liste est déjà créée
def IdSumIn0(x):
minId[x][0]=sum(minId[x])-len(minId[x])+1
majId[x][0]=sum(majId[x])-len(majId[x])+1
numId[x][0]=sum(numId[x])-len(numId[x])+1
ok=0
while not ok:
# initialisation des variables
ok=0
psw =[0] #mot de passe
size =[0] #taille du mot de passe
numDif=[0] #nombre de chiffres différents
minDif=[0] #nombre de lettres minuscules différentes
majDif=[0] #nombre de lettres majuscules différentes
allDif=[0] #nombre de caractéres différents
numId =[0] #nombre de chiffres identiques
minId =[0] #nombre de lettres minuscules identiques
majId =[0] #nombre de lettres majuscules identiques
allId =[0] #nombre de caractéres identiques
# demande des mots de passe de départ
for x in range (1,NbrePsw+1):
ok=0
while not ok:
old=1
while old:
if lang=="fr": msg="e mot de passe: "
elif lang=="es": msg="a palabra: "
elif lang=="en": msg="st password: "
msg=str(x)+str(msg)
new=input(msg)
old= new in psw
if old:
if lang=="fr": print("mot déjà utilisé, en choisir un autre")
elif lang=="es": print("palabra ya utilisada, elegir una otra")
elif lang=="en": print("word yet given, change")
# vérification si le mot correspond à un autre à l'envers ou avec exactement les mêmes lettres qu'un autre
# Fonction supprimée
psw.append(new)
for var in symbolSup:
if var in psw[x]:
psw[x]=psw[x].replace(var,"")
size.append( len( str(psw[x]) ) )
if size[x]<lenmotmin:
if lang=="fr": msg="min, ce mot est trop court"
elif lang=="es": msg="min, esta palabra es demasiada corta"
elif lang=="en": msg="min, word too small"
print("",lenmotmin,msg)
else:
ok=1
# nombres
numDif.append(0)
numId.append([0]) # crée une liste dans la liste
for var in nombre:
if var in psw[x]:
numDif[x] +=1
identique = size[x] - len( str(psw[x]).replace(var,"") )
if identique>1:
numId[x].append(identique)
# minuscules
minDif.append(0)
minId.append([0]) # crée une liste dans la liste
for var in minuscule:
if var in psw[x]:
minDif[x] +=1
identique = size[x] - len( str(psw[x]).replace(var,"") )
if identique>1:
minId[x].append(identique)
# majuscules
majDif.append(0)
majId.append([0]) # crée une liste dans la liste
for var in majuscule:
if var in psw[x]:
majDif[x] +=1
identique = size[x] - len( str(psw[x]).replace(var,"") )
if identique>1:
majId[x].append(identique)
# calcul et évaluation du mot
# caractéres identiques
IdSumIn0(x)
allId.append( minId[x][0] + majId[x][0] + numId[x][0] )
# caractéres différents
allDif.append( minDif[x] + majDif[x] + numDif[x] )
if allDif[x]> lenmotmax:
if lang=="fr": msg="max, ce mot est trop long"
elif lang=="es": msg="max, esta palabra es demasiada larga"
elif lang=="en": msg="max, this word is too long"
print("",lenmotmax,msg)
ok=0
if allDif[x]> 20: melt=1
elif numDif[x]> 8: melt=1
elif size[x]<= 6 and allDif[x]>= 0.75*size[x]: melt=1
elif size[x]<=16 and allDif[x]>=10/16*size[x]: melt=1
elif size[x]<=20 and allDif[x]>=12/20*size[x]: melt=1
elif size[x]<=25 and allDif[x]>=14/25*size[x]: melt=1
else:
if lang=="fr": print(" ce mot est trop monotone")
elif lang=="es": print(" esta palabra es demasiada monotona")
elif lang=="en": print(" this word is too ...")
ok=0
if stat:
print("statistiques du mot d'entrée:")
print(" -longueur du mot :", size[x])
if stat==2:
print(" -chiffres différents :",numDif[x])
print(" -minuscules différentes:",minDif[x])
print(" -majuscules différentes:",majDif[x])
print(" -caractéres différents :",allDif[x])
elif stat==1:
print(" -caractéres différents :",allDif[x])
if stat==2:
print(" -chiffres identiques :",numId[x])
print(" -minuscules identiques :",minId[x])
print(" -majuscules identiques :",majId[x])
print(" -caractéres identiques :",allId[x])
if not ok:
if lang=="fr": print("\033[33m mot refusé\033[0m, on recommence")
elif lang=="es": print("\033[33m palabra denegada\033[0m, vamos de nuevo")
elif lang=="en": print("\033[33m word refused\033[0m, i come back")
# \033[33m couleur \033[0m => couleur est écrit en orange
# suppession du mot refusé et des données du mot refusé
del psw[x]
del size[x]
del numDif[x]
del minDif[x]
del majDif[x]
del allDif[x]
del minId[x]
del majId[x]
del numId[x]
del allId[x]
else:
if lang=="fr": print("\033[32m mot accepté\033[0m")
elif lang=="es": print("\033[32m palabra aceptada\033[0m")
elif lang=="en": print("\033[32m word accepted\033[0m")
# \033[32m couleur \033[0m => couleur est écrit en vert
if x<NbrePsw:
if lang=="fr": print("=>suivant")
elif lang=="es": print("=>suivant")
elif lang=="en": print("=>next")
else:
if lang=="fr": print("=>prépation au mixage...")
elif lang=="es": print("=>preparación al mezcla...")
elif lang=="en": print("=>preparing the mix...")
# calcul et évaluation globale
size[0]=sum(size)
var=""
for x in range (1,len(psw)):
var = var + str(psw[x])
psw[0]= var
x=0
compte_all(0)
#IdSumIn0(0)
allDif[0]= minDif[0] + majDif[0] + numDif[0]
if allDif[x]> 30: melt=1
elif size[x]<=16 and allDif[x]>=10/16*size[x]: melt=1
elif size[x]<=20 and allDif[x]>=12/20*size[x]: melt=1
elif size[x]<=25 and allDif[x]>=14/25*size[x]: melt=1
elif NbrePsw== 2 and allDif[x]>=10: melt=1
elif NbrePsw== 3 and allDif[x]>=15: melt=1
else:
if lang=="fr": print(" cette combinaison est trop monotone")
elif lang=="es": print(" esta combinación es demasiada monotona")
elif lang=="en": print(" this combination is too ...")
ok=0
if stat:
print("statistiques globales:")
print(" -longueur cumulée des mots:",size)
if stat==2:
print(" -chiffres différents :",numDif)
print(" -minuscules différentes :",minDif)
print(" -majuscules différentes :",majDif)
print(" -caractéres différents :",allDif)
if stat==2:
print(" -chiffres identiques :",numId)
print(" -minuscules identiques :",minId)
print(" -majuscules identiques :",majId)
print(" -caractéres identiques :",allId)
if not ok:
if lang=="fr": print("\033[33m combinaison refusée\033[0m, on recommence")
elif lang=="es": print("\033[33m combinación denegada\033[0m, vamos de nuevo")
elif lang=="en": print("\033[33m combination refused\033[0m, i come back")
# \033[33m couleur \033[0m => couleur est écrit en orange
# suppession du mot refusé et des données du mot refusé
#initialise()
else:
if lang=="fr": print("\033[32m combinaison accepté\033[0m")
elif lang=="es": print("\033[32m combinación aceptada\033[0m")
elif lang=="en": print("\033[32m combination accepted\033[0m")
# \033[32m couleur \033[0m => couleur est écrit en vert
ok=1
if evol:
print("données initiales:")
print(psw)
# calcul sur les longueurs des mots entrés
# la méthode "liste.index(valeur)" indique la position de la valeur recherchée dans la liste
if 1:
#def sizeCalc(size):
lst=[]
var=[]
for x in range (1,len(size)):
var=size[x]
lst.append(var)
maxSize =max(lst)
maxSizeIn =size.index(maxSize)
minSize =min(lst)
minSizeIn =size.index(minSize)
DeltaSize =maxSize-minSize
otherSize =size[0]-maxSize
# otherSize: taille des autres mots
#return(maxSize, maxSizeIn, minSize, minSizeIn, DeltaSize)
#sizeCalc(size)
# définition de la fonction
def reducePsw(x):
# suppression des caractéres identiques dans le mot
if 0<x<NbrePsw:
msg=str(x)+"e mot"
if evol: print("réduction ",msg)
for var in str(minuscule)+str(majuscule)+str(nombre):
if var in psw[x]:
identique = len(psw[x]) - len( str(psw[x]).replace(var,"") )
if identique>1:
psw[x]=psw[x].replace(var,"")
# correction de la longueur de la nouvelle chaine:
size[x]=len( str(psw[x]) )
# mise à jour des calculs sur les longueurs des mots entrés:
#sizeCalc()
else:
if evol: print("erreur l'index",x," est refusé par la fonction \"reducePsw\" ")
return(size,psw)
revlst=[]
reduceAsk=0
# gestion avec 2 mots entrés
if NbrePsw==2:
if DeltaSize==0:
revlst=2
elif DeltaSize<minSize:
revlst.append(maxSizeIn)
else:
print(XPsolve_msg)
revlst=[minSizeIn]
reducePsw(maxSizeIn)
# gestion de la taille des mots:
if NbrePsw>2:
if maxSize>otherSize+1:
# si le mot le plus grand dépase la somme des autres
if allDif(maxSizeIn)<otherSize:
reduceAsk=1
if reduceAsk:
reducePsw(maxSizeIn)
#sizeCalc()
# gestion des différences de longueur:
if NbrePsw==3:
revlst=[1,3] # valeur par défaut
if maxSizeIn in [1,3]:
if DeltaSize<3:
revlst=[1,3]
else:
print(XPsolve_msg)
revlst=[1,3]
else:# maxSizeIn in [2]:
if size[1]+size[3]>size[2]:
revlst=[1,3]
elif size[1]+size[3]<size[2]:
#allDif = minDif[2] + majDif[2] + numDif[2]
if size[1]+size[3]>=allDif:
revlst=[1,3]
reducePsw(maxSizeIn)
else:
print("mot trop long par rapport aux autres")
print(errFatal_msg)
sys.exit(2)
elif size[1]+size[3]==size[2]:
revlst=[2]
if evol: print("liste inversion:",revlst,"\n",psw)
# inversion
for x in range (1,NbrePsw+1):
if x in revlst:
reverse="" # mot à l'envers
y=0
for var in reversed(psw[x]):
y +=1
reverse=str(reverse)+str(var)
if size[x]==y:
psw[x]=reverse
if evol: print("inversion:","\n",psw)
#vérification qu'un mot inversé ne soit pas identique à un mot non inversé
ok=0
while not ok:
for x in range (1,NbrePsw+1):
for y in range (1,NbrePsw+1):
if not x==y:
if psw[x]==psw[y]:
print("erreur: égalité de 2 mots lors de l'inversion")
print("",XPsolve_msg,":")
if NbrePsw>2:
print("","avertissement: faiblesse possible")
else:
print("",errFatal_msg)
sys.exit(2)
ok=1
# ne fonctionne pas bien
if evol: print("contrôle anti-égalité après inversion:","\n",psw)
# fusion des x mots de passe (résultat provisoire)
# x: numéro dans la liste des mots entrés
# y: numéro dans la chaine du mot entré
# la "bidouille" maxSize est nécésaire sinon le plus grand mot n'est pas "pris en sandwich" et donc pas "déformé"
def Xor(A,B):
"""ou exclusif"""
Xor=(A and not B) or (B and not A)
return(Xor)
if maxSizeIn==1: lstDebut=[maxSizeIn,2,4]
if maxSizeIn==2: lstDebut=[maxSizeIn,1,3]
if maxSizeIn==3: lstDebut=[maxSizeIn,2,4]
var=""
for y in range (1,maxSize+1):
for x in range (1,NbrePsw+1):
# print(Xor(x%2, maxSizeIn%2),end="-")
#if (x%2): # si x est impair
#if Xor(x%2, maxSizeIn%2):
if x in lstDebut:
if y<=size[x]:
var=str(var)+str( str(psw[x])[y-1] )
# l'écriture commence au début
else:
debut= maxSize-len(str(psw[x]))
if y>=debut:
var=str(var)+str( str(psw[x])[y-debut-1] )
# l'écriture se termine à la fin (enfin théoriquement!)
psw[0]=var
if evol:
print("fusion:")
print(psw[0])
size[0]= len( str(psw[0]) )
if lang=="fr": print("\033[34mrésultat final\033[0m (",size[0],"caractéres ):")
elif lang=="es": print("\033[34mrésultado final\033[0m (",size[0],"caractéres ):")
elif lang=="en": print("\033[34mfinal result\033[0m (",size[0],"caractéres ):")
# \033[34m couleur \033[0m => couleur est écrit en bleu
print("",psw[0])