Avant de faire quoi que ce soit d'autre, cherchez à comprendre la différence entre cryptage et authentification et pourquoi vous voulez probablement cryptage authentifié plutôt que juste cryptage .
Pour mettre en œuvre le cryptage authentifié, vous voulez Crypter puis MAC. L'ordre du cryptage et de l'authentification est très important ! L'une des réponses existantes à cette question fait cette erreur, tout comme de nombreuses bibliothèques de cryptographie écrites en PHP.
Vous devez éviter d'implémenter votre propre cryptographie et utiliser plutôt une bibliothèque sécurisée écrite et révisée par des experts en cryptographie.
Mise à jour : PHP 7.2 fournit maintenant libsodium. ! Pour une meilleure sécurité, mettez à jour vos systèmes pour utiliser PHP 7.2 ou plus et suivez uniquement les conseils de libsodium dans cette réponse.
Utilisez libsodium si vous avez un accès PECL (ou sodium_compat si vous voulez libsodium sans PECL) ; sinon...
Utiliser defuse/php-encryption ; ne faites pas votre propre cryptographie !
Les deux bibliothèques liées ci-dessus permettent de mettre en œuvre facilement et sans difficulté le cryptage authentifié dans vos propres bibliothèques.
Si vous souhaitez toujours écrire et déployer votre propre bibliothèque de cryptographie, contre la sagesse conventionnelle de tous les experts en cryptographie sur Internet, voici les étapes que vous devrez suivre.
Le cryptage :
- Cryptez en utilisant AES en mode CTR. Vous pouvez également utiliser le GCM (qui supprime la nécessité d'un MAC séparé). En outre, ChaCha20 et Salsa20 (fournis par le ministère des Affaires étrangères et du Commerce international) peuvent être utilisés. libsodium ) sont des ciphers à flux et ne nécessitent pas de modes spéciaux.
- À moins que vous n'ayez choisi GCM ci-dessus, vous devriez authentifier le texte chiffré avec HMAC-SHA-256 (ou, pour les chiffrages de flux, Poly1305 -- la plupart des API libsodium le font pour vous). Le MAC doit couvrir le IV ainsi que le texte chiffré !
Décryptage :
- À moins que Poly1305 ou GCM ne soit utilisé, recalculez le MAC du texte chiffré et comparez-le au MAC qui a été envoyé à l'aide de
hash_equals()
. S'il échoue, abandonnez.
- Décryptez le message.
Autres considérations de conception :
- Ne comprimez jamais rien. Le texte chiffré n'est pas compressible ; la compression du texte en clair avant le chiffrement peut entraîner des fuites d'informations (par exemple, CRIME et BREACH sur TLS).
- Veillez à utiliser
mb_strlen()
et mb_substr()
en utilisant le '8bit'
mode de jeu de caractères pour empêcher mbstring.func_overload
problèmes.
- Les IV doivent être générés en utilisant un CSPRNG Si vous utilisez
mcrypt_create_iv()
, NE PAS UTILISER MCRYPT_RAND
!
- A moins que vous n'utilisiez une construction AEAD, TOUJOURS crypter puis MAC !
-
bin2hex()
, base64_encode()
etc. peuvent divulguer des informations sur vos clés de chiffrement via la synchronisation du cache. Évitez-les si possible.
Même si vous suivez les conseils donnés ici, beaucoup de choses peuvent mal tourner avec la cryptographie. Demandez toujours à un expert en cryptographie de revoir votre mise en œuvre. Si vous n'avez pas la chance d'être personnellement ami avec un étudiant en cryptographie de votre université locale, vous pouvez toujours essayer le site Web de la Commission européenne. Cryptographie Stack Exchange pour obtenir des conseils.
Si vous avez besoin d'une analyse professionnelle de votre mise en œuvre, vous pouvez toujours engager un une équipe réputée de consultants en sécurité pour examiner votre code de cryptographie PHP (divulgation : mon employeur).
Important : Quand ne pas utiliser le chiffrement
Ne fais pas ça. crypter mots de passe . Vous voulez dièse à la place, en utilisant l'un de ces algorithmes de cryptage de mot de passe :
N'utilisez jamais une fonction de hachage à usage général (MD5, SHA256) pour le stockage des mots de passe.
Ne pas crypter les paramètres d'URL . C'est le mauvais outil pour le travail.
Exemple de chiffrement de chaînes en PHP avec Libsodium
Si vous utilisez PHP < 7.2 ou si vous n'avez pas installé libsodium, vous pouvez utiliser sodium_compat pour obtenir le même résultat (bien que plus lentement).
<?php
declare(strict_types=1);
/**
* Encrypt a message
*
* @param string $message - message to encrypt
* @param string $key - encryption key
* @return string
* @throws RangeException
*/
function safeEncrypt(string $message, string $key): string
{
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new RangeException('Key is not the correct size (must be 32 bytes).');
}
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = base64_encode(
$nonce.
sodium_crypto_secretbox(
$message,
$nonce,
$key
)
);
sodium_memzero($message);
sodium_memzero($key);
return $cipher;
}
/**
* Decrypt a message
*
* @param string $encrypted - message encrypted with safeEncrypt()
* @param string $key - encryption key
* @return string
* @throws Exception
*/
function safeDecrypt(string $encrypted, string $key): string
{
$decoded = base64_decode($encrypted);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plain = sodium_crypto_secretbox_open(
$ciphertext,
$nonce,
$key
);
if (!is_string($plain)) {
throw new Exception('Invalid MAC');
}
sodium_memzero($ciphertext);
sodium_memzero($key);
return $plain;
}
Puis de le tester :
<?php
// This refers to the previous code block.
require "safeCrypto.php";
// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';
$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Halite - Le libsodium en toute simplicité
Un des projets sur lequel j'ai travaillé est une bibliothèque de cryptage appelée Halite qui vise à rendre libsodium plus facile et plus intuitif.
<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;
// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');
$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Toute la cryptographie sous-jacente est gérée par libsodium.
Exemple avec defuse/php-encryption
<?php
/**
* This requires https://github.com/defuse/php-encryption
* php composer.phar require defuse/php-encryption
*/
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;
require "vendor/autoload.php";
// Do this once then store it somehow:
$key = Key::createNewRandomKey();
$message = 'We are all living in a yellow submarine';
$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Note : Crypto::encrypt()
renvoie une sortie codée en hexadécimal.
Gestion des clés de cryptage
Si vous êtes tenté d'utiliser un "mot de passe", arrêtez tout de suite. Vous avez besoin d'une clé de cryptage 128 bits aléatoire, pas d'un mot de passe mémorisable par l'homme.
Vous pouvez stocker une clé de cryptage pour une utilisation à long terme comme suit :
$storeMe = bin2hex($key);
Et, à la demande, vous pouvez le récupérer comme ceci :
$key = hex2bin($storeMe);
I fortement recommande de simplement stocker une clé générée aléatoirement pour une utilisation à long terme au lieu d'utiliser un mot de passe comme clé (ou pour dériver la clé).
Si vous utilisez la bibliothèque de Defuse :
"Mais je vraiment veulent utiliser un mot de passe."
C'est une mauvaise idée, mais bon, voici comment le faire en toute sécurité.
Tout d'abord, générez une clé aléatoire et stockez-la dans une constante.
/**
* Replace this with your own salt!
* Use bin2hex() then add \x before every 2 hex characters, like so:
*/
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");
Notez que vous ajoutez du travail supplémentaire et que vous pourriez simplement utiliser cette constante comme clé et vous épargner bien des soucis !
Utilisez ensuite PBKDF2 (comme ceci) pour dériver une clé de chiffrement appropriée à partir de votre mot de passe plutôt que de chiffrer directement avec votre mot de passe.
/**
* Get an AES key from a static password and a secret salt
*
* @param string $password Your weak password here
* @param int $keysize Number of bytes in encryption key
*/
function getKeyFromPassword($password, $keysize = 16)
{
return hash_pbkdf2(
'sha256',
$password,
MY_PBKDF2_SALT,
100000, // Number of iterations
$keysize,
true
);
}
N'utilisez pas seulement un mot de passe à 16 caractères. Votre clé de cryptage sera ridiculement cassée.
43 votes
@Rogue Il ne veut pas de hachage, il veut un cryptage symétrique (comme AES), mais il ne sait pas comment ça s'appelle. (Et maintenant il le sait :) )
0 votes
Quelle doit être la sécurité ?
3 votes
@, Vous ne faites pas de cryptage symétrique "salé", vous utilisez une clé. Une clé doit être gardée secrète. Un sel peut être public sans nuire à la sécurité (tant que le sel de chacun est différent), et c'est un terme utilisé dans le hachage des mots de passe.
2 votes
Vous avez besoin d'un Salt (clé privée), d'une clé publique et d'un algorithme de cryptage comme AES-256 : wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
8 votes
@CristianFlorea L'auteur de cet article de blog utilise des termes qui n'ont tout simplement pas le moindre sens dans le contexte du cryptage symétrique. Il n'y a pas de clé publique avec AES, ni de sel. Il n'y a qu'une seule clé, qui doit être gardée secrète. Dans certains modes de fonctionnement, il existe un IV qui n'a pas besoin d'être secret, mais un IV n'est pas un sel (selon le mode, il peut avoir des exigences très différentes) et n'a pas besoin d'être secret, tandis que la clé de cryptage réelle ne peut absolument pas être publique. La clé publique/privée s'applique à la cryptographie asymétrique, mais n'a rien à voir avec AES.