¿Cómo se encripta y desencripta una cadena PHP?

225

Lo que quiero decir es:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

Tal vez algo como:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • En PHP, ¿cómo puedes hacer esto?

Intenté usarlo Crypt_Blowfish, pero no funcionó para mí.

夏 期 劇場
fuente
35
@Rogue No quiere un hash, quiere cifrado simétrico (como AES), simplemente no sabe cómo se llama. (Y ahora lo hace :))
Patashu
¿Qué tan seguro debe ser?
3
@ 夏 期 劇場, No 'encripta' simétricamente la sal, usa una clave. Una clave debe mantenerse en secreto. Una sal puede ser pública sin dañar la seguridad (siempre que la sal de todos sea diferente), y es un término utilizado en contraseñas hash.
Patashu
2
Necesita una Salt (clave privada), una clave pública y un algoritmo de cifrado como AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy
8
@CristianFlorea El autor de esa publicación de blog utiliza términos que simplemente no tienen el más mínimo sentido en el contexto del cifrado simétrico. No hay clave pública con AES, ni hay sal. Hay una sola clave; Debe mantenerse en secreto. En algunos modos de operación hay un IV que no necesita ser secreto, pero un IV no es una sal (dependiendo del modo, puede tener requisitos bastante diferentes) y no necesita ser secreto, mientras que la clave de cifrado real no puede ser pública. La clave pública / privada se aplica a la criptografía asimétrica, pero no tiene nada que ver con AES.
cpast

Respuestas:

410

Antes de continuar, intente comprender la diferencia entre cifrado y autenticación , y por qué probablemente desee un cifrado autenticado en lugar de solo cifrado .

Para implementar el cifrado autenticado, desea cifrar y luego MAC. ¡El orden de encriptación y autenticación es muy importante! Una de las respuestas existentes a esta pregunta cometió este error; al igual que muchas bibliotecas de criptografía escritas en PHP.

Debe evitar implementar su propia criptografía y, en su lugar, usar una biblioteca segura escrita y revisada por expertos en criptografía.

Actualización: PHP 7.2 ahora proporciona libsodium ! Para una mejor seguridad, actualice sus sistemas para usar PHP 7.2 o superior y solo siga los consejos de libsodium en esta respuesta.

Use libsodium si tiene acceso PECL (o sodium_compat si quiere libsodium sin PECL); de lo contrario ...
Use defuse / php-encryption ; ¡no tires tu propia criptografía!

Ambas bibliotecas vinculadas anteriormente hacen que sea fácil y sencillo implementar el cifrado autenticado en sus propias bibliotecas.

Si aún desea escribir e implementar su propia biblioteca de criptografía, en contra de la sabiduría convencional de cada experto en criptografía en Internet, estos son los pasos que debe seguir.

Cifrado:

  1. Cifrar usando AES en modo CTR. También puede usar GCM (que elimina la necesidad de un MAC separado). Además, ChaCha20 y Salsa20 (proporcionados por libsodium ) son cifrados de flujo y no necesitan modos especiales.
  2. A menos que elija GCM arriba, debe autenticar el texto cifrado con HMAC-SHA-256 (o, para los cifrados de flujo, Poly1305, la mayoría de las API de libsodium lo hacen por usted). ¡El MAC debería cubrir tanto el IV como el texto cifrado!

Descifrado:

  1. A menos que se use Poly1305 o GCM, vuelva a calcular el MAC del texto cifrado y compárelo con el MAC que se envió usando hash_equals(). Si falla, aborta.
  2. Descifra el mensaje.

Otras consideraciones de diseño:

  1. No comprimir nada nunca. El texto cifrado no es compresible; La compresión de texto sin formato antes del cifrado puede generar filtraciones de información (por ejemplo, CRIMEN y BREACH en TLS).
  2. Asegúrese de usar mb_strlen()y mb_substr(), usando el '8bit'modo de juego de caracteres para evitar mbstring.func_overloadproblemas.
  3. Los IV deben generarse utilizando un CSPRNG ; Si está usando mcrypt_create_iv(), ¡NO LO USEMCRYPT_RAND !
  4. A menos que esté utilizando una construcción AEAD, ¡ SIEMPRE cifre y luego MAC!
  5. bin2hex(), base64_encode(), Etc., puede filtrar información acerca de sus claves de cifrado a través de la sincronización de caché. Evítalos si es posible.

Incluso si sigue los consejos dados aquí, muchas cosas pueden salir mal con la criptografía. Siempre haga que un experto en criptografía revise su implementación. Si no tiene la suerte de ser amigo personal de un estudiante de criptografía en su universidad local, siempre puede intentar el foro de intercambio de pila de criptografía para obtener asesoramiento.

Si necesita un análisis profesional de su implementación, siempre puede contratar a un equipo de consultores de seguridad acreditados para revisar su código de criptografía PHP (divulgación: mi empleador).

Importante: Cuándo no usar cifrado

No encriptes las contraseñas . Ensu lugar,deseausar hash , utilizando uno de estos algoritmos de hash de contraseña:

Nunca use una función hash de propósito general (MD5, SHA256) para el almacenamiento de contraseñas.

No cifre los parámetros de URL . Es la herramienta incorrecta para el trabajo.

Ejemplo de cifrado de cadenas PHP con Libsodium

Si tiene PHP <7.2 o no tiene instalado libsodium, puede usar sodium_compat para lograr el mismo resultado (aunque más lento).

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

Luego para probarlo:

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

Halita - Libsodium hecho más fácil

Uno de los proyectos en los que he estado trabajando es una biblioteca de cifrado llamada Halite , cuyo objetivo es hacer que libsodium sea más fácil e intuitivo.

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

Toda la criptografía subyacente es manejada por libsodium.

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

Nota : Crypto::encrypt()devuelve salida codificada en hexadecimal.

Gestión de claves de cifrado

Si está tentado a usar una "contraseña", deténgase ahora mismo. Necesita una clave de cifrado aleatoria de 128 bits, no una contraseña humana memorable.

Puede almacenar una clave de cifrado para uso a largo plazo de esta manera:

$storeMe = bin2hex($key);

Y, a pedido, puede recuperarlo así:

$key = hex2bin($storeMe);

Yo fuertemente recomiendo que acaba de almacenar una clave generada aleatoriamente para uso a largo plazo en lugar de cualquier tipo de contraseña que la tecla (o deducir la clave).

Si está utilizando la biblioteca de Defuse:

"Pero realmente quiero usar una contraseña".

Esa es una mala idea, pero está bien, aquí está cómo hacerlo de manera segura.

Primero, genere una clave aleatoria y almacénela en una 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");

¡Tenga en cuenta que está agregando trabajo adicional y podría usar esta constante como la clave y ahorrarse mucha angustia!

Luego use PBKDF2 (así) para derivar una clave de cifrado adecuada de su contraseña en lugar de cifrarla directamente.

/**
 * 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
    );
}

No solo use una contraseña de 16 caracteres. Su clave de cifrado se romperá cómicamente.

Scott Arciszewski
fuente
3
No cifre las contraseñas , hágalas hash password_hash()y verifíquelas password_verify().
Scott Arciszewski
2
"No comprimas nada nunca". ¿Te refieres a HTTP, spdy y otros protocolos? Antes de TLS? Consejos absolutistas mucho?
Tiberiu-Ionuț Stan
1
@ScottArciszewski Me gusta su comentario sobre la clave "// Haga esto una vez y luego guárdelo de alguna manera:" .. de alguna manera, lol :)) bien, ¿qué tal si almacena esta 'clave' (que es un objeto) como una cadena simple, codificada? Necesito la llave en sí, como una cadena. ¿Puedo obtenerlo de este objeto de alguna manera? Gracias
Andrew
2
Gracias, solo tuve que modificar una línea para que tus ejemplos de sodio funcionen:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey Ozerov
1
¡Guauu! +1 por mencionar que no se deben cifrar los parámetros de URL. Me gustó mucho el artículo que brindan: paragonie.com/blog/2015/09/…
Lynnell Emmanuel Neri
73

Llegué tarde a la fiesta, pero al buscar la forma correcta de hacerlo, encontré esta página, fue uno de los principales resultados de búsqueda de Google, por lo que me gustaría compartir mi opinión sobre el problema, que considero que es actualizado al momento de escribir esta publicación (principios de 2017). Desde PHP 7.1.0, mcrypt_decrypty mcrypt_encryptserá obsoleto, por lo que la creación de código de prueba futuro debe usar openssl_encrypt y openssl_decrypt

Puedes hacer algo como:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

Importante : Esto usa el modo ECB , que no es seguro. Si desea una solución simple sin tomar un curso intensivo en ingeniería de criptografía, no la escriba usted mismo, solo use una biblioteca.

También puede usar cualquier otro método de astillador, según su necesidad de seguridad. Para conocer los métodos de chipper disponibles, consulte la función openssl_get_cipher_methods .

Emil Borconi
fuente
10
Gracias, me sorprende que esta respuesta simple y clara no sea más votada. Prefiero no leer una discusión de 10 páginas sobre el tema como la respuesta principal cuando todo lo que quiero es cifrar / descifrar una cadena simple.
Laurent
44
Esta no es una respuesta segura. El modo ECB no debe usarse. Si desea una "respuesta simple y clara", simplemente use una biblioteca .
Scott Arciszewski
2
@ScottArciszewski, sí, admito que he hablado demasiado rápido mientras buscaba un código simple. Desde entonces he agregado un IV y uso CBC en mi propio código, que es lo suficientemente bueno para mi uso.
Laurent
Lea esto y reconsidere . Con el modo CBC, un atacante puede cambiar completamente el mensaje. Si el mensaje es un archivo, un atacante puede voltear bits y hacer estallar calc.exe. Los riesgos del cifrado no autenticado son graves.
Scott Arciszewski
77
¡Todo depende del caso de uso! Hay casos en que esto está perfectamente bien. Por ejemplo, quiero pasar un parámetro GET de una página a otra, digamos, prod_id=123pero no quiero que 123 sea legible para todos, sin embargo, incluso si pudieran leerlo, no será un problema. Un atacante que pueda reemplazar el 123 a un valor personalizado no causará ningún daño, solo podrá obtener detalles de cualquier otro producto, pero Joe Average User no tendrá idea de cómo obtener detalles para producto 124 por ejemplo. Para un escenario como este, es una solución perfecta, ¡por seguridad no se puede!
Emil Borconi
43

Qué no hacer

ADVERTENCIA:
Esta respuesta usa BCE . El BCE no es un modo de cifrado, es solo un bloque de construcción. Usar ECB como se demuestra en esta respuesta no cifra realmente la cadena de forma segura. No use BCE en su código. Vea la respuesta de Scott para una buena solución.

Lo tengo yo mismo. En realidad, encontré alguna respuesta en Google y modifiqué algo. Sin embargo, el resultado es completamente inseguro.

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>
夏 期 劇場
fuente
8
Puede usar "MCRYPT_MODE_CBC" en lugar de "MCRYPT_MODE_ECB" para garantizar más seguridad.
Parixit
10
Ramesh, esto se debe a que estás obteniendo los datos encriptados sin procesar. Puede obtener una versión más agradable de los datos cifrados utilizando base64, de esta manera: base64_encode(encrypt($string))- Para descifrarlo:decrypt(base64_decode($encrypted))
mendezcode
82
ADVERTENCIA: esto es inseguro . El modo ECB no debe usarse para cadenas, ECB no toma un IV, esto no está autenticado, usa un cifrado antiguo (Blowfish) en lugar de AES, la clave no es binaria, etc., etc. La comunidad SO realmente debería dejar de votar encriptado / descifrado que simplemente "funciona" y comienza a votar respuestas que se sabe que son seguras. Si no lo sabe con certeza, no vote.
Maarten Bodewes
3
Ya hice esto al mcrypt_encryptreemplazar el código de muestra : php.net/manual/en/function.mcrypt-encrypt.php . Tenga en cuenta que al revisarlo ahora probablemente debería tener un rtrimcarácter for "\0"al final.
Maarten Bodewes
44
La respuesta correcta es usar algo como desactivar / cifrado php en lugar de escribir su propio código mcrypt.
Scott Arciszewski
18

Para el marco de Laravel

Si está utilizando el marco Laravel, es más fácil encriptar y desencriptar con funciones internas.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

Nota: Asegúrese de establecer una cadena aleatoria de 16, 24 o 32 caracteres en la opción clave del archivo config / app.php. De lo contrario, los valores cifrados no serán seguros.

Somnath Muluk
fuente
1
Claro, puede ser fácil de usar. ¿Pero es seguro? ¿Cómo aborda los problemas en stackoverflow.com/a/30159120/781723 ? ¿Utiliza encriptación autenticada? ¿Evita las vulnerabilidades de los canales secundarios y garantiza comprobaciones de igualdad de tiempo constante? ¿Utiliza una clave verdaderamente aleatoria en lugar de una contraseña / frase de contraseña? ¿Utiliza un modo de operación adecuado? ¿Genera IV al azar correctamente?
DW
10

Actualizado

Versión preparada para PHP 7. Utiliza la función openssl_encrypt de la biblioteca PHP OpenSSL .

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);
夏 期 劇場
fuente
1
Esta es una versión mejor y mucho más segura. Gracias, funciona como se esperaba también.
1
¿Cómo se crea y dónde guarda la clave de cifrado?
user2800464
7

Nota histórica: Esto fue escrito en el momento de PHP4. Esto es lo que llamamos "código heredado" ahora.

He dejado esta respuesta con fines históricos, pero algunos de los métodos ahora están en desuso, el método de cifrado DES no es una práctica recomendada, etc.

No he actualizado este código por dos razones: 1) ya no trabajo con métodos de cifrado a mano en PHP, y 2) este código todavía cumple el propósito para el que estaba destinado: demostrar el concepto mínimo y simplista de cómo puede funcionar el cifrado en PHP

Si encuentra un tipo de fuente similarmente simplista, "cifrado PHP para tontos" que puede hacer que la gente comience en 10-20 líneas de código o menos, hágamelo saber en los comentarios.

Más allá de eso, disfrute este episodio clásico de la respuesta de cifrado minimalista PHP4 de la era temprana.


Idealmente, usted tiene, o puede obtener, acceso a la biblioteca PHP de mcrypt, ya que es una variedad de tareas muy popular y muy útil. Aquí hay un resumen de los diferentes tipos de cifrado y algunos códigos de ejemplo: Técnicas de cifrado en PHP

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

Algunas advertencias:

1) Nunca use encriptación reversible o "simétrica" ​​cuando un hash unidireccional servirá.

2) Si los datos son realmente confidenciales, como números de tarjeta de crédito o de seguridad social, deténgase; necesita más de lo que proporcionará un simple fragmento de código, sino que necesita una biblioteca criptográfica diseñada para este propósito y una cantidad significativa de tiempo para investigar los métodos necesarios. Además, el software de cifrado es probablemente <10% de seguridad de los datos confidenciales. Es como volver a cablear una estación de energía nuclear: acepte que la tarea es peligrosa y difícil y que está más allá de su conocimiento si ese es el caso. Las sanciones financieras pueden ser inmensas, por lo que es mejor utilizar un servicio y enviarles la responsabilidad.

3) Cualquier tipo de cifrado fácilmente implementable, como se enumera aquí, puede proteger razonablemente la información levemente importante que desea evitar de miradas indiscretas o limitar la exposición en caso de fuga accidental / intencional. Pero viendo cómo se almacena la clave en texto plano en el servidor web, si pueden obtener los datos, pueden obtener la clave de descifrado.

Sea como fuere, diviértete :)

BrianH
fuente
99
Eww, DES. ¿Dónde está AES?
Patashu
2
¡Gracias! Pero algunos problemas. Estoy obteniendo M�������f=�_=personajes extraños como el cifrado. ¿No puedo obtener personajes simples? Al igual que: 2a2ffa8f13220befbe30819047e23b2c. Además, ¿no puedo cambiar la LONGITUD de $key_value(fijada a 8 ???) y la LONGITUD de salida $encrypted_text? (¿no puede ser 32 o 64 de largo o lo que sea más?)
夏 期 劇場
3
@ 夏 期 劇場 El resultado del cifrado son datos binarios. Si necesita que sea legible para humanos, use codificación base64 o hexadecimal en él. '¿No puedo cambiar la longitud del valor clave?' Los diferentes algoritmos de cifrado simétrico tienen diferentes requisitos para el valor clave. 'y la LONGITUD de la salida ...' La longitud del texto cifrado debe ser al menos tan larga como el texto original, o de lo contrario no hay suficiente información para recrear el texto original. (Esta es una aplicación del principio de Pigeonhole). Por cierto, debe usar AES en lugar de DES. DES es fácilmente rompible y ya no es seguro.
Patashu
8
mcrypt_ecb ha sido DEPRECADO a partir de PHP 5.5.0. Se desaconseja confiar en esta función. php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari
1
@BrianDHall La razón por la que esto todavía obtiene votos negativos es porque el modo ECB no es seguro (use CBC, CTR, GCM o Poly1305), DES es débil (desea AES, que es MCRYPT_RIJNDAEL_128), y los textos cifrados deben ser autenticados ( hash_hmac()verificados) con hash_equals()).
Scott Arciszewski
7

Si no desea usar la biblioteca (que debería), use algo como esto (PHP 7):

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);
Ascon
fuente
¿Puede ser esto un reemplazo para stackoverflow.com/a/16606352/126833 ? He usado el primero hasta que mi host actualizó a PHP 7.2.
anjanesh
@anjanesh no podrás descifrar datos antiguos con este (diferentes algoritmos + este también verifica la firma)
Ascon
2
En su caso, probablemente esto debería hacer:define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon
Esto es super!
anjanesh
2

Estos son métodos compactos para cifrar / descifrar cadenas con PHP usando AES256 CBC :

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

Uso:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");
Marco Concas
fuente
0

El siguiente código funciona en php para todas las cadenas con caracteres especiales

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
Javed
fuente