Saltar al contenido

Encriptar en Javascript, desencriptar en PHP, usando criptografía de clave pública

Solución:

He usado algo similar para mi página de inicio de sesión; cifra las credenciales de inicio de sesión utilizando la información de clave pública proporcionada (N, e) que se puede descifrar en PHP.

Utiliza los siguientes archivos que forman parte de JSBN:

  • jsbn.js – trabajar con números enteros grandes
  • rsa.js – solo para encriptación RSA (usa jsbn.js)
  • rng.js – colector de entropía básico
  • prng4.js – Backend ARC4 RNG

Para cifrar datos:

$pk = '-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----';
$kh = openssl_pkey_get_private($pk);
$details = openssl_pkey_get_details($kh);

function to_hex($data)
{
    return strtoupper(bin2hex($data));
}

?>
<script>
var rsa = new RSAKey();
rsa.setPublic('<?php echo to_hex($details['rsa']['n']) ?>', '<?php echo to_hex($details['rsa']['e']) ?>');

// encrypt using RSA
var data = rsa.encrypt('hello world');
</script>

Así es como decodificaría los datos enviados:

$kh = openssl_pkey_get_private($pk);
$details = openssl_pkey_get_details($kh);
// convert data from hexadecimal notation
$data = pack('H*', $data);
if (openssl_private_decrypt($data, $r, $kh)) {
   echo $r;
}

Echa un vistazo a node-rsa.

Es un módulo node.js

Este módulo proporciona acceso a rutinas de clave pública RSA desde OpenSSL. El soporte está limitado a RSAES-OAEP y cifrado con clave pública, descifrado con clave privada.

Tal vez puedas portarlo para que se ejecute en el navegador.

ACTUALIZAR

Biblioteca del lado del cliente RSA para javascript: (pidcrypt se ha descontinuado oficialmente y el dominio del sitio web ha caducado; consulte la respuesta de @ jack, que contiene las mismas bibliotecas que pidcrypt). https://www.pidder.com/pidcrypt/?page=rsa

Componente del lado del servidor PHP: http://phpseclib.sourceforge.net/

¡Buena suerte!

Tenga cuidado con la implementación de RSA. De hecho, probablemente no debería usar RSA en absoluto. (¡Utilice libsodium en su lugar!)

Incluso si está utilizando una biblioteca (por ejemplo, la extensión OpenSSL de PHP directamente o, hasta hace poco, ZendCrypt), todavía hay muchas cosas que pueden salir mal. En particular:

  • Relleno PKCS1v1.5, que es el defecto (y en muchos casos el único modo de relleno admitido), es vulnerable a una clase de ataques de texto cifrado elegido llamado oráculo de relleno. Esto fue descubierto por primera vez por Daniel Bleichenbacher. En 1998.
  • RSA no es adecuado para cifrar mensajes grandes, por lo que lo que los implementadores suelen hacer es tomar un mensaje largo, dividirlo en bloques de tamaño fijo y cifrar cada bloque por separado. Esto no solo es lento, es análogo al temido modo ECB para la criptografía de clave simétrica.

Lo mejor que puede hacer con Libsodium

Es posible que desee leer La criptografía de JavaScript se considera perjudicial unas cuantas veces antes de seguir esta ruta. Pero dicho eso …

  1. Use TLSv1.2 con HSTS y HPKP, preferiblemente con ChaCha20-Poly1305 y / o AES-GCM y un certificado ECDSA-P256 (importante: cuando el IETF bautiza Curve25519 y Ed25519, cambie a eso).
  2. Agrega libsodium.js a tu proyecto.
  3. Usar crypto_box_seal() con una clave pública para cifrar sus mensajes, del lado del cliente.
  4. En PHP, use Sodiumcrypto_box_seal_open() con la clave secreta correspondiente a la clave pública para descifrar el mensaje.

Necesito usar RSA para resolver este problema.

Por favor no lo hagas. La criptografía de curva elíptica es más rápida, más simple y mucho más fácil de implementar sin canales laterales. La mayoría de las bibliotecas ya hacen esto por ti. (¡Libsodio!)

Pero yo De Verdad quiere usar RSA!

Bien, sigue estas recomendaciones al pie de la letra y no vengas llorando a StackOverflow cuando cometas un error (como lo hizo SaltStack) que inutilice tu criptografía.

Una opción (que no viene con una implementación de JavaScript complementaria, y no solicite una) que tiene como objetivo proporcionar un cifrado RSA simple y fácil es paragonie / easyrsa.

  • Evita los oráculos de relleno utilizando RSA-OAEP con MGF1 + SHA256 en lugar de PKCS1v1.5.
  • Evita el modo ECB mediante un diseño de protocolo inteligente:

El protocolo de cifrado EasyRSA

  1. EasyRSA genera una clave aleatoria de 128 bits para la criptografía de clave simétrica (a través de AES).
  2. Su mensaje de texto sin formato está encriptado con defuse / php-encryption.
  3. Su clave AES está encriptada con RSA, proporcionada por phpseclib, usando el modo correcto (mencionado anteriormente).
  4. Esta información se empaqueta como una cadena simple (con una suma de comprobación).

Pero, realmente, si encuentra un caso de uso válido para la criptografía de clave pública, desea libsodium en su lugar.

Bono: cifrado con JavaScript, descifrado con PHP

Usaremos sodio-plus para lograr este objetivo. (Adoptado de esta publicación).

const publicKey = X25519PublicKey.from('fb1a219011c1e0d17699900ef22723e8a2b6e3b52ddbc268d763df4b0c002e73', 'hex');

async function sendEncryptedMessage() {
    let key = await getExampleKey();
    let message = $("#user-input").val();
    let encrypted = await sodium.crypto_box_seal(message, publicKey);
    $.post("/send-message", {"message": encrypted.toString('hex')}, function (response) {
        console.log(response);
        $("#output").append("<li><pre>" + response.message + "</pre></li>");
    });
}

Y luego el código PHP congruente:

<?php
declare(strict_types=1);
require 'vendor/autoload.php'; // Composer
header('Content-Type: application/json');
$keypair = sodium_hex2bin(
    '0202040a9fbf98e1e712b0be8f4e46e73e4f72e25edb72e0cdec026b370f4787' .
    'fb1a219011c1e0d17699900ef22723e8a2b6e3b52ddbc268d763df4b0c002e73'
);

$encrypted = $_POST['message'] ?? null;
if (!$encrypted) {
    echo json_encode(
        ['message' => null, 'error' => 'no message provided'],
        JSON_PRETTY_PRINT
    );
    exit(1);
}
$plaintext = sodium_crypto_box_seal_open(sodium_hex2bin($encrypted), $keypair);

echo json_encode(
    ['message' => $plaintext, 'original' => $encrypted],
    JSON_PRETTY_PRINT
);
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *