120 votes

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

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

Voici ce que j'essaie de faire :

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

Ce que je veux, c'est que tous les champs soient cryptés, puis décryptés (est-il possible d'utiliser la méthode de l'utilisateur final ? sha256 pour le cryptage/décryptage, sinon tout algorithme de cryptage)

Une autre chose que je veux apprendre est comment créer une voie unique hash(sha256) combiné avec un bon "sel". (Fondamentalement, je veux juste avoir une implémentation simple du cryptage/décryptage, hash(sha256)+salt) Monsieur/Madame, vos réponses seraient d'une grande aide et très appréciées. Merci++.

3 votes

0 votes

9 votes

SHA est un hachage, pas un cryptage. Le point clé est qu'un hachage ne peut pas être inversé en données originales (pas facilement, en tout cas). Vous voulez probablement mcrypt ou si elle n'est pas disponible, je recommande phpseclib - Bien qu'il soit important de noter que toute implémentation purement PHP de quelque chose qui implique beaucoup de mathématiques de bas niveau sera lente... C'est pourquoi j'aime phpseclib, parce qu'il utilise mcrypt en premier s'il est disponible et ne se rabat sur les implémentations PHP qu'en dernier recours.

300voto

Jack Points 88446

Avant-propos

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

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

Voici les changements :

  1. Les champs Fname , Lname y Email sera crypté en utilisant un chiffrement symétrique, fourni par OpenSSL ,
  2. El IV permettra de stocker le vecteur d'initialisation utilisé pour le cryptage. Les exigences en matière de stockage dépendent du chiffrement et du mode utilisés ; nous y reviendrons plus tard.
  3. El Password sera haché en utilisant un à sens unique le hachage du mot de passe,

Cryptage

Chiffre et mode

Le choix du meilleur chiffrement et du meilleur mode de chiffrement dépasse le cadre de cette réponse, mais le choix final affecte la taille de la clé de chiffrement 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 cryptage

Une bonne clé de chiffrement est un blob binaire généré par un générateur de nombres aléatoires fiable. L'exemple suivant est 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

Cette opération peut être effectuée une ou plusieurs fois (si vous souhaitez créer une chaîne de clés de cryptage). Gardez ces clés aussi privées que possible.

IV

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

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

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

Exemple

Cryptons le champ du nom, en utilisant la méthode précédente. $encryption_key y $iv Pour ce faire, nous devons adapter 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
);

Exigences de stockage

La sortie chiffrée, comme le IV, est binaire ; le stockage de ces valeurs dans une base de données peut être réalisé en utilisant des types de colonnes désignés tels que BINARY o VARBINARY .

La valeur de sortie, comme l'IV, est binaire ; pour stocker ces valeurs dans MySQL, envisagez d'utiliser BINARY o VARBINARY colonnes. Si ce n'est pas possible, vous pouvez également convertir les données binaires en une représentation textuelle à l'aide de la fonction base64_encode() o bin2hex() En effet, cela nécessite entre 33 % et 100 % d'espace de stockage supplémentaire.

Décryptage

Le décryptage 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 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 en 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

Le stockage 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 pour une durée limitée).

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

Les algorithmes de hachage tels que MD5 ou SHA1 ont été conçus pour vérifier le contenu des fichiers par rapport à une valeur de hachage connue. Ils sont largement optimisés pour rendre cette vérification aussi rapide que possible tout en restant précis. Étant donné leur espace de sortie relativement limité, il a été facile de construire une base de données avec des mots de passe connus et leurs résultats de hachage respectifs, les tables arc-en-ciel.

L'ajout d'un sel au mot de passe avant de le hacher rendrait une table arc-en-ciel inutile, mais les récentes avancées matérielles ont fait des recherches par force brute une approche viable. C'est pourquoi vous avez besoin d'un algorithme de hachage qui soit délibérément lent et tout simplement impossible à optimiser. Il doit également être capable d'augmenter la charge pour un matériel plus rapide sans affecter la capacité à vérifier les hachages de mots de passe existants, afin d'être à l'épreuve du temps.

Actuellement, deux choix populaires sont disponibles :

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

Cette réponse utilisera un exemple avec bcrypt.

Génération

Un hachage de mot de passe peut être généré comme suit :

$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é à travers base64_encode() y strtr() pour correspondre à l'alphabet requis de [A-Za-z0-9/.] .

El crypt() effectue le hachage en se basant sur l'algorithme ( $2y$ pour Blowfish), le facteur de coût (un facteur de 13 prend environ 0,40s sur une machine de 3GHz) et le sel de 22 caractères.

