Erreur dans mon code SHA-1 [Résolu]

Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 2 mars 2011 à 19:24 - Dernière réponse :
Messages postés
3829
Date d'inscription
dimanche 12 décembre 2004
Dernière intervention
5 novembre 2018
- 5 mars 2011 à 15:56
Bonjour,

Je viens d'essayer de développer une application retournant la valeur hachée (SHA-1) d'un fichier, cependant malgré de nombreuses relectures du code et des documents disponibles sur internet relatifs à ce sujet, je ne parviens pas à trouver l'erreur.

Voici le code (il n'est pas optimisé, j'avais juste pour objectif de reprendre le c/c++ en créant un petit programme avec les connaissances qui me restaient à propos du langage):
string SHA1( string nomFichier ) {

    /* Obtention des Mi (512 bits soit 64 octets) */
    /*
     - 1 est ajouté à la fin de x
     - On ajoute des 0 à la fin de x pour que ||x|| =  512n − 64
     - ||x|| est écrite en base 2 sur 64 bits, qui sont rajoutés à la fin du mot ci-dessus
    */

    ifstream monFlux;
    monFlux.open( nomFichier.c_str() );
    if( monFlux ) {
        monFlux.seekg (0, ios::end);
        unsigned int length = monFlux.tellg(); /* ATTENTION: au-delà de 2^32 :'( */
        monFlux.seekg (0, ios::beg);

        /* 512 bits = 64 octets */
        /*  64 bits =  8 octets */
        int nbLectures = ( length+1 +8 )/64;
        if( ( length+1 +8 )%64 > 0 ) ++nbLectures;

        unsigned int h0 = 0x67452301; /* unsigned int: 32 bits */
        unsigned int h1 = 0xEFCDAB89; /* http://www.commentcamarche.net/contents/cpp/cpptype.php3 */
        unsigned int h2 = 0x98BADCFE;
        unsigned int h3 = 0x10325476;
        unsigned int h4 = 0xC3D2E1F0;

        for( int i=0 ; i!=nbLectures ; ++i ) {

            int tailleLecture = 64; /* 64 octets */
            if( i nbLectures-1 ) tailleLecture length%64;

            char* buffer = new char[tailleLecture];
            monFlux.read( buffer, tailleLecture );

            unsigned int M[16]; /* 512 bits / 32 bits */
            for( int j=0 ; j!=16 ; ++j ) { M[j] = 0; }
            for( int t=0 ; t!=64 ; ++t ) {
                if( t < tailleLecture ) {
                    unsigned char tmp = *(buffer+t);
                    M[ t/4 ] += ( tmp << 8*( 3 - (t%4) ) );
                } else if( t == tailleLecture ) /* On ajoute le char: % 1000 0000 ie 128 */
                    M[ t/4 ] += ( 128 << 8*( 3 - (t%4) ) );
                /* length: "64" bits soit 2*32, on les ajoute après */
                /* else rien, on ajoute des 0 */
                if( i == nbLectures-1 ) {
                    /*M[ 14 ] = 0; length fait en réalité 32 bits */
                    M[15] = length;
                }
            }
            free( buffer );

            /* Obtient les Wt */
            unsigned int W[80];
            for( int t=0 ; t!=16 ; ++t ) { W[t] = M[t]; }
            for( int t=16 ; t!=80 ; ++t ) { W[t] = ROL32( W[t-3] xor W[t-8] xor W[t-14] xor W[t-16], 1 );  }

            /* A, B, C, D, E */
            unsigned int A = h0;
            unsigned int B = h1;
            unsigned int C = h2;
            unsigned int D = h3;
            unsigned int E = h4;

            /* Boucle sur t... */
            for( int t=0 ; t!=80 ; ++t ) {
                /*
                T = S5(A) + (ft(B,C,D) + Kt) + E + Wt
                E = D
                D = C
                C = S30(B)
                B = A
                A = T
                */
                unsigned int tmp;
                /* 19/ (B &#8743; C) or (¬B &#8743; D) *//* 39/ B xor C xor D *//* 59/ (B &#8743; C) or (B &#8743; D) or (C &#8743; D) *//* B xor C xor D */
                if( t <19 )      tmp ( (B & C) | ((~B) & D) )        + 0x5A827999;
                else if( t <39 ) tmp ( B ^ C ^ D )                   + 0x6ED9EBA1;
                else if( t <59 ) tmp ( (B & C) | (B & D) | (C & D) ) + 0x8F1BBCDC;
                else               tmp = ( B ^ C ^ D )                   + 0xCA62C1D6;

                unsigned int T = ROL32(A,5) + tmp + E + W[t];
                E = D;
                D = C;
                C = ROL32(B,30);
                B = A;
                A = T;
            }

            /* Ajouter A à H0, B à H1, C à H2, D à H3 et E à H4 */
            h0 += A;
            h1 += B;
            h2 += C;
            h3 += D;
            h4 += E;
        }

        monFlux.close();

        return hexa_of_valeurhachee( (unsigned int[]){h0,h1,h2,h3,h4} );
    } else return 0;
}


