Шифрование/дешифрование RSA, совместимое с Javascript и PHP

Я хотел бы зашифровать в Javascript, а затем расшифровать в PHP. Существуют реализации RSA для Javascript и PHP, но они несовместимы. Я не могу правильно расшифровать в PHP то, что я зашифровал с помощью Javascript.

Кто-нибудь знает библиотеку/код, который будет работать как с Javascript, так и с PHP?

Спасибо.


person Community    schedule 04.03.2009    source источник
comment
Похоже, вы рассматриваете это для шифрования конфиденциальных данных между клиентом и сервером. Вы предупреждены, что это НЕ обеспечит НИКАКОЙ защиты от атаки «человек посередине», когда любые проходящие данные будут скомпрометированы. Используйте HTTPS для безопасного сквозного шифрования с проверкой подлинности.   -  person deed02392    schedule 08.08.2013


Ответы (7)


Вот библиотека шифрования JavaScript RSA: http://www.ohdave.com/rsa/

И я думаю, вы могли бы использовать что-то вроде этого класса для расшифровки сгенерированной зашифрованной строки - http://www.phpclasses.org/browse/package/4121.html

Дайте мне знать, если вам удастся собрать эту работу вместе, так как я сам изучаю эту тему (на самом деле я сам нашел этот пост в поисках этого ответа: P).

Редактировать: Смотри, я также нашел это - http://www.sematopia.com/?p=275 - похоже, тоже связано с двумя предыдущими...

person titel    schedule 20.04.2009

Попробуйте следующий простой пример.

Он использует библиотеку javascript с открытым исходным кодом https://github.com/ziyan/javascript-rsa

HTML/JAVASCRIPT:

<script language="JavaScript" type="text/javascript" src="jsbn.js"></script>
<script language="JavaScript" type="text/javascript" src="rsa.js"></script>

<script language="JavaScript">

    function encryptData(){

        //Don't forget to escape the lines:
        var pem="-----BEGIN PUBLIC KEY-----\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfmlc2EgrdhvakQApmLCDOgP0n\
NERInBheMh7J/r5aU8PUAIpGXET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t\
6rF4sYqV5Lj9t32ELbh2VNbE/7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaA\
U8bTnLEPMNC1h3qcUQIDAQAB\
-----END PUBLIC KEY-----";

        var key = RSA.getPublicKey(pem);

        element=document.getElementById('password');
        element.value=RSA.encrypt(element.value, key);
    }
</script>

<form method='POST' id='txtAuth' onsubmit='encryptData()'>
    <input type='text' name='username'/>
    <input type='password' name='password' id='password' placeholder="password"/>
    <input name='submit' type='submit' value='Submit'>
</form>

PHP:

<?php

if (isset($_POST['password'])) {

    //Load private key:
    $private = "-----BEGIN RSA PRIVATE KEY-----
    MIICXAIBAAKBgQDfmlc2EgrdhvakQApmLCDOgP0nNERInBheMh7J/r5aU8PUAIpG
    XET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t6rF4sYqV5Lj9t32ELbh2VNbE
    /7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaAU8bTnLEPMNC1h3qcUQIDAQAB
    AoGAcbh6UFqewgnpGKIlZ89bpAsANVckv1T8I7QT6qGvyBrABut7Z8t3oEE5r1yX
    UPGcOtkoRniM1h276ex9VtoGr09sUn7duoLiEsp8aip7p7SB3X6XXWJ9K733co6C
    dpXotfO0zMnv8l3O9h4pHrrBkmWDBEKbUeuE9Zz7uy6mFAECQQDygylLjzX+2rvm
    FYd5ejSaLEeK17AiuT29LNPRHWLu6a0zl923299FCyHLasFgbeuLRCW0LMCs2SKE
    Y+cIWMSRAkEA7AnzWjby8j8efjvUwIWh/L5YJyWlSgYKlR0zdgKxxUy9+i1MGRkn
    m81NLYza4JLvb8/qjUtvw92Zcppxb7E7wQJAIuQWC+X12c30nLzaOfMIIGpgfKxd
    jhFivZX2f66frkn2fmbKIorCy7c3TIH2gn4uFmJenlaV/ghbe/q3oa7L0QJAFP19
    ipRAXpKGX6tqbAR2N0emBzUt0btfzYrfPKtYq7b7XfgRQFogT5aeOmLARCBM8qCG
    tzHyKnTWZH6ff9M/AQJBAIToUPachXPhDyOpDBcBliRNsowZcw4Yln8CnLqgS9H5
    Ya8iBJilFm2UlcXfpUOk9bhBTbgFp+Bv6BZ2Alag7pY=
    -----END RSA PRIVATE KEY-----";
    if (!$privateKey = openssl_pkey_get_private($private)) die('Loading Private Key failed');

    //Decrypt
    $decrypted_text = "";
    if (!openssl_private_decrypt(base64_decode($_POST['password']), $decrypted_text, $privateKey)) die('Failed to decrypt data');

    //Decrypted :) 
    var_dump($decrypted_text);

    //Free key
    openssl_free_key($privateKey);
}
?>

