web-dev-qa-db-fra.com

Comment chiffrer/déchiffrer des données en php?

Je suis actuellement étudiant et j'étudie le langage PHP. J'essaie de faire un cryptage/décryptage simple des données en PHP. J'ai fait des recherches en ligne et certaines d'entre elles étaient assez déroutantes (du moins pour moi).

Voici ce que j'essaie de faire:

J'ai une table composée de ces champs (UserID, Fname, Lname, Email, Password)

Ce que je veux, c’est que tous les champs soient chiffrés et ensuite déchiffrés (est-il possible d’utiliser sha256 pour le chiffrement/déchiffrement, s’il n’ya pas d’algorithme de chiffrement)

Une autre chose que je veux apprendre est la façon de créer un hash(sha256) à sens unique combiné à un bon "sel" . (Je veux simplement avoir une implémentation simple du cryptage/décryptage, hash(sha256)+salt) Monsieur/Madame, vos réponses seraient d'une grande aide et seraient très appréciées. Merci ++

102
Randel Ramirez

Avant-propos

En commençant par votre définition de table:

_- UserID
- Fname
- Lname
- Email
- Password
- IV
_

Voici les changements:

  1. Les champs Fname, Lname et Email seront cryptés à l'aide d'un chiffrement symétrique, fourni par OpenSSL ,
  2. Le champ IV stockera le vecteur d’initialisation utilisé pour le cryptage. Les besoins de stockage dépendent du chiffre et du mode utilisés. plus à ce sujet plus tard.
  3. Le champ Password sera haché en utilisant un hachage one-way password,

Cryptage

Chiffre et mode

Le choix du meilleur chiffrement et du meilleur mode de cryptage dépasse le cadre de cette réponse, mais le choix final affecte la taille de la clé de cryptage et du vecteur d'initialisation. pour cet article, nous utiliserons AES-256-CBC, qui a une taille de bloc fixe de 16 octets et une taille de clé de 16, 24 ou 32 octets.

Clé de chiffrement

Une bonne clé de cryptage est un blob binaire généré à partir d'un générateur de nombres aléatoires fiable. L'exemple suivant serait recommandé (> = 5.3):

_$key_size = 32; // 256 bits
$encryption_key = openssl_random_pseudo_bytes($key_size, $strong);
// $strong will be true if the key is crypto safe
_

Cela peut être fait une ou plusieurs fois (si vous souhaitez créer une chaîne de clés de chiffrement). Gardez-les aussi privés que possible.

IV

Le vecteur d’initialisation ajoute un caractère aléatoire au chiffrement et est requis pour le mode CBC. Ces valeurs doivent idéalement être utilisées une seule fois (techniquement une fois par clé de cryptage), de sorte qu'une mise à jour de n'importe quelle partie d'une ligne doit la régénérer.

Une fonction est fournie pour vous aider à générer le IV:

_$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);
_

Exemple

Cryptons le champ du nom en utilisant les versions précédentes _$encryption_key_ et _$iv_; Pour ce faire, nous devons compiler nos données à la taille du bloc:

_function pkcs7_pad($data, $size)
{
    $length = $size - strlen($data) % $size;
    return $data . str_repeat(chr($length), $length);
}

$name = 'Jack';
$enc_name = openssl_encrypt(
    pkcs7_pad($name, 16), // padded data
    'AES-256-CBC',        // cipher and mode
    $encryption_key,      // secret key
    0,                    // options (not used)
    $iv                   // initialisation vector
);
_

Besoins de stockage

La sortie chiffrée, comme le IV, est binaire; le stockage de ces valeurs dans une base de données peut être effectué à l'aide de types de colonne désignés, tels que BINARY ou VARBINARY.

La valeur de sortie, comme l'IV, est binaire; pour stocker ces valeurs dans MySQL, utilisez des colonnes BINARY OU VARBINARY . Si ce n'est pas une option, vous pouvez également convertir les données binaires en une représentation textuelle en utilisant base64_encode() ou bin2hex() , cela nécessite entre 33% et 100% plus d'espace de stockage.

Décryptage

Le déchiffrement des valeurs stockées est similaire:

_function pkcs7_unpad($data)
{
    return substr($data, 0, -ord($data[strlen($data) - 1]));
}

$row = $result->fetch(PDO::FETCH_ASSOC); // read from database result
// $enc_name = base64_decode($row['Name']);
// $enc_name = hex2bin($row['Name']);
$enc_name = $row['Name'];
// $iv = base64_decode($row['IV']);
// $iv = hex2bin($row['IV']);
$iv = $row['IV'];

$name = pkcs7_unpad(openssl_decrypt(
    $enc_name,
    'AES-256-CBC',
    $encryption_key,
    0,
    $iv
));
_

Cryptage authentifié

Vous pouvez améliorer encore l'intégrité du texte chiffré généré en ajoutant une signature générée à partir d'une clé secrète (différente de la clé de chiffrement) et du texte chiffré. Avant que le texte chiffré ne soit déchiffré, la signature est d'abord vérifiée (de préférence avec une méthode de comparaison à temps constant).

Exemple

_// generate once, keep safe
$auth_key = openssl_random_pseudo_bytes(32, $strong);

// authentication
$auth = hash_hmac('sha256', $enc_name, $auth_key, true);
$auth_enc_name = $auth . $enc_name;

// verification
$auth = substr($auth_enc_name, 0, 32);
$enc_name = substr($auth_enc_name, 32);
$actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);

if (hash_equals($auth, $actual_auth)) {
    // perform decryption
}
_

Voir aussi: hash_equals()

Hachage

L'enregistrement d'un mot de passe réversible dans votre base de données doit être évité autant que possible. vous souhaitez uniquement vérifier le mot de passe plutôt que de connaître son contenu. Si un utilisateur perd son mot de passe, il est préférable de lui permettre de le réinitialiser plutôt que de lui envoyer son mot de passe original (assurez-vous que la réinitialisation du mot de passe ne peut être effectuée que pendant un temps limité).

L'application d'une fonction de hachage est une opération à sens unique; ensuite, il peut être utilisé en toute sécurité pour la vérification sans révéler les données originales; pour les mots de passe, une méthode de force brute est une approche réalisable pour la découvrir en raison de sa longueur relativement courte et du choix de mot de passe médiocre de nombreuses personnes.

Des algorithmes de hachage tels que MD5 ou SHA1 ont été créés pour vérifier le contenu du fichier par rapport à une valeur de hachage connue. Ils sont grandement optimisés pour rendre cette vérification aussi rapide que possible tout en restant précise. Compte tenu de leur espace de sortie relativement limité, il était facile de créer une base de données avec des mots de passe connus et leurs sorties de hachage respectives, les tables Rainbow.

Ajouter un sel au mot de passe avant le hachage rendrait une table Rainbow inutile, mais les récents progrès matériels ont rendu les recherches en force brute une approche viable. C'est pourquoi vous avez besoin d'un algorithme de hachage délibérément lent et tout simplement impossible à optimiser. Il devrait également être en mesure d’augmenter la charge pour un matériel plus rapide sans affecter la possibilité de vérifier les hachages de mots de passe existants pour en assurer la pérennité.

Il existe actuellement deux choix populaires:

  1. PBKDF2 (Fonction de dérivation de clé basée sur un mot de passe v2)
  2. bcrypt (alias Blowfish)

Cette réponse utilisera un exemple avec bcrypt.

Génération

Un hash de mot de passe peut être généré comme ceci:

_$password = 'my password';
$random = openssl_random_pseudo_bytes(18);
$salt = sprintf('$2y$%02d$%s',
    13, // 2^n cost factor
    substr(strtr(base64_encode($random), '+', '.'), 0, 22)
);

$hash = crypt($password, $salt);
_

Le sel est généré avec openssl_random_pseudo_bytes() pour former un blob aléatoire de données, qui est ensuite exécuté via base64_encode() et strtr() pour correspondre à l'alphabet requis de _[A-Za-z0-9/.]_.

La fonction crypt() effectue le hachage en fonction de l'algorithme (_$2y$_ pour Blowfish), du facteur de coût (un facteur de 13 prend environ 0.40s sur une machine 3GHz) et du sel de 22 caractères. .

Validation

Une fois que vous avez récupéré la ligne contenant les informations utilisateur, vous validez le mot de passe de la manière suivante:

_$given_password = $_POST['password']; // the submitted password
$db_hash = $row['Password']; // field with the password hash

$given_hash = crypt($given_password, $db_hash);

if (isEqual($given_hash, $db_hash)) {
    // user password verified
}

// constant time string compare
function isEqual($str1, $str2)
{
    $n1 = strlen($str1);
    if (strlen($str2) != $n1) {
        return false;
    }
    for ($i = 0, $diff = 0; $i != $n1; ++$i) {
        $diff |= ord($str1[$i]) ^ ord($str2[$i]);
    }
    return !$diff;
}
_

Pour vérifier un mot de passe, vous appelez à nouveau crypt() mais vous transmettez la valeur de hachage calculée précédemment comme valeur du sel. La valeur de retour produit le même hash si le mot de passe donné correspond au hash. Pour vérifier le hachage, il est souvent recommandé d'utiliser une fonction de comparaison à temps constant pour éviter les attaques par minutage.