Le problème est qu'elle ne renvoie pas la bonne valeur hachée:
* Pour le fichier "test":
retour = 9b0decbd3c093f369d6d2462d784ad49a9ff4698
au lieu de = a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
* Pour le fichier "": le retour est correct da39a3ee5e6b4b0d3255bfef95601890afd80709

Merci d'avance et à bientôt...

Nico
PS: Articles concernant le hachage SHA-1:
http://en.wikipedia.org/wiki/SHA-1
http://fr.wikipedia.org/wiki/Sp%C3%A9cifications_SHA-1
http://www.sinfocol.org/herramientas/hashes.php
Afficher la suite 

Votre réponse

13 réponses

Meilleure réponse
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 19:32
3
Merci
Bingo !

Remplace simplement :
 M[15] = length;


Par :
 M[15] = length * 8;


Dans l'algo la taille à hacher est exprimée en nombre de bits et non en nombre de bytes.

good bytes:)

PS : au temps pour moi pour la fausse piste de l'endianness.

Merci cs_Lucky92 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 88 internautes ce mois-ci

Commenter la réponse de cs_Lucky92
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 2 mars 2011 à 22:39
0
Merci
Salut,

Je ne suis pas sûr de mon coup car j'ai survolé très vite ton problème et je n'ai pas eu le temps de tester, mais dans l'article wikipédia que tu cites, il est dit que les constantes sont fournies en big endian. Or, si tu utilises un PC, il y a forte chance que tu sois en little endian ; tu peux essayer de permuter les octets des constantes hexa.

@+.
Commenter la réponse de cs_Lucky92
Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 2 mars 2011 à 23:47
0
Merci
Bonjour,

Le projet a en effet été compilé sous Windows (avec CodeBlocks), mais je souhaitais également pouvoir le recompiler sous Linux (Ubuntu avec CodeBlocks (gcc)).

Comment faut-il procéder pour passer de big endian à little endian ?
Pourrais-je conserver le même code pour Linux ou faudra-t'il changer ceci d'une version à l'autre ?

Merci d'avance et à bientôt...
Nico
Commenter la réponse de ndubien
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 06:59
0
Merci
Salut,

L'endianness ne dépend ni de l'OS ni du compilateur mais de l'architecture matérielle. Elle correspond à la représentation des données en mémoire, et dans le monde PC, les données sont représentées en little endian.
Il suffit de permuter les octets dans les constantes comme ceci :

 unsigned int h0 = 0x01234567; //0x67452301; 
 unsigned int h1 = 0x89ABCDEF; //0xEFCDAB89; 
 unsigned int h2 = 0xFEDCBA98; //0x98BADCFE;
 unsigned int h3 = 0x76543210; //0x10325476;
 unsigned int h4 = 0xF0E1D2C3; //0xC3D2E1F0;


 if( t <19 )      tmp ( (B & C) | ((~B) & D) )        + 0x9979825A; //+ 0x5A827999;
 else if( t <39 ) tmp ( B ^ C ^ D )                   + 0xA1EBD96E; //+ 0x6ED9EBA1;
 else if( t <59 ) tmp ( (B & C) | (B & D) | (C & D) ) + 0xDCBC1B8F; //+ 0x8F1BBCDC;
 else               tmp = ( B ^ C ^ D )                   + 0xD6C162CA; //+ 0xCA62C1D6;


@+
Commenter la réponse de cs_Lucky92
Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 3 mars 2011 à 11:13
0
Merci
Bonjour,

Je viens d'essayer les modifications que vous m'avez suggéré, cependant le problème persiste, je n'obtiens toujours pas le bon résultat.

Merci d'avance et à bientôt... Nico
Commenter la réponse de ndubien
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 12:55
0
Merci
Peux-tu poster la macro ROL32 ?
Commenter la réponse de cs_Lucky92
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 13:06
0
Merci
..et l'opérateur ou la macro xor aussi.
Commenter la réponse de cs_Lucky92
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 13:09
0
Merci
...et la fonction hexa_of_valeurhachee aussi.
Commenter la réponse de cs_Lucky92
Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 3 mars 2011 à 16:05
0
Merci
Bonjour,

Voici les fonctions que vous m'avez demandé:
string hexa_of_uint( unsigned int entier ) {
    string hexa = "";
    for( int i=0 ; i!=8 ; ++i ) { /* entier: 32 bits, hexa: 4bits */
        switch( entier%16 ) {
            case 0:  hexa = "0" + hexa; break;
            case 1:  hexa = "1" + hexa; break;
            case 2:  hexa = "2" + hexa; break;
            case 3:  hexa = "3" + hexa; break;
            case 4:  hexa = "4" + hexa; break;
            case 5:  hexa = "5" + hexa; break;
            case 6:  hexa = "6" + hexa; break;
            case 7:  hexa = "7" + hexa; break;
            case 8:  hexa = "8" + hexa; break;
            case 9:  hexa = "9" + hexa; break;
            case 10: hexa = "a" + hexa; break;
            case 11: hexa = "b" + hexa; break;
            case 12: hexa = "c" + hexa; break;
            case 13: hexa = "d" + hexa; break;
            case 14: hexa = "e" + hexa; break;
            case 15: hexa = "f" + hexa; break;
            default: hexa = "*" + hexa; break;
        }
        entier /= 16;
    }
    return hexa;
}

string hexa_of_valeurhachee( unsigned int* valeurhacheee ) {
    string hexa = "";
    for( int i=0 ; i!= 5 ; ++i ) { hexa += hexa_of_uint( *(valeurhacheee+i) ); }
    return hexa;
}

et ROL32:
#define ROL32(x,b) (((x) << (b)) | ((x) >> (32 - (b))))


pour les fonctions xor, or et and j'utilise les fonctions de bases définies par le langage (xor:uint*uint->uint...).

Merci d'avance et à bientôt...
Nico
Commenter la réponse de ndubien
Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 3 mars 2011 à 20:54
0
Merci
Bonjour,

Je tenais à vous remercier pour votre aide, ça fonctionne parfaitement sur les deux exemples essayé, j'en essaierai d'autres, mais ça doit être correct. La prochaine fois j'essaierai de mieux lire et pour l'endianness et pour les bits.

Dernière question: j'utilise unsigned int pour avoir des variables de 32 bits, mais existe-t-il un type du genre uint32 (pour les opérations) et uint64 (pour length) afin d'être sûr d'avoir des variables de 32 bits (resp. 64 bits). Car sur un processeur 16 bits unsigned int est sur 16 bits, 32 bits sur un 32 bits donc 64 bits sur un 64 bits ?

Merci d'avance et à bientôt
Nico

Encore merci pour votre réponse :)
Commenter la réponse de ndubien
Messages postés
180
Date d'inscription
mercredi 22 décembre 2004
Dernière intervention
16 août 2012
- 3 mars 2011 à 22:45
0
Merci
Bonsoir,

"long" et "unsigned long" sont encodés sur 32 bits.
"long long" et "unsigned long long" sont encodés sur 64 bits.
Tu peux introduire des typedef à ta guise pour alléger le code.

@+
Commenter la réponse de cs_Lucky92
Messages postés
557
Date d'inscription
dimanche 25 septembre 2005
Dernière intervention
10 mai 2014
- 4 mars 2011 à 01:22
0
Merci
Merci et à bientôt ;)
Commenter la réponse de ndubien
Messages postés
3829
Date d'inscription
dimanche 12 décembre 2004
Dernière intervention
5 novembre 2018
- 5 mars 2011 à 15:56
0
Merci
Dans stdint.h tu as les types uint32_t, int32_t, uint64_t, int64_t, etc...

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.