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.
'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
Voici un indice: le résumé de l'itération 7 (le dernier avant qu'ils divergent) contient un octet zéro. – matt
Merci pour le heads-up! – Yoshimitsu