Наслаждаться!

person Tieme    schedule 06.06.2012

Если вы настроили свой сервер на использование SSL, вы можете иметь зашифрованную передачу через ajax с использованием https. Это, вероятно, лучший способ шифрования данных между javascript и php. Если вы хотите сделать это самостоятельно, есть большая вероятность, что вы где-то облажаетесь, и система не будет безопасной.

Google о том, как настроить https для вашего сервера.

person Marius    schedule 04.03.2009

Я предполагаю, что у вас есть веская причина сделать это, кроме как сделать https самостоятельно, поэтому я бы сказал, что если вы придерживаетесь стандартов, вы сможете легко расшифровать любую технологию, поддерживающую эти стандарты: т.е. это должно работать

Например, если вы шифруете данные в формате PKCS#7, убедитесь, что ваша php-библиотека знает, что входными данными является PKCS#7.

Также убедитесь, что ваш ключ шифрования не зашифрован между сервером и клиентом. Вы пытались расшифровать свои данные с помощью библиотеки javascript?

Надеюсь, это поможет...

person Sébastien Nussbaumer    schedule 04.03.2009

Может быть, вы можете помочь, поместив код, который вы используете для js и php.

Кроме того, возможно, вы могли бы более конкретно указать, почему вам нужно использовать js и php. Возможно, вы могли бы использовать только php и AJAX (для запроса той же функции php), где вы использовали js.

person Nacho    schedule 04.03.2009
comment
Я думаю, что ОП пытается отправить что-то вроде пароля на сервер в зашифрованном виде. Если бы вы отправляли пароль в функцию php с помощью AJAX, вы все равно отправляли бы простой текст пароля на вызов AJAX, а затем шифрование его в методе php больше не имело бы никакого смысла. - person lugte098; 17.04.2013

Я не из тех, кто гудит в свой собственный рог, но у меня есть проект на github.com, который будет выполнять эту функцию.

Закрытый ключ генерируется на сервере, открытый ключ и сертификат pkcs#7 также извлекаются из закрытого ключа. Открытый ключ отправляется клиенту, при этом каждый элемент формы, связанный с указанной формой, шифруется перед отправкой на сервер.

Он на 100% совместим с OpenSSL, поскольку использует расширение PHP OpenSSL для генерации, шифрования и расшифровки данных.

https://github.com/jas-/jQuery.pidCrypt/

Этот проект не так безопасен, как PGP, потому что JavaScript не будет подписывать и шифровать электронные письма до тех пор, пока данные формы не будут отправлены на сервер, но данные формы, которые должны быть зашифрованы или подписаны, перед отправкой шифруются с использованием шифрования с открытым ключом RSA. на сервер.

Опять же, проект не завершен с точки зрения аутентификации и подписи электронной почты, но для шифрования обычной формы с использованием открытого ключа он работает очень хорошо.

person jas-    schedule 27.11.2011

