Cómo cifrar / descifrar datos en php?


Actualmente soy un estudiante y estoy estudiando PHP, estoy tratando de hacer un simple cifrar/descifrar de datos en PHP. Hice algunas investigaciones en línea y algunas de ellas fueron bastante confusas(al menos para mí).

Esto es lo que estoy tratando de hacer:

Tengo una tabla que consiste en estos campos (userId,Fname,Lname,Email, Password)

Lo que quiero es tener todos los campos encriptados y luego ser descifrados(¿ Es posible usar sha256 para encriptación / desencriptación, si no cualquier algoritmo de cifrado)

Otra cosa que quiero aprender es cómo crear una forma única hash(sha256) combinada con una buena "sal". (Básicamente solo quiero tener una implementación simple de cifrado/descifrado, hash(sha256)+salt) Señor / señora, sus respuestas serían de gran ayuda y muy apreciadas. Gracias++

Author: Scott Arciszewski, 2012-06-06

6 answers

Prólogo

Comenzando con la definición de la tabla:

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

Aquí están los cambios:

  1. Los campos Fname, Lname and Email will be encrypted using a symmetric cipher, provided by OpenSSL ,
  2. El campo IV almacenará el vector de inicialización utilizado para el cifrado. Los requisitos de almacenamiento dependen del cifrado y el modo utilizado; más sobre esto más adelante.
  3. El campo Password se hasheará usando un unidireccional hash de contraseña,

Cifrado

Cifrado y modo

Elegir el mejor cifrado y modo de cifrado está más allá del alcance de esta respuesta, pero la elección final afecta el tamaño tanto de la clave de cifrado como del vector de inicialización; para este post usaremos AES-256-CBC que tiene un tamaño de bloque fijo de 16 bytes y un tamaño de clave de 16, 24 o 32 bytes.

Clave de Cifrado

Una buena clave de cifrado es un blob binario eso se genera a partir de un generador de números aleatorios confiable. Se recomienda el siguiente ejemplo (>=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

Esto se puede hacer una o varias veces (si desea crear una cadena de claves de cifrado). Mantén esto lo más privado posible.

IV

El vector de inicialización añade aleatoriedad al cifrado y es necesario para el modo CBC. Idealmente, estos valores deben usarse solo una vez (técnicamente una vez por clave de cifrado), por lo que una actualización de cualquier parte de una fila debe regenerarlo.

Se proporciona una función para ayudarlo a generar el IV:

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

Ejemplo

Cifremos el campo name, usando los anteriores $encryption_key y $iv; para hacer esto, tenemos que rellenar nuestros datos con el tamaño de bloque:

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
);

Requisitos de almacenamiento

La salida cifrada, como la IV, es binaria; el almacenamiento de estos valores en una base de datos se puede lograr utilizando tipos de columna designados como BINARY o VARBINARY.

La salida el valor, como el IV, es binario; para almacenar esos valores en MySQL, considere usar BINARY o VARBINARY columnas. Si esta no es una opción, también puede convertir los datos binarios en una representación textual utilizando base64_encode() o bin2hex(), hacerlo requiere entre un 33% y un 100% más de espacio de almacenamiento.

Descifrado

El descifrado de los valores almacenados es similar:

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
));

Cifrado autenticado

Puede mejorar aún más la integridad de la texto cifrado generado añadiendo una firma generada a partir de una clave secreta (diferente de la clave de cifrado) y el texto cifrado. Antes de descifrar el texto cifrado, primero se verifica la firma (preferiblemente con un método de comparación de tiempo constante).

Ejemplo

// 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
}

Véase también: hash_equals()

Hashing

El almacenamiento de una contraseña reversible en su base de datos debe evitarse tanto como sea posible; solo desea verificar la contraseña en lugar de conocer su contenido. Si un usuario pierde su contraseña, es mejor que le permita restablecerla en lugar de enviarle la original (asegúrese de que el restablecimiento de la contraseña solo se puede hacer por un tiempo limitado).

La aplicación de una función hash es una operación unidireccional; luego se puede usar de forma segura para la verificación sin revelar los datos originales; para las contraseñas, un método de fuerza bruta es un enfoque factible para descubrirlo debido a su longitud relativamente corta y las malas opciones de contraseña de muchos personas.

