Il est assez fréquent de retrouver l'algorithme de chiffrement de Vigenère dans des challenges de sécurité informatique. Voici un script python pour l'occasion. Il existe déjà un programme en C sur ce site dans la section Documents > Programmation sur Vigenère. Ce script fait suite au challenge de Thalès refait. Sauf que cette fois, j'ai codé un script Python pour l'occasion





0x01. ANALYSE DE L'IMAGE


 
wget "http://images.go.thales-esecurity.com/EloquaImages/clients/ThalesEsecurity/%7Bf2240c5e-765c-4672-a8c8-0d1d00b05f4d%7D_spooks2.png" -O -|strings
 


Le texte suivant m'interpèle :


ptEXtciphertext
MESSAGE: gbvmdaxhtgfisaa uz dipzebtmao ztiw zmyeakr bnq arfekd ysh zkcumem oe riwmcekm END-OF-MESSAGEmk$
tEXthandover-date
25 July 1939



0x02. ANALYSE DU TEXTE



On en extrait le message:


gbvmdaxhtgfisaa uz dipzebtmao ztiw zmyeakr bnq arfekd ysh zkcumem oe riwmcekm


Je tente l'algo que j'ai le plus retrouvé dans les challenge de Hacking, celui de Vigenère. Et cette fois, je me dis, autant écrire un "bruteforce" "intelligent", notre bruteforce doit :

1- Implémenter l'algo de Vigenère (sans déc' ^^)

2.1- Essayer une liste de mot de passe depuis un fichier …

2.2- … ou essayer toutes les combinaisons possibles (aaaa ... aaab .... mlkj ... zzzz)

3- Détecter des mots de la langue française ou anglaise





0x03. ALGORITHME DE VIGENÈRE


 
#!/usr/bin/env python
#-*- Encoding: UTF-8 -*-
 
# Pour la fonction sys.exit() et pour les arguments sys.arg*
import sys
 
# Le nom du programme
APP="vigenere"
 
# Base de la clé (si elle commence par A, AB, ...)
KEY_BASE=""
 
# Alphabet, le chiffrement de Vigenère ne chiffre que l alphabet
ab="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
# Contiendra la liste des mots du fichier de langue
lang=[]
 
# Fichier de langue par défaut
DIC_FILE="french.dic"
 
# Taille minimale d'un mot
MIN_LEN_WORD=3
 
# Lecture du fichier de langue
def initlang():
  fh = open(DIC_FILE,"r")
  for line in fh.readlines():
    # On ajoute que les mots de longueur supérieures à MIN_LEN_WORD
    if( len(line) > MIN_LEN_WORD ):
      lang.append(line.strip())
 
# Génère une liste de mot pour le bruteforce (aaaaaa, aaaaab, qsdfgh, zzzzzz)
def combine(alphabet, nb, base = ''):
  for c in alphabet:
    if nb == 1:
      yield base + c
    else:
      for c1 in combine(alphabet, nb-1, base + c):
        yield c1
 
# Associe l'index du tableau à l'indexe de la lettre du mot de passe :
# key = "ANIMAL"
# ikey= {0: 1, 1: 14, 2: 9, 3: 13, 4: 1, 5: 12}
#        0     1      2     3      4     5   
#           A     N      I     M      A     L
def init(key):
  ikey={}
  for i in range(0,len(key)):
    ikey[i]=ord(key[i])-ord(ab[0])+1
  return(ikey)
 
# Chiffre avec le tableau initialisé
def encrypt(str,key):
  enc=""
  ikey={}
  ikey=init(key)
  k = 0
  for i in range(0,len(str)):
    if( str[i] >= "A" and str[i] <= "Z" ):
      # ord(str[i]) - ord(ab[0]) = ABCD => 65-65 66-65 67-65 68-65 => 0123
      enc = enc + chr(  ( ord(str[i]) - ord(ab[0]) + ikey[k%len(key)] - 1 ) % len(ab)  + ord(ab[0])  )
      k = k + 1
    else:
      enc = enc + str[i]
  return(enc)
 
 
# Déhiffre avec le tableau initialisé
def decrypt(enc,key):
  dec=""
  ikey=init(key)
  k = 0
  for i in range(0,len(enc)):
    if( enc[i] >= "A" and  enc[i] <= "Z" ):
      dec = dec + chr(  ( ord(enc[i]) - ord(ab[0]) - ikey[k%len(key)] + 1 ) % len(ab)  + ord(ab[0])  )
      k = k + 1
    else:
      dec = dec + enc[i]
  return(dec)
 
 
def usage():
    print "\\nUsage: %s <-e -k key | -d -k key | -d -b # | -d -F wordlist> <-s string|-f file> [-D dict] [-B base]\\n" % APP
    sys.exit(0)
 
# Traitement des arguments
if( len(sys.argv) < 6 or len(sys.argv) > 10 ):
  usage()
 
if( len(sys.argv) >= 8 ):
  DIC_FILE=sys.argv[7]
 
if( len(sys.argv) == 10 ):
  if( sys.argv[8] == "-B" ):
    KEY_BASE=sys.argv[9]
  else:
    usage()
 
arg1=sys.argv[1]
arg2=sys.argv[2]
 
if( arg2 == "-k" ):
  key=sys.argv[3].upper()
elif( arg2 == "-b" ):
  sze=int(sys.argv[3])
  words=combine(ab,sze,KEY_BASE)
elif( arg2 == "-F" ):
  dic=sys.argv[3]
  fh = open(dic,"r")
  words=fh.readlines()
  fh.close()
else:
  usage()
 
 
