Tous les liens portant le nom d'une classe Qt seront des liens vers la doc' de Qt 4.6 !
Bon, c'est fini avec la théorie, cette fois, on va vraiment programmer !
Pour hacher, on va utiliser une classe du doux nom (un peu long aussi) de
QCryptographicHash. Tout se fera via la méthode statique
hash.
Voyons déjà son prototype :
Code : C++ | QByteArray QCryptographicHash::hash ( const QByteArray & data, Algorithm method ) [static]
|
On voit donc plusieurs choses :
- Cette méthode est statique, mais ça je vous l'ai déjà dit
. Pour rappel, une méthode statique peut être appelée sans avoir créé d'objet, avec Classe::methode()
.
- La méthode retourne un QByteArray, soit un tableau d'octets.
- Elle prend en premier paramètre un autre QByteArray, qui ne sera pas modifié (const).
- Elle prend en second paramètre Algorithm, qui est une énumération définie dans QCryptographicHash.
Détaillons ses paramètres :
- data est tout simplement ce que la fonction va chiffrer.
- method est la méthode de hachage. Car oui, il y a plusieurs méthodes !
Reprenons donc le code de base de Qt :
Code : C++ | #include <QApplication>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget w;
w.show();
return app.exec();
}
|
On ne va ici utiliser que le main.
Ajoutons la fonction de hachage :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include <QApplication>
#include <QWidget>
#include <QCryptographicHash>
#include <QByteArray>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget w;
QByteArray ba = QCryptographicHash::hash(/*arguments*/);
w.show();
return app.exec();
}
|
Eh, au fait, tu nous as toujours pas dit qu'est-ce qu'on met comme arguments ! Et si j'ai pas de QByteArray, mais que je veux hacher... Je sais pas, moi ! Une chaine !
Et puis, d'abord, on met quoi en deuxième argument, concrètement ?
Je vais commencer par répondre à la première,
parce que c'est la plus simple pour faire ça dans l'ordre :
Pour envoyer une chaine de caractères (ce qui sera le cas si on veut hacher un mot de passe, par exemple), il faut que ça soit une QString, et envoyer à
hash() sa conversion en UTF-8 :
Code : C++ | QCryptographicHash(chaine.toUtf8(), /*arg 2*/); // chaine est une QString
|
Ensuite, pour les différentes méthodes. Qt en propose à ce jour 3 :
- En MD4 (wikipedia) : Cette méthode n'est pas sûre, et peut être cassée, mais elle a l'avantage d'être rapide. Dans l'absolu, mieux vaut éviter de l'utiliser, sauf si la rapidité de l'algorithme est vraiment importante. Pour l'utiliser, le second paramètre est QCryptographicHash::Md4.
- En MD5 (wikipedia) : Une méthode assez sûre, bien qu'elle ne le soit de moins en moins avec l'apparition de "dictionnaires Md5/texte", et la possibilité de générer des collisions (merci à Phacog pour l'info sur les collisions !). Pour l'utiliser, le second paramètre est QCryptographicHash::Md5.
- En SHA-1 (wikipedia) : La méthode considérée comme la plus sûre des trois, et celle que je vous conseille d'utiliser. Pour l'utiliser, le second paramètre est QCryptographicHash::Sha1.
Essayez-donc de hacher en SHA-1 une chaine appelée
chaine et définie un peu plus haut dans le code ! À vous de jouer !
Secret (cliquez pour afficher)Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | #include <QApplication>
#include <QWidget>
#include <QCryptographicHash>
#include <QByteArray>
#include <QString>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget w;
QString chaine="Ceci sera haché.";
QByteArray ba = QCryptographicHash::hash(chaine.toUtf8(), QCryptographicHash::Sha1);
w.show();
return app.exec();
}
|
Et voilà ! Vous avez haché votre chaine !
J'ai essayé d'afficher le QByteArray dans un QMessageBox. Ça m'affiche un truc bizarre, plein de caractères spéciaux. Ça ressemble à ça un hash ?
Non