Validation

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

$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 crypt() mais vous passez le hachage calculé précédemment comme valeur de sel. La valeur de retour donne le même hachage si le mot de passe donné correspond au hachage. Pour vérifier le hachage, il est souvent recommandé d'utiliser une fonction de comparaison à temps constant afin d'éviter les attaques de synchronisation.

Hachage de mot de passe avec PHP 5.5

PHP 5.5 a introduit la fonction 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 la vérification :

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

Voir aussi : password_hash() , password_verify()

0 votes

Quelle longueur dois-je utiliser pour stocker le nom, le prénom, l'e-mail, etc. pour plus de sécurité ? varbinary( ???)

0 votes

@MadMax Cela dépend entièrement de vous ; ma réponse couvre les différents codages que vous pouvez utiliser pour stocker les valeurs, qu'il s'agisse de binaire, d'hexadécimal ou de base64, et la quantité de stockage nécessaire par caractère.

0 votes

Je suis d'accord avec @MaartenBodewes que vos ciphertexts devraient être authentifiés (par exemple HMAC) et vérifiés en temps constant.

24voto

romo Points 1492

Je pense que cette question a déjà été traitée... mais quoi qu'il en soit, si vous voulez crypter/décrypter 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);

7 votes

Vous ne devriez pas non plus utiliser les BCE, d'ailleurs.

7 votes

Les clés doivent être des octets aléatoires, ou vous devez utiliser une fonction de dérivation de clé sécurisée.

4 votes

MCRYPT_RIJNDAEL_256 n'est pas une fonction standardisée, vous devriez utiliser AES (MCRYPT_RIJNDAEL_128)

14voto

cytinus Points 1184

Réponse Contexte et explication

Pour comprendre cette question, vous devez d'abord comprendre ce qu'est SHA256. SHA256 est un Fonction de hachage cryptographique . Une fonction de hachage cryptographique est une fonction à sens unique dont la sortie est cryptographiquement sécurisée. Cela signifie qu'il est facile de calculer un hachage (équivalent au cryptage des données), mais difficile d'obtenir l'entrée originale en utilisant le hachage (équivalent au décryptage des données). Puisque l'utilisation d'une fonction de hachage cryptographique signifie que le décryptage est infaisable sur le plan informatique, vous ne pouvez donc pas effectuer de décryptage avec SHA256.

Ce que vous voulez utiliser, c'est une fonction bidirectionnelle, mais plus précisément, une fonction Chiffre en bloc . Une fonction qui permet à la fois le cryptage et le décryptage des données. Les fonctions mcrypt_encrypt y mcrypt_decrypt utilisent par défaut l'algorithme Blowfish. L'utilisation de mcrypt par PHP peut être trouvée dans le document suivant manuel . Une liste de définitions du chiffrement pour sélectionner le chiffrement utilisé par mcrypt existe également. Un wiki sur Blowfish peut être trouvé à l'adresse suivante Wikipedia . Un chiffrement par blocs chiffre l'entrée en blocs de taille et de position connues avec une clé connue, de sorte que les données peuvent être déchiffrées ultérieurement à 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);

0 votes

Vous ne devriez pas non plus utiliser les BCE, d'ailleurs.

0 votes

Les clés doivent être des octets aléatoires, ou vous devez utiliser une fonction de dérivation de clé sécurisée.

4 votes

Jamais. utiliser le mode BCE. Ce mode n'est pas sûr et, la plupart du temps, il n'aide pas vraiment à crypter les données (au lieu de simplement les coder). Voir le excellent article de Wikipedia sur le sujet pour plus d'informations.

10voto

Vivek Points 169

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;

2 votes

Au lieu de mcrypt_create_iv() que j'utiliserais : openssl_random_pseudo_bytes(openssl_cipher_iv_length($encryp‌​tionMethod)) De cette façon, la méthodologie fonctionne pour n'importe quelle valeur de $encryptionMethod et utilise uniquement l'extension openssl.

0 votes

Le code ci-dessus renvoie false para openssl_decrypt() . Voir stackoverflow.com/q/41952509/1066234 Étant donné que les chiffrements par blocs tels que l'AES exigent que les données d'entrée soient un multiple exact de la taille du bloc (16 octets pour l'AES), le remplissage est nécessaire.

10voto

gaurav daxini Points 479
     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 votes

Très simple ! Je l'utilise pour le cryptage-décryptage des segments d'url. Merci

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X