arg3=sys.argv[4]
input=sys.argv[5]
 
 
if( arg3 == "-s" ):
  str=input.upper()
elif( arg3 == "-f" ):
  fh = open(input,"r")
  str = fh.read()
  fh.close()
else:
  usage()
 
 
if( arg1 == "-e" ):
  if( arg2 == "-b" ):
    usage()
  else:
    print encrypt(str, key),
 
elif( arg1 == "-d" ):
  if( arg2 == "-b" or arg2 == "-F" ):
    initlang()
    count=0
    for key in words:
      key = key.strip()
      if( len(key) >= MIN_LEN_WORD ):
        count=count+1
        res = decrypt(str, key)
        score = 0
        for word in lang:
          if word in res:
              score = score + 1
        # if score: # Pour l'explication et la démonstration
        print("\\n[ # %-8s ]  Score: %-2d   Key: %-15s   Result: '%s'") % (count,score,"'"+key+"'",res.strip()),
  else:
    print decrypt(str, key),
 
else:
  usage()
 
print "\\n"
 




0x04. DICTIONNAIRE DE MOTS DE PASSE



Étant donné le contexte de l'image (1939), voici une liste de mot en rapport avec le contexte :


 
echo 'AIDE
CENTERFOLD
EINSTEIN
ENIGMA
JEW
JULY
MESSAGE
PASS
PODANSKI
TESLA
TURING
WAR' > wordlist.dic
 




0x05. DICTIONNAIRE LINGUISTIQUE



Définir une liste de mot qui pourrait faire office de reconnaissance de langue (ici, l'anglais) :


 
echo 'CONGRAT
THIS
HELL
GOOD
WERE
IS
TEST
FROM
BLUE
WORD
WORLD
WAR
OVER' > english.dic
 




0x06. BRUTEFORCE



Le périmètre de bruteforce étant maintenant limité, nous pouvons exécuter une attaque par force brute :


 
python Vigenere.py -d -F wordlist.dic -f in -D english.dic
 

[ # 1        ]  Score: 0    Key: 'AIDE'            Result: 'GTSIDSUDTYCESSX QZ VFLZWYPMSL VTAT VMQBWKJ YJQ SOBECA USZ WGCMJAM GB NIOJYECJ'
[ # 2        ]  Score: 0    Key: 'CENTERFOLD'      Result: 'EXITZJSTIDDEFHW DU PXMXAOAIJJ LIFU VZFAJFD QKO WEMATY KHE XGPBINH AT OGSZJATH'
[ # 3        ]  Score: 0    Key: 'EINSTEIN'        Result: 'CTIUKWPUPYSQZWS HV VVXGATGISB HAEO MIQRIRN TAM SENLGV LOZ MSJQERI GR ZPSEPACZ'
[ # 4        ]  Score: 2    Key: 'ENIGMA'          Result: 'CONGRATULATIONS ON DECRYPTING THIS MESSAGE THE ANSWER YOU REQUIRE IS REJEWSKI'
[ # 5        ]  Score: 0    Key: 'JEW'             Result: 'XXZDZEODXXBMJWE LV HZLDVXXDWS QPMN VQPAEBN FEM EIBIBZ CJD DBYYDAQ FA VZSQTAOD'
[ # 6        ]  Score: 0    Key: 'JULY'            Result: 'XHKOUGMJKMUKJGP WQ JXRQKQVDGD BKOL BDETCBX QPH GGHVQS AJN OMTABGD UT TZCBEVQB'
[ # 7        ]  Score: 0    Key: 'MESSAGE'         Result: 'UXDUDUTVPONIMWO QH LIJVSXBUAI VHEE HMSAOGZ JNK WFBMSD SOV VSKUGAA KM ZIQIQASU'
[ # 8        ]  Score: 0    Key: 'PASS'            Result: 'RBDUOAFPEGNQDAI CK DQXKEJBXAW HEIE HXYMIVR JVB AZNPKL GDH HSNUUMX OM ZTWUKPKU'
[ # 9        ]  Score: 0    Key: 'PODANSKI'        Result: 'RNSMQINZESCIFIQ MK PFPMMRLXML ZGQM RXKBAXZ RFB MOFRST QDT WKPCCWX AB RVECUPWJ'
[ # 10       ]  Score: 0    Key: 'TESLA'           Result: 'NXDBDHTPIGMEAPA BV LXPGAJIMHK HIID VUNEHGZ QNX WZUERZ GHH GGKJMLI WT RPSURERI'
[ # 11       ]  Score: 0    Key: 'TURING'          Result: 'NHEEQUENCYSCZGJ MM XPVIWONTGX RGCD FVQRURX KFD UYLNCQ SZN ICPOTKV GR LPCVURET'
[ # 12       ]  Score: 0    Key: 'WAR'             Result: 'KBEQDJBHCKFRWAJ YZ MMPIIBCQAX DTRA ZVCEJOR KRQ JVFNOD HWH IOCDQEV SE AMWVGETQ'
 
python Vigenere.py -d -F wordlist.dic -f in -D english.dic|grep -v 'Score: 0'
 

[ # 4        ]  Score: 2    Key: 'ENIGMA'          Result: 'CONGRATULATIONS ON DECRYPTING THIS MESSAGE THE ANSWER YOU REQUIRE IS REJEWSKI'


   =>   Écrit par : Nicolas, le 13 juin 2016


 
Mots clés :  
  crypto 
  
  python 
    >   Articles connexes :

Cheat SHeet OpenSSL



Chiffrement multicouche



Trim (ou strip) pour votre terminal


Supprimer les espaces, tabulation et sauts de lignes en début et fin de ligne peut être très utiles lors de l'utilisation courante du...

1183950