Hachage du mot de passe avec PHP 5.5

PHP 5.5 a introduit le fonctions de hachage de mot de passe que vous pouvez utiliser pour simplifier la méthode de hachage ci-dessus:

_$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);
_

Et en vérifiant:

_if (password_verify($given_password, $db_hash)) {
    // password valid
}
_

Voir aussi: password_hash() , password_verify()

283
Ja͢ck

Je pense que cela a déjà été répondu auparavant ... mais de toute façon, si vous voulez chiffrer/déchiffrer des données, vous ne pouvez pas utiliser SHA256

//Key
$key = 'SuperSecretKey';

//To Encrypt:
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, 'I want to encrypt this', MCRYPT_MODE_ECB);

//To Decrypt:
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB);
21
romo

Réponse contexte et explication

Pour comprendre cette question, vous devez d'abord comprendre ce qu'est SHA256. SHA256 est une fonction de hachage cryptographique. Une fonction de hachage cryptographique est une fonction unidirectionnelle, dont la sortie est sécurisée de manière cryptographique. Cela signifie qu'il est facile de calculer un hachage (équivalent à chiffrer des données), mais difficile d'obtenir l'entrée d'origine à l'aide du hachage (équivalent à déchiffrer les données). Étant donné que l'utilisation d'une fonction de hachage cryptographique signifie que le décryptage est infaisable en calcul, vous ne pouvez donc pas effectuer de décryptage avec SHA256. 

Ce que vous voulez utiliser est une fonction à double sens, mais plus précisément un Block Cipher. Une fonction qui permet à la fois le cryptage et le décryptage des données. Les fonctions mcrypt_encrypt et mcrypt_decrypt utilisent par défaut l'algorithme Blowfish. L'utilisation de mcrypt par PHP peut être trouvée dans ce manual . Une liste de définitions de chiffrement pour sélectionner le chiffrement utilisé par mcrypt existe également. Un wiki sur Blowfish est disponible sur Wikipedia . Un chiffrement de bloc chiffre l'entrée dans des blocs de taille et de position connues avec une clé connue, de sorte que les données puissent ensuite être déchiffrées à l'aide de la clé. C'est ce que SHA256 ne peut pas vous fournir.

Code

$key = 'ThisIsTheCipherKey';

$ciphertext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, 'This is plaintext.', MCRYPT_MODE_CFB);

$plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB);
14
cytinus

Voici un exemple utilisant openssl_encrypt 

//Encryption:
$textToEncrypt = "My Text to Encrypt";
$encryptionMethod = "AES-256-CBC";
$secretHash = "encryptionhash";
$iv = mcrypt_create_iv(16, MCRYPT_Rand);
$encryptedText = openssl_encrypt($textToEncrypt,$encryptionMethod,$secretHash, 0, $iv);

//Decryption:
$decryptedText = openssl_decrypt($encryptedText, $encryptionMethod, $secretHash, 0, $iv);
print "My Decrypted Text: ". $decryptedText;
8
Vivek
     function my_simple_crypt( $string, $action = 'e' ) {
        // you may change these values to your own
        $secret_key = 'my_simple_secret_key';
        $secret_iv = 'my_simple_secret_iv';

        $output = false;
        $encrypt_method = "AES-256-CBC";
        $key = hash( 'sha256', $secret_key );
        $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

        if( $action == 'e' ) {
            $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
        }
        else if( $action == 'd' ){
            $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
        }

        return $output;
    }
1
gauravbhai daxini

Il m'a fallu un bon bout de temps pour comprendre comment ne pas obtenir une false lors de l'utilisation de openssl_decrypt() et obtenir le chiffrement et le déchiffrement qui fonctionnent. 

    // cryptographic key of a binary string 16 bytes long (because AES-128 has a key size of 16 bytes)
    $encryption_key = '58adf8c78efef9570c447295008e2e6e'; // example
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($plaintext, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv);
    $encrypted = $encrypted . ':' . base64_encode($iv);

    // decrypt to get again $plaintext
    $parts = explode(':', $encrypted);
    $decrypted = openssl_decrypt($parts[0], 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, base64_decode($parts[1])); 

Si vous voulez transmettre la chaîne cryptée via une URL, vous devez encoder la chaîne: 

    $encrypted = urlencode($encrypted);

Pour mieux comprendre ce qui se passe, lisez: 

Pour générer des clés de 16 octets, vous pouvez utiliser: 

    $bytes = openssl_random_pseudo_bytes(16);
    $hex = bin2hex($bytes);

Pour voir les messages d'erreur de openssl, vous pouvez utiliser: echo openssl_error_string();

J'espère que cela pourra aider.

0
Kai Noack