password_hash password pass encriptar encriptada desencriptar contraseña con codigo php security encryption cryptography encryption-symmetric

php - encriptar - password_hash



Cómo cifrar/descifrar datos en php? (6)

Actualmente soy estudiante y estoy estudiando PHP, estoy intentando hacer un cifrado / descifrado simple 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 trato de hacer:

Tengo una tabla que consta de estos campos (UserID, Fname, Lname, correo electrónico, contraseña)

Lo que quiero tener es cifrar todos los campos y luego descifrarlos (¿es posible usar sha256 para el cifrado / descifrado, si no es algún algoritmo de cifrado)?

Otra cosa que quiero aprender es cómo crear un hash(sha256) una manera hash(sha256) combinado con una buena "sal". (Básicamente, solo quiero tener una implementación simple de cifrado / descifrado, hash(sha256)+salt) Sir / Señora, sus respuestas serán de gran ayuda y serán muy apreciadas. Gracias ++


Prefacio

Comenzando con la definición de su tabla:

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

Aquí están los cambios:

  1. Los campos Fname , Lname y Email se Lname utilizando un cifrado simétrico, proporcionado por 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 tarde.
  3. El campo de Password será hash usando un hash de contraseña de un solo sentido ,

Cifrado

Cifrado y modo

Elegir el mejor cifrado y modo de encriptación está más allá del alcance de esta respuesta, pero la elección final afecta el tamaño de la clave de cifrado y el vector de inicialización; para esta publicación utilizaremos 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 encriptación

Una buena clave de cifrado es un blob binario que 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). Mantenga esto tan privado como sea posible.

IV

El vector de inicialización agrega aleatoriedad al cifrado y se requiere para el modo CBC. Estos valores deberían idealmente usarse solo una vez (técnicamente una vez por clave de cifrado), por lo que una actualización de cualquier parte de una fila debería 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

Encriptemos el campo de nombre, usando la $encryption_key anterior y $iv ; para hacer esto, tenemos que rellenar nuestros datos con el tamaño del 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 encriptada, como IV, es binaria; el almacenamiento de estos valores en una base de datos se puede lograr mediante el uso de tipos de columnas designadas como BINARY o VARBINARY .

El valor de salida, como el IV, es binario; para almacenar esos valores en MySQL, considere usar columnas BINARY o VARBINARY . Si no se trata de una opción, también puede convertir los datos binarios en una representación textual utilizando base64_encode() o bin2hex() , lo que requiere entre 33% y 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 ));

Encriptación autenticada

Puede mejorar aún más la integridad del texto de cifrado generado agregando una firma generada a partir de una clave secreta (diferente de la clave de cifrado) y el texto de cifrado. Antes de descifrar el texto de cifrado, la firma se verifica primero (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 }

Ver 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 permitir que la reinicie en lugar de enviar su 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 puede usarse con seguridad para la verificación sin revelar los datos originales; para contraseñas, un método de fuerza bruta es un enfoque factible para descubrirlo debido a su longitud relativamente corta y la mala selección de contraseñas de muchas personas.

Algoritmos hash como MD5 o SHA1 se hicieron para verificar el contenido del archivo contra un valor hash conocido. Están enormemente optimizados para hacer esta verificación lo más rápido posible sin dejar de ser precisos. Dado su espacio de producción 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 de arcoiris, pero los recientes avances de hardware hicieron que las búsquedas de fuerza bruta fueran un enfoque viable. Es por eso que necesita un algoritmo hash 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 hashes de contraseñas existentes para que sea una prueba futura.

Actualmente hay dos opciones populares disponibles:

  1. PBKDF2 (Función de derivación de clave basada en contraseña v2)
  2. bcrypt (también conocido como Blowfish)

Esta respuesta usará un ejemplo con bcrypt.

Generacion

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 una masa aleatoria de datos que luego se ejecuta a través de base64_encode() y strtr() para que coincida con el alfabeto requerido de [A-Za-z0-9/.] .

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

Validación

Una vez que haya buscado la fila que contiene la información del usuario, valide 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 de nuevo a crypt() pero pase el hash calculado previamente como el valor de sal. El valor de retorno produce el mismo hash si la contraseña dada coincide con el hash. Para verificar el hash, a menudo se recomienda utilizar una función de comparación de tiempo constante para evitar ataques de tiempo.

Hashing de contraseña con PHP 5.5

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

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


Respuesta de fondo y explicación

Para entender esta pregunta, primero debes entender qué es SHA256. SHA256 es una función de hash criptográfica . Una función de hash criptográfica es una función unidireccional, cuya salida es criptográficamente segura. Esto significa que es fácil calcular un hash (equivalente al cifrado de datos), pero es 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 que el descifrado no es computacionalmente factible, por lo tanto, no puede realizar el descifrado con SHA256.

Lo que quiere usar es una función de dos vías, pero más específicamente, un Cifrado de Bloque . Una función que permite el cifrado y descifrado de datos. Las funciones mcrypt_encrypt y mcrypt_decrypt usan de manera predeterminada 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 los usos de cifrado mcrypt. Una wiki sobre Blowfish se puede encontrar en Wikipedia . Un cifrado de bloques cifra la entrada en bloques de tamaño y posición conocidos con una clave conocida, de modo que los datos puedan descifrarse posteriormente utilizando 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);


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;


Creo que esto ha sido respondido antes ... pero de todos modos, si quieres cifrar / descifrar datos, no puedes 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);


Me tomó bastante tiempo descubrir, cómo no obtener un resultado false al usar openssl_decrypt() y obtener encriptar y desencriptar el 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 urlencode la cadena:

$encrypted = urlencode($encrypted);

Para comprender mejor lo que está sucediendo, lee:

Para generar claves de 16 bytes de longitud, puede 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 ayude.


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