. C'est normal que ça affiche ça, car le retour de
hash n'est PAS une QString ! Pour le convertir en QString, il faut utiliser la méthode
toHex() :
Code : C++ | QString hash = ba.toHex();
|
Là, vous obtiendrez une chaine qui ressemble à
0e6d2d873c7ec7ce703e48b009723c9b820f29bd. Eh bien, ceci est votre hash !
Si on résume le code, on a donc :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | #include <QApplication>
#include <QWidget>
#include <QCryptographicHash>
#include <QByteArray>
#include <QString>
#include <QMessageBox>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget w;
QString chaine="Ceci sera haché."; // On crée la chaine à hacher
QByteArray ba = QCryptographicHash::hash(chaine.toUtf8(), QCryptographicHash::Sha1); // on la hache
QString out=ba.toHex(); // on convertit le hash en QString
QMessageBox::information(&w, "test", out); // on l'affiche
w.show();
return app.exec();
}
|
Plus de sécurité ?
Comment ça, "plus de sécurité" ? Tu nous avais dit que c'est indécryptable ! Tu nous aurais menti ?
D'une certaine manière, non. En effet, c'est, à proprement parler, indéchiffrable. Mais... Il existe des correspondances entre les mots courants et leurs hachages MD5/SHA-1 ou autres. Évidemment, ces bases de données ne sont pas complètes ! Mais si votre hash est dedans... Pour cela, il a été mis au point une technique permettant
d'assaisonner les aliments de rendre ces méthodes quasi-inutiles, et de rendre plus difficiles les attaques par force brute (test de toutes les combinaisons) : le
salage (
wikipedia).
Cette technique est très simple : pour compliquer les données à hacher, on rajoute avant ou après (ou les deux) des données qui sont toujours les mêmes. Ces données sont appelées
sels.
Ainsi, si on veut hacher la chaine "siteduzero" avec le sel "GRAINDESEL" (où GRAINDESEL est un define d'une chaîne de caractères, méthode que je vous recommande) avant, on mettra en argument "data" de la fonction
hash QString(GRAINDESEL"siteduzero").toUtf8
Il y a même encore mieux : hacher les sels eux-mêmes, de préférence avec un autre algorithme de hachage (par exemple, MD5 si vous utilisez du SHA-1 pour le hash final). Vous pouvez faire de même avec votre chaîne à chiffrer elle même :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | #include <QApplication>
#include <QWidget>
#include <QCryptographicHash>
#include <QByteArray>
#include <QString>
#include <QMessageBox>
#define SEL_AVANT "D4Dqdz68$E" // une technique approuvée pour vos sels est de s'endormir sur le clavier.
#define SEL_APRES "7HHo£hh7YH" // Si ils ne veulent rien dire, c'est mieux.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget w;
QString chaine="Ceci sera haché."; // On crée la chaine à hacher
QByteArray ba = QCryptographicHash::hash(QByteArray(QCryptographicHash::hash(QString(SEL_AVANT).toUtf8(), QCryptographicHash::Md5) +
QCryptographicHash::hash(chaine.toUtf8(), QCryptographicHash::Md5) +
QCryptographicHash::hash(QString(SEL_APRES).toUtf8(), QCryptographicHash::Md5)), QCryptographicHash::Sha1); // on la hache
QString out=ba.toHex(); // on convertit le hash en QString
QMessageBox::information(&w, "test", out); // on l'affiche
w.show();
return app.exec();
}
|
Nous sommes donc au final arrivés à un code pas si gros, mais très sécurisé ! Par contre, il faut savoir une chose : plus vous mettez de sécurités, sels, hachages de sels, etc., plus le temps de calcul est long ! Pour hacher vos sels, l'utilisation du MD4 est éventuellement possible, si vous trouvez que le temps de calcul est trop long (mais franchement, vous devriez même pas le voir passer, sauf si vous générez 100 000 hashs, et encore).