Я нашел эту библиотеку jsencrypt (http://travistidwell.com/jsencrypt), после двух дней попыток я получил свой решение.

Единственная проблема, с которой я столкнулся, это когда я отправляю длинный текст. Это потому, что RSA по определению поддерживает строки ограниченной длины.

https://security.stackexchange.com/questions/33434/rsa-maximum-bytes-to-encrypt-comparison-to-aes-in-terms-of-security/33445#33445

RSA, как определено в PKCS#1, шифрует «сообщения» ограниченного размера. С широко используемым «заполнением v1.5» и 2048-битным ключом RSA максимальный размер данных, которые можно зашифровать с помощью RSA, составляет 245 байт. Больше не надо.

т. е. если я использую private_key_bits из 1024, я могу отправить

"José compró en Perú una vieja zampoña. Excusándose, Sofía tiró su whisky al desagüe de la banqueta."

больше ничего. Если я использую private_key_bits из 512, я могу отправить

"José compró en Perú una vieja zampoña. Excusánd"

больше ничего.

О длинных строках консоль JavaScript сообщает: «Сообщение слишком длинное для RSA».

Затем, если вы хотите зашифровать длинные строки, вы должны сжимать и разделять их перед шифрованием javascript, а после дешифрования объединять и распаковывать на php, я думаю, что zlib - хорошее решение для разделения/объединения, поскольку оно поддерживается на javascript и php.

Мой рабочий код выглядит следующим образом:

<?php
    //------------------------------------------------------------
    // Global Settings.
    //------------------------------------------------------------
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    $directorio = "/path/to/key/directory/apache/writable/";
    $nombre_base = "llaves_php";

    //------------------------------------------------------------
    // Initialization.
    //------------------------------------------------------------
    $encabezado_html = "";
    $cuerpo_html = "";

    //------------------------------------------------------------
    // Loading keys
    //------------------------------------------------------------
    list($privateKey, $pubKey) =
        cargar_llaves_RSA($directorio, $nombre_base);

    //------------------------------------------------------------
    // Form that uses javascript to encrypt data.
    // (it uses only the public key)
    //------------------------------------------------------------
    $librerias_html = "
        <script type='text/javascript'
                src='https://ajax.googleapis.com/ajax/libs/".
                    "jquery/3.2.1/jquery.min.js'></script>
        <script type='text/javascript'
                src='lib/jsencrypt.js'></script>
        ";

    $pubKey_html = htmlentities($pubKey);
    $datos_html = "
        <h2>Cifrando con Javascript</h2>
        <input type='text' id='mensaje' />
        <br />
        <button id='ENVIAR'>Enviar</button>
        <br />
        <textarea id='pubkey' style='display: none;'>".
        $pubKey_html.
        "</textarea>
        <script type='text/javascript'>
            $('#ENVIAR').click(function () {
                var codificador = new JSEncrypt();
                codificador.setKey($('#pubkey').val());
                var cifrado = codificador.encrypt($('#mensaje').val());
                window.open('?mensaje=' + encodeURIComponent(cifrado)
                           , '_top');
            });
        </script>
        ";

    //------------------------------------------------------------
    // Decrypting using php (it uses only the privateKey)
    //------------------------------------------------------------
    if (isset($_REQUEST['mensaje'])) {
        openssl_private_decrypt( base64_decode($_REQUEST['mensaje'])
                               , $descifrado
                               , $privateKey);
        $datos_html.= "
            <h2>Descifrando con PHP</h2>
            ".$descifrado."
            ";
    }

    //------------------------------------------------------------
    // HTML DISPLAY
    //------------------------------------------------------------
    $encabezado_html.= "<title>Receptor de mensaje cifrado</title>"
                     . $librerias_html;

    $cuerpo_html.= $datos_html;

    $contenido = "<head>$encabezado_html</head><body>$cuerpo_html</body>";
    $contenido = "<html>$contenido</html>";
    print $contenido;

//============================================================
//============================================================
// Functions
//============================================================
//============================================================

    //------------------------------------------------------------
    function cargar_llaves_RSA($directorio, $nombre_base) {
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // PROPÓSITO: Genera o carga desde archivos las llaves RSA
    // ENTRADAS:
    // $directorio: Directorio donde se encuentran los archivos.
    // $nombre_base: Nombre, sin extensión, de los archivos con
    //               las llaves.
    // SALIDAS:
    //------------------------------------------------------------
        if (  !file_exists($directorio.$nombre_base.".crt")
           || !file_exists($directorio.$nombre_base.".pub")) {
            list($privateKey, $pubKey) = crear_llaves_RSA($directorio.$nombre_base);
        } else {
            //------------------------------------------------------------
            // CARGA DE LLAVES RSA ARCHIVADAS
            //------------------------------------------------------------
            $privateKey = file_get_contents($directorio.$nombre_base.".crt");
        if (!$privKey = openssl_pkey_get_private($privateKey))
            die('Loading Private Key failed');
            $pubKey  = file_get_contents($directorio.$nombre_base.".pub");
        }

    return array($privateKey, $pubKey);
    }

    //------------------------------------------------------------
    function crear_llaves_RSA($ruta_base) {
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // PROPÓSITO:
    // generacion de llaves RSA en php
    // ENTRADAS:
    // $ruta_base: Ruta de los archivos a generar sin extensión.
    // SALIDAS:
    // Se generarán dos archivos, uno con la llave privada con
    // extensión .crt, el otro con llave pública con extensión
    // .pub; la función retorna tanto la llave pública como la
    // privada en un arreglo.
    //------------------------------------------------------------
        $config = array(
            "private_key_bits" => 1024,
            "private_key_type" => OPENSSL_KEYTYPE_RSA,
        );

        $llavePrivadaCruda = openssl_pkey_new($config);
        openssl_pkey_export_to_file($llavePrivadaCruda, $ruta_base.".crt");
        $privateKey = file_get_contents($ruta_base.".crt");
        openssl_pkey_export($llavePrivadaCruda, $privKey);

        $pubKeyData = openssl_pkey_get_details($llavePrivadaCruda);
        $pubKey = $pubKeyData["key"];
        file_put_contents($ruta_base.".pub", $pubKey);
        openssl_free_key($llavePrivadaCruda);

    return array($privateKey, $pubKey);
    }

    //------------------------------------------------------------
    function Mostrar($valor) {
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // PROPÓSITO: Genera el código HTML para presentar una
    // variable embebida en la página.
    // ENTRADAS:
    // $valor: el valor a presentar.
    // SALIDAS: código html que permite visualizar la variable.
    //------------------------------------------------------------
        $retorno = htmlentities(stripslashes(var_export($valor, true)));
        $retorno = "<pre>$retorno</pre>";
        return $retorno;
    }

?>

Дерево каталогов должно выглядеть так:

├── script.php
└── lib
    └── jsencrypt.js

и каталог, доступный для записи php за пределами общедоступной зоны с именем

/path/to/key/directory/apache/writable/

person gramo    schedule 26.10.2017