Solución:
Prefacio
Comenzando con la definición de su tabla:
- UserID
- Fname
- Lname
- Email
- Password
- IV
Aquí están los cambios:
- Los campos
Fname
,Lname
yEmail
se cifrará mediante un cifrado simétrico, proporcionado por OpenSSL, - los
IV
El campo 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. - los
Password
el campo se codificará con un de una sola mano hash de contraseña,
Cifrado
Cifrado y modo
La elección del mejor modo y cifrado 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 esta publicación 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 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 recomendaría 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éngalos lo más privados posible.
IV
El vector de inicialización agrega aleatoriedad al cifrado y es necesario para el modo CBC. Lo ideal es que estos valores se utilicen 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 regenerarla.
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 el anterior $encryption_key
y $iv
; para hacer esto, tenemos que rellenar nuestros datos al 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 cifrada, como la IV, es binaria; El almacenamiento de estos valores en una base de datos se puede lograr mediante el uso de tipos de columna designados como BINARY
o VARBINARY
.
El valor de salida, 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 usando 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 del texto cifrado generado agregando una firma generada a partir de una clave secreta (diferente de la clave de cifrado) y el texto cifrado. Antes de que se descifre 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
}
Ver también: hash_equals()
Hashing
Debe evitarse en la medida de lo posible almacenar una contraseña reversible en su base de datos; solo desea verificar la contraseña en lugar de conocer su contenido. Si un usuario pierde su contraseña, es mejor permitirle restablecerla en lugar de enviarle la original (asegúrese de que el restablecimiento de contraseña solo se pueda realizar por un tiempo limitado).
La aplicación de una función hash es una operación unidireccional; posteriormente, se puede utilizar 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 a la mala elección de contraseñas de muchas personas.
Se crearon algoritmos de hash como MD5 o SHA1 para verificar el contenido del archivo con un valor de hash conocido. Están muy optimizados para hacer 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 de arco iris.
Agregar una sal a la contraseña antes de aplicar el hash haría inútil una tabla de arcoíris, pero los avances recientes en el hardware hicieron que las búsquedas de fuerza bruta fueran un enfoque viable. Es por eso que necesita un algoritmo hash que sea deliberadamente lento y simplemente imposible de optimizar. También debería poder aumentar la carga para un hardware más rápido sin afectar la capacidad de verificar los hashes de contraseñas existentes para que estén a prueba de futuro.
Actualmente hay dos opciones populares disponibles:
- PBKDF2 (función de derivación de claves basada en contraseña v2)
- bcrypt (también conocido como Blowfish)
Esta respuesta usará un ejemplo con bcrypt.
Generacion
Se puede generar un hash de contraseña de la siguiente manera:
$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 base64_encode()
y strtr()
para que coincida con el alfabeto requerido de [A-Za-z0-9/.]
.
los crypt()
La función realiza el hash basado en el algoritmo ($2y$
para Blowfish), el factor de costo (un factor de 13 toma aproximadamente 0.40s 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, 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 crypt()
de nuevo, pero pasa 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.
Hash de contraseña con PHP 5.5
PHP 5.5 introdujo las funciones de hash de contraseñas que puede utilizar 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()
Creo que esto ha sido respondido 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);
Respuesta Antecedentes y explicación
Para comprender esta pregunta, primero debe comprender qué es SHA256. SHA256 es un 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 encriptar datos), pero difícil obtener la entrada original usando el hash (equivalente a desencriptar los datos). Dado que el uso de una función hash criptográfica significa que el descifrado no es factible computacionalmente, por lo tanto, no puede realizar el descifrado con SHA256.
Lo que desea utilizar es una función bidireccional, pero más específicamente, una Cifrado de bloque. Una función que permite tanto el cifrado como el descifrado de datos. Las funciones mcrypt_encrypt
y mcrypt_decrypt
de forma predeterminada, utilice 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 utiliza mcrypt. Se puede encontrar una wiki sobre Blowfish 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 se puedan descifrar 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);