Se hicieron algoritmos de hash como MD5 o SHA1 para verificar el contenido del archivo contra un valor hash conocido. Están optimizados en gran medida para que esta verificación sea lo más rápida posible sin dejar de ser precisa. Dado su espacio de salida relativamente limitado, fue fácil construir una base de datos con contraseñas conocidas y sus respectivas salidas hash, las tablas rainbow.

Agregar una sal a la contraseña antes de hash haría inútil una tabla rainbow, pero el hardware reciente los avances hicieron que las búsquedas de fuerza bruta fueran un enfoque viable. Es por eso que necesitas un algoritmo de hash que sea deliberadamente lento y simplemente imposible de optimizar. También debería ser capaz de aumentar la carga para un hardware más rápido sin afectar la capacidad de verificar los hashes de contraseñas existentes para que sea a prueba de futuro.

Actualmente hay dos opciones populares disponibles:

  1. PBKDF2 (Función de Derivación de Clave Basada en Contraseña v2)
  2. bcrypt (alias Blowfish)

Esta respuesta usará un ejemplo con bcrypt.

Generación

Un hash de contraseña se puede generar así:

$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);

La sal se genera con openssl_random_pseudo_bytes() para formar un blob aleatorio de datos que luego se ejecuta a través de base64_encode() y strtr() para coincidir con el alfabeto requerido de [A-Za-z0-9/.].

El crypt() función realiza el hash basado en el algoritmo ($2y$ para Blowfish), el factor de coste (un factor de 13 toma aproximadamente 0.40 s en una máquina de 3GHz) y la sal de 22 caracteres.

Validación

Una vez que haya obtenido la fila que contiene la información del usuario, validará la contraseña de esta manera:

$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;
}

Para verificar una contraseña, llame a crypt() de nuevo pero pase el hash calculado previamente como el valor de sal. El valor devuelto produce el mismo hash si la contraseña dada coincide con el hash. Para verificar el hash, a menudo se recomienda usar un tiempo constante función de comparación para evitar ataques de sincronización.

Hashing de contraseñas con PHP 5.5

PHP 5.5 introdujo las funciones de hashing de contraseñas que puede usar para simplificar el método de hashing anterior:

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

Y verificando:

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

Ver también: password_hash(), password_verify()

 271
Author: Ja͢ck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-11 10:44:57

Creo que esto ha sido contestado antes...pero de todos modos, si desea cifrar/descifrar datos, no puede usar 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);
 20
Author: romo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-06 14:37:22

Respuesta Antecedentes y Explicación

Para entender esta pregunta, primero debe entender qué es SHA256. SHA256 es una Función Hash criptográfica . Una función Hash criptográfica es una función unidireccional, cuya salida es criptográficamente segura. Esto significa que es fácil calcular un hash (equivalente a cifrar datos), pero difícil obtener la entrada original usando el hash (equivalente a descifrar los datos). Dado que el uso de una función hash criptográfica significa descifrar es computacionalmente inviable, por lo que no puede realizar el descifrado con SHA256.

Lo que quieres usar es una función bidireccional, pero más específicamente, un Cifrado por bloques . Una función que permite tanto el cifrado como el descifrado de datos. Las funciones mcrypt_encrypt y mcrypt_decrypt por defecto usan el algoritmo Blowfish. El uso de PHP de mcrypt se puede encontrar en este manual . También existe una lista de definiciones de cifrado para seleccionar el cifrado que usa mcrypt. Un wiki sobre Blowfish se puede encontrar en Wikipedia. Un cifrado por bloques encripta la entrada en bloques de tamaño y posición conocidos con una clave conocida, para que los datos puedan ser descifrados más tarde usando la clave. Esto es lo que SHA256 no puede proporcionarle.

Código

$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
Author: cytinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-06 12:15:51

Aquí hay un ejemplo usando 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;
 7
Author: Vivek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-19 20:28:31

Me llevó bastante tiempo averiguar, cómo no obtener un false cuando se utiliza openssl_decrypt() y obtener cifrar y descifrar de trabajo.

    // 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 desea pasar la cadena cifrada a través de una URL, debe codificar la cadena:

    $encrypted = urlencode($encrypted);

Para entender mejor lo que está pasando, lea:

Para generar claves largas de 16 bytes puedes usar:

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

Para ver los mensajes de error de openssl puede usar: echo openssl_error_string();

Espero que eso ayude.

 0
Author: Kai Noack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 21:26:30
     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;
    }
 0
Author: gaurav daxini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-20 07:12:05