Crypto PBKDF2 Grub2
Cet algorithme est utilisé pour lutter contre le brute force de mots de passe (ou clefs) . Il augmente considérablement les temps de calculs pour obtenir un hash.
on le retrouve notamment dans :
grub2
wpa
truecrypt
Dans ces 3 exemples, PBKDF2 repose sur l’algorithme cryptographique HMAC que l’on combine dans une fonction (F) itérative à base de xor.
Théorie
DK = PBKDF2(PRF, Password, Salt, itérations, dkLen)
PRF : PRF est une fonction pseudo-aléatoire composé de deux paramètres.
on utilise généralement HMAC comme PRF
Password : le mot de passe en clair
Salt: le sel
itérations : nombre d’itération
dkLen : la longueur en octets du résultat (DK – Derived Key)
Dk : Le résultat appelé DerivedKey => le hash du mot de passe
Formule
F( Password, Salt, c, i ) = U1 xor U2 xor... ...xor Uc
c = nombre d’ itération
i = index itération
U1 = PRF(Password, Salt || i)
U2 = PRF(Password, U1)
Uc = PRF(Password, Uc-1)
La fonction F réalise un « xor » entre les différentes chaines U1 à Uc.
c est égale au nombre d’ itérations.
Calcul de U1 (1ere itération)
- 1er paramètre : password
- 2ieme paramètre : salt || i ( || signifie concaténation )
- i est l’ index d’ itération, à la première itération i vaut 1
- i est codé sur 4 octets (big-endian 32 bits) cela devient : « \x00\x00\x00\x01 »
- Ces 2 paramètres servent à calculer U1
Calcul de U2…..Uc( itérations suivantes):
- 1er paramètre : password ( constant, ne change pas jusqu’à la dernière itération)
- 2ieme paramètre : correspond à U1(calculé précédemment )
et on réalise un xor entre les Ux comme ceci
entre U1 et U2
puis ensuite entre le résultat précédent (U1 xor U2) et U3
et ainsi de suite
Exemple pratique – Grub2
La suite de cet article est basée sur le protocole de hashage de mots de passe utilisé par GRUB2.
par défaut, grub2 exécute (10 mille) itérations et la longueur du salt est égale à 64 octets.
La commande grub-mkpasswd-pbkdf2 permet de générer un hash pbkdf2
exemple de résultat :
Détaillons chaque champs:
- Le mot de passe que j’ ai saisi est : 12345678
- sha512 : pbkdf2 utilise le protocole sha512 comme PRF
- 10000 : nombre d’ itérations (10 mille)
- salt : 64 octets
- le hash du mot de passe : 64 octets
Les champs sont séparés par des points (.).
Par souci de clarté j’ ai découpé chaque chaine en 4 partie , mais en réalité tout est sur une même ligne.
Rappel :
DK = PBKDF2(PRF, Password, Salt, itérations, dkLen)
Dans le cadre de grub2 :
- la fonction Prf est la fonction cryptographique HMAC-SHA512.
- Le nombre d’ itérations est fixé à 10000
- le résultats est sur 64 octets
Donc la formule devient :
DK = PBKDF2(HMAC-SHA512, password, salt, 10000, 64)
calcul de la 1ere itération :
U1 = HMAC-SHA512(« 12345678 », »\0x2D\0xD6…..\0xDE\x08\x00\x00\x00\x01″)
Rappel : l’indice (\x00\x00\x00\x01) est concaténé au salt
calcul 2ieme itération et itérations suivantes :
U2 = HMAC-SHA512(« 12345678 »,U1)
…
…
Uc = HMAC-SHA512(« 12345678 »,Uc-1 )
Programme écrit en python qui génère un hash PBKDF2
Programme écrit en python qui génère un hash PBKDF2
j’ ai testé ce programme sur kali 1.0.3.
Généré un hash avec la commande grub2 ci-dessous , saisir le mot de passe « 12345678 » :
grub-mkpasswd-pbkdf2 -s 3
-s : nombre d’ octets du salt
important:
Dans cet exemple j’ai réduit longueur du salt pour éviter par la suite des saisis au clavier fastidieuses.
Avant de lancer le programme, repérer la ligne 51 (surlignée) pour déclarer les bons paramètres. Vous devriez normalement changer uniquement le salt ( en bleu).
resultat = PBKDF2(« 12345678″, »\xF2\xB0\xF0 »,10000,64)
Pour sélectionner tout le code , double-cliquez dans la fenêtre.
# -*- coding: utf-8 -*-
import struct
import timeit
import hashlib
import hmac
import binascii
# fonctions
def hmacfunc(key,message):
# key = mot de passe
# message = salt
return hmac.new(key,message,hashlib.sha512).digest()
def xor_string(str1, str2):
# TODO: slow!
str3 = ''
for i in xrange(len(str1)):
str3 += chr(ord(str1[i]) ^ ord(str2[i]))
return str3
def PBKDF2(password, salt, iterations, derivedlen):
def F(P, S, c, i):
U_prev = hmacfunc(P, S + struct.pack('>L', i))
res = U_prev
for cc in xrange(2, c+1):
U_c = hmacfunc(P, U_prev)
res = xor_string(res, U_c)
U_prev = U_c
return res
tmp = ''
i = 1
while True:
tmp += str(F(password, salt, iterations, i))
if len(tmp) > derivedlen:
break
i += 1
return tmp[0:(derivedlen)]
# grub-mkpasswd-pbkdf2 -s 3
# pensez à changer le mot de passe,le salt et le nombre d' iteration
# dans cet exemple
# le mot de passe est "password"
# le salt est "\x4D\x06\x01"
# le nombre d' itération est : 10000
resultat = PBKDF2("123", "\xA2\xC8\x73", 10000, 64)
#arg01 : mot de pase
#arg02 : salt
#arg03 : iteration
#arg04 : taille en octets du resultat
# commande a taper en ligner de commande pour timer la durée de la fonction
# pbkdf2 est le nom du programme a timer (sans l' extension .py)
#import timeit
#from pbkdf2 import *
#timeit.Timer(stmt='PBKDF2("password", "\xF2\xB0\xF0", 10000, 64)',setup='from pbkdf2 import PBKDF2,hmacfunc').timeit(1)
print "resultat " + binascii.hexlify(resultat).upper()
Le protocole WPA2 utilise également le protocole PBKDF2. Voici les paramètres utilisés
DK = PBKDF2(HMAC−SHA1, passphrase, ssid, 4096, 256)
la fonction PRF est dans ce cas HMAC-SHA1 le ssid fait office de salt le nombre d’ itération s’élève à 4096 le taille du résultat est égale à 256 octets.
Un challenge pour la fin
Enoncé : grub-mkpasswd-pbkdf2 -s 3 password : ???
#
# Your PBKDF2 is grub.pbkdf2.sha512.10000.BBD751.AFC96786A477E787381FBB4AE0B42DAA2E56B25C0A285C653C3452D0A8A31FD42E83736E53BE1CA8380E4C90C791AFA80ACE59DCB285E0EB2F9D018B1D55233E
#
le mot de passe à trouver est composé de 3 chiffres (001 à 999)