2016-12-07 17 views
1

MISE À JOUR: Problem solvedLooping OpenSSL SHA512 en C donne des résultats différents de PHP

Comme commenté ci-dessous par plusieurs personnes généreuses, le problème était lié aux fonctions de chaîne utilisées lorsque le traitement des octets bruts. La principale question était l'utilisation de sprintf dans la boucle, qui maintenant j'ai changé pour memmove. code mis à jour suit:

#include <stdio.h> 
#include <string.h> 
#include <math.h> 
#include <openssl/evp.h> 
#include <openssl/bio.h> 

/* 
    Don't forget the compile switches: 
    gcc sha.c -lssl -lcrypto -lm -o sha 
*/ 
typedef struct { 
    unsigned char raw_hash[EVP_MAX_MD_SIZE]; 
    size_t hash_len; 
} HashResult; 


/* 
    adapted from https://gist.github.com/barrysteyn/4409525 
*/ 
int Base64Encode(const char* message, unsigned int message_size, char** buffer) { //Encodes a string to base64 
    BIO *bio, *b64; 
    FILE* stream; 
    int encodedSize = 4*ceil((double)message_size/3); 
    *buffer = (char *)malloc(encodedSize+1); 

    stream = fmemopen(*buffer, encodedSize+1, "w"); 
    b64 = BIO_new(BIO_f_base64()); 
    bio = BIO_new_fp(stream, BIO_NOCLOSE); 
    bio = BIO_push(b64, bio); 
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line 
    BIO_write(bio, message, message_size); 
    BIO_flush(bio); 
    BIO_free_all(bio); 
    fclose(stream); 

    return (0); //success 
} 


HashResult HashThis(char message[], int m_len, EVP_MD_CTX mdctx) { 
    unsigned char md_value[EVP_MAX_MD_SIZE]; 
    int md_len; 
    EVP_DigestInit_ex(&mdctx, EVP_sha512(), NULL); 
    EVP_DigestUpdate(&mdctx, message, m_len); 
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len); 

    HashResult hash; 
    memcpy(hash.raw_hash, md_value, md_len); 
    hash.hash_len = md_len; 

    return hash; 
} 


main(int argc, char *argv[]) 
{ 
    int i, l; 
    char salt[256] = "SALT"; 
    char pass[256] = "PASSWORD"; 
    char salted[512]; 
    char digest[512]; 
    char* base64EncodeOutput; 
    sprintf(salted, "%s{%s}", pass, salt); 
    printf("C: Salted is: >>>>>>%s<<<<<<\n", salted); 

    EVP_MD_CTX mdctx; 
    OpenSSL_add_all_digests(); 
    EVP_MD_CTX_init(&mdctx); 

    int s_len = strlen(salted); 
    HashResult h_result = HashThis(salted, s_len, mdctx); 
    memcpy(digest, h_result.raw_hash, h_result.hash_len); 

    for(i = 1; i < 20; i++){ 
     memmove(digest+h_result.hash_len, salted, s_len); 
     l = h_result.hash_len; 
     h_result.hash_len = 0; 
     memset(h_result.raw_hash, 0, l); 
     h_result = HashThis(digest, (int)l+s_len, mdctx); 
     memset(digest, 0, 512); 
     memcpy(digest, h_result.raw_hash, h_result.hash_len); 

     memset(base64EncodeOutput, 0, strlen(base64EncodeOutput)); 
     Base64Encode(digest, l, &base64EncodeOutput); 
     printf("%d => %s\n", i, base64EncodeOutput); 
    } 

    EVP_MD_CTX_cleanup(&mdctx); 
} 

POST ORIGINAL:

Je suis en train de mettre en œuvre en C la même clé d'étirement comme cela se fait en PHP par encodeur de mot de passe par défaut de Symfony:

<?php 
$password = "PASSWORD"; 
$salt = "SALT"; 
$salted = $password."{".$salt."}"; 
$digest = hash("sha512", $salted, true); 
echo "PHP: Salted is: >>>>>>$salted<<<<<<\n"; 

for ($i = 1; $i < 20; ++$i) { 
    $digest = hash("sha512", $digest.$salted, true); 
    $encoded_password = base64_encode($digest); 
    echo "$i => $encoded_password\n"; 
} 
?> 

... essayer ceci:

#include <stdio.h> 
#include <string.h> 
#include <math.h> 
#include <openssl/evp.h> 
#include <openssl/bio.h> 

/* 
    Don't forget the compile switches: 
    gcc sha.c -lssl -lcrypto -lm -o sha 
*/ 
typedef struct { 
    unsigned char raw_hash[EVP_MAX_MD_SIZE]; 
    size_t hash_len; 
} HashResult; 


/* 
    adapted from https://gist.github.com/barrysteyn/4409525 
*/ 
int Base64Encode(const char* message, unsigned int message_size, char** buffer) { //Encodes a string to base64 
    BIO *bio, *b64; 
    FILE* stream; 
    int encodedSize = 4*ceil((double)message_size/3); 
    *buffer = (char *)malloc(encodedSize+1); 

    stream = fmemopen(*buffer, encodedSize+1, "w"); 
    b64 = BIO_new(BIO_f_base64()); 
    bio = BIO_new_fp(stream, BIO_NOCLOSE); 
    bio = BIO_push(b64, bio); 
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line 
    BIO_write(bio, message, message_size); 
    BIO_flush(bio); 
    BIO_free_all(bio); 
    fclose(stream); 

    return (0); //success 
} 


HashResult HashThis(char message[], EVP_MD_CTX mdctx) { 
    unsigned char md_value[EVP_MAX_MD_SIZE]; 
    int md_len; 
    EVP_DigestInit_ex(&mdctx, EVP_sha512(), NULL); 
    EVP_DigestUpdate(&mdctx, message, strlen(message)); 
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len); 

    HashResult hash; 
    memcpy(hash.raw_hash, md_value, md_len); 
    hash.hash_len = md_len; 

    return hash; 
} 


main(int argc, char *argv[]) 
{ 
    int i, l; 
    char salt[256] = "SALT"; 
    char pass[256] = "PASSWORD"; 
    char salted[512]; 
    char digest[512]; 
    char* base64EncodeOutput; 
    sprintf(salted, "%s{%s}", pass, salt); 
    printf("C: Salted is: >>>>>>%s<<<<<<\n", salted); 

    EVP_MD_CTX mdctx; 
    OpenSSL_add_all_digests(); 
    EVP_MD_CTX_init(&mdctx); 

    HashResult h_result = HashThis(salted, mdctx); 
    memcpy(digest, h_result.raw_hash, h_result.hash_len); 

    for(i = 1; i < 20; i++){ 
     sprintf(digest, "%s%s", digest, salted); 
     l = h_result.hash_len; 
     h_result.hash_len = 0; 
     memset(h_result.raw_hash, 0, l); 
     h_result = HashThis(digest, mdctx); 
     memset(digest, 0, 512); 
     memcpy(digest, h_result.raw_hash, sizeof(h_result.raw_hash)); 

     memset(base64EncodeOutput, 0, strlen(base64EncodeOutput)); 
     Base64Encode(digest, l, &base64EncodeOutput); 
     printf("%d => %s\n", i, base64EncodeOutput); 
    } 

    EVP_MD_CTX_cleanup(&mdctx); 
} 

... donne les résultats suivants:

C: Salted is: >>>>>>PASSWORD{SALT}<<<<<< 
1 => 2yqDGoZ6NrdAKeS/yf7fCT/Zbv0/1Wa7cGwiy1pOvTpFE/I2Xfpajh8ukRhkM6j/8rv90C02ISeaz8K9awJLzw== 
2 => QVn8YydCA/9J5j8YTnUlnDXtqq0yNRPVz2m1QFkZ7fwQBWY4rgjP/JUCIjQbL4JRyIZATf3Bsnh0OfhaT52f/A== 
3 => ixpdJ4TaAY5POys95nhtU0Ghbu+yDgch3PL0UsPktxVUa5igEEdRmzMH5JZH7SrTkBaHUCa9ThKiSfA/TdbPog== 
4 => Am1dkcqXZkXOfDuwsj/VaZy3j3CQnzDzbj1B4g4/dkCJ5g/0nXAti7PKdo5oxm8GIv3AoHHW6eldTbwGj3IgzA== 
5 => mrfwPBiT3+TDl41xcf34p0A+eNHP18qWzm0uwOpzAarkfemzV5xsnz/x2QxuE4V7vNgYB8pVV6mYqRQkqitQRA== 
6 => JIGX+XD6XVaPwP3LuJO/OToef2jBiCq70mKyg6PmvUARigS5VkZMrcbnI/PXdHXrZ081fVMYavJRsXJiXRhiaQ== 
7 => oqU+PpM+HqJmUKcmOUMtIxvPgsCNyJ4zo+986ksr+Wvjp6ejDezFS49NuUXxi03GIj0ueLJxdPlIABvEBpd6RQ== 
8 => lg8/4/xhjb0IIBndLnH00UM6Umyq5NrtwrwXcHCFgoRJK54m9sIUgtsPlJd7N3F1RDCoRhQBmXzrTz1vPXkQYQ== 
9 => 2VAoIXuK960520NAL8iQUIbsTT4LRoEl5drxTXDfBEAPxCX+cA9hRKo2VTollak8x9VKTuzmR8c4zEKZhFlYAA== 
10 => TxFIQe3ynULLQFyePIJq7v3dybsMMp9krpISG5UsR3qhXkcC50RwAH90n2LA7isxS9Cn2wiHbgKi3v4mLaWnWA== 
11 => yhsHdTR7tlxZpoG2LsJWcG9UrNNsCgFf8cfLd/duwRNeD08aKuChv9hSpQAaXAKkkGlqqApmUGDu0G+gRVbLhg== 
12 => SqJfMgE5WJoc5ImGoDaXhiYCoXmxVnBA3rDcGHC975Q8mtJMxpU4nxSe67dq+pSH5bpR02Se5QXypHeI/PwGLg== 
13 => kbU6SUbAQhcysnw6O3RsjeX1xwKwd9j7L1ejJhhu1APa4ZzjFQmyFX3pHG7tnBitPPXRKxbgu49dRUZOtrtHgA== 
14 => K4r4AxmWTZIT7YA+BaGrVWCrdjFk2EiIK+s352FZeAmzDUpiJe8wC6DuVYwfmY8z3krmYlw9k+cHvfAlDFVwZg== 
15 => h7qPJz5mhzWPfeiQ+/quMWPmmb8yVjBc8KNvRN95h7Ycw7/nAj9+E19M2q1OaaJnT8xJ/ZzYUM4BV/vSol0Wpg== 
16 => WHTn5zz5JY/x0iQf3J0rceaaa5d0J3kPhChrQZsI7t/OU1RSSuumsiEzrPs4m/p/RsCTbI1XBsydoHzOr7Xf8A== 
17 => 5BTyu5Iujc6g2j7OhGAQJWqMyqC75lbEXCxUnixB1tse7YuhcrSD4Q977ijC8WGjt+dTxI4XiNWx8pR7p4ixoA== 
18 => 0j+GqFg75KPJgeg0f4Tvhr95qNWgyQT8eiK+kRGatXvnO0Guq0LdJlw6LwA2Ymfhr+GBy1HVmahCuzWTjxKTNg== 
19 => OGFBWgdqCjkkLSSbxywIekHqVXaXBHbm3NrxVYb+xPELr1efA/0L6S0xjynHH+NxIQ1cyQYlGeMAh+Ks3Rd08Q== 


PHP: Salted is: >>>>>>PASSWORD{SALT}<<<<<< 
1 => 2yqDGoZ6NrdAKeS/yf7fCT/Zbv0/1Wa7cGwiy1pOvTpFE/I2Xfpajh8ukRhkM6j/8rv90C02ISeaz8K9awJLzw== 
2 => QVn8YydCA/9J5j8YTnUlnDXtqq0yNRPVz2m1QFkZ7fwQBWY4rgjP/JUCIjQbL4JRyIZATf3Bsnh0OfhaT52f/A== 
3 => ixpdJ4TaAY5POys95nhtU0Ghbu+yDgch3PL0UsPktxVUa5igEEdRmzMH5JZH7SrTkBaHUCa9ThKiSfA/TdbPog== 
4 => Am1dkcqXZkXOfDuwsj/VaZy3j3CQnzDzbj1B4g4/dkCJ5g/0nXAti7PKdo5oxm8GIv3AoHHW6eldTbwGj3IgzA== 
5 => mrfwPBiT3+TDl41xcf34p0A+eNHP18qWzm0uwOpzAarkfemzV5xsnz/x2QxuE4V7vNgYB8pVV6mYqRQkqitQRA== 
6 => JIGX+XD6XVaPwP3LuJO/OToef2jBiCq70mKyg6PmvUARigS5VkZMrcbnI/PXdHXrZ081fVMYavJRsXJiXRhiaQ== 
7 => oqU+PpM+HqJmUKcmOUMtIxvPgsCNyJ4zo+986ksr+Wvjp6ejDezFS49NuUXxi03GIj0ueLJxdPlIABvEBpd6RQ== 
8 => nf9QhPhXnG7Fnh0t7YRXnfq/JlBUUogt9A8U+7aTA2A834c8SKiGqMgXqm7K7LUPHw3F8jwYxeMyXktPvUmMQQ== 
9 => QvttW+hXvBL2DLA5qCfq2205C/6A+YhYRA4YY63Fb7kqGYq3vrQIiSr/xsl/o8HCZr1KZ+lvNw4+ds/r/yqmBg== 
10 => tP0kRYQ1k3VAWXGqkHVh+i00e8WMODwmSh9UHtIcJm97sKVpum6iUzfKSEEHWbfjyUGG2P/+jgZLOe4LV1Rmig== 
11 => Wxmdu8t1VCMf/6Inax8jCzCSOUEwiDDugoQafE4lYN8k5NkCXUyIvXINcg0Di5ayW0NnxNuOEmmXR6rdTopyrA== 
12 => cNUPNmfJyCBZ6zKVaB2UCiiKyKzNKREPv7cBFCJFdrCB4t1Vqaw3TmldrjOiclJ3+w3tx4rTn2P1K1nP2SMcKg== 
13 => AT1LD3sETQe50HmVcHmqgY6emY+sT0OZPSIRffKjHfV1xktejbQnGE1evfrls5MpacULmzgNJccjsbWnDomsVA== 
14 => Um02XaFEiRm7oxQAQ7pUsxXxnhI9M6xSymapkKPrHBmhjrgcSPimMQ9tUi9Vc7H5OJlAvW0svM2e45pwZfxh+w== 
15 => 68vct/q024/3EppVZo4fw4vWI2IYN/99RsjI7ebvrv6GZL0xwqV3ERXynGuLdTlILwQyovM9QA7tvRNduu3qqQ== 
16 => PRfC+T2nLT9NRk/k+/XZ/UoNHYWGJR7naRLSX16+++rzjFVDMOnrQYFqEHWf+qTxqPMrS2NmyoD4P9pNr5d16A== 
17 => N3l3MBljhgzNsd7K3x6dU9btwAlTaJMk/8S7Jp9ICrOss6FVc+hMKYkUuiuE1vT+P3DK6s+NeArWS8/DtBGyug== 
18 => ihidFTx2BPBhHvq0WZ9yVEPoYciKApNsm9mSvSArZsf75rWrJRFA1fluusKllwNXPvbZinLczd8d8EQLNnsG5A== 
19 => EDo6YqOQaUmd0Vp8cGZPe5G4Dta2j/JFtc4W4aYQLo5+OvKdolzLu6YLK3GjKHCJdpbj1fUsH7sKxH98UyFhxA== 

les digestions premières délivrer montrera que par itération 8 de la digestion commence et se termine égale à celle en PHP, mais il y a quelques octets différents au milieu . Des idées pour lesquelles cela se passe? Comme tout le monde a connu des résultats similaires? J'ai besoin de faire cela pour pouvoir hacher les mots de passe sur un système existant. Toute aide sera grandement appréciée.

+1

'memcpy (digérer, h_result.raw_hash, sizeof (h_result.raw_hash));' <- ne doit pas être que 'h_result.hash_len'? Sinon, vous pourriez lire la mémoire non initialisée. – immibis

+2

Voici un indice: le résumé de l'itération 7 (le dernier avant qu'ils divergent) contient un octet zéro. – matt

+0

Merci pour le heads-up! – Yoshimitsu

Répondre

1

Ne pas utiliser une chaîne fonctions basées sur des données binaires, telles que:

strlen(message) 

ou votre code échouera.

+0

Un conseil: quand quelqu'un vous pose une question à propos de C, dans une salle comme celle-ci, la bonne réponse n'est jamais "utiliser une autre langue". Si vous lisez attentivement mon OP, vous remarquerez que je le fais afin de migrer les données d'un ancien système (sur ce même système). En fait, j'ai seulement fait cette erreur (stupide) exactement parce que je suis passé à d'autres langues il y a longtemps. En y repensant, la dernière fois que j'ai programmé en C était précisément il y a 28 ans. – Yoshimitsu