Шифрование в Javascript, расшифровка в PHP, используя криптографию с открытым ключом

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

В настоящее время я, глядя на openpgpjs, но мне нужна поддержка во всех браузерах, и даже на тестовой странице есть ошибки только в списке поддерживаемых браузеров (Google Chrome).

Примечания о конечной цели:

TCP-соединение уже защищен SSL. Основная цель этого уровня защиты-защита от преднамеренного или непреднамеренного ведения журнала веб-сервера, аварийных дампов и т. д.

на стороне PHP будет сгенерирован временный закрытый ключ (он истечет через короткое время). Вызывающий абонент (в Javascript) отвечает за запрос нового открытого ключа, когда он истекает. Причина истечения срока действия закрытого ключа-предотвращение расшифровки зарегистрированных зашифрованных данных, если сервер, на котором хранится закрытый ключ позже скомпрометирован.

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

5 ответов


я использовал что-то подобное для моей страницы входа в систему; он шифрует учетные данные, используя заданную информацию открытого ключа (N, e), которая может быть расшифрована в PHP.

он использует следующие файлы, которые являются частью JSBN:

  • jsbn.js - для работы с большими целыми числами
  • rsa.js - только для шифрования RSA (использует jsbn.в JS)
  • rng.js - основной коллектор энтропии
  • prng4.js - ARC4 RNG бэкэнд

для шифрования данных:

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

вот как вы расшифруете отправленные данные:

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

проверить узел-rsa.

Это узел.модуль js

этот модуль предоставляет доступ к подпрограммам открытого ключа RSA из OpenSSL. Поддержка ограничена RSAES-OAEP и шифрованием с открытым ключом, дешифрованием с закрытым ключом.

возможно, вы можете перенести его для запуска в браузере.

обновление

клиентская библиотека RSA для javascript:(pidcrypt был официально прекращено, и домен веб-сайта истек-см. ответ @jack, который содержит те же библиотеки, что и pidcrypt). https://www.pidder.com/pidcrypt/?page=rsa

серверный компонент PHP: http://phpseclib.sourceforge.net/

удачи!


будьте осторожны с реализацией RSA. На самом деле, вы, вероятно, не должны использовать RSA вообще. (вместо этого используйте libsodium!)

даже если вы используете библиотеку (например, расширение OpenSSL PHP напрямую или, до недавнего времени,Zend\Crypt), есть еще много, что может пойти не так. В частности:

  • PKCS1v1.5 заполнение, которое является по умолчанию (и во многих случаях единственный поддерживаемый режим заполнения), уязвим для класса выбрали-шифротекст атак называется обивка оракул. Это был впервые обнаружен исполнителя Daniel Bleichenbacher. в 1998 году.
  • RSA не подходит для шифрования больших сообщений, поэтому разработчики часто делают длинное сообщение, разбивают его на блоки фиксированного размера и шифруют каждый блок отдельно. Это не только медленно, это аналогично страшный режим ECB для криптографии с симметричным ключом.

лучшее, что можно сделать, с Libsodium

вы можете прочитать Криптография JavaScript Считается Вредной несколько раз, прежде чем идти по этому пути. Но это было сказано...

  1. Используйте TLSv1.2 с HSTS и HPKP, предпочтительно с ChaCha20-Poly1305 и/или AES-GCM и сертификатом ECDSA-P256 (важно: когда IETF крестит Curve25519 и Ed25519, переключитесь на это вместо этого).
  2. добавить libsodium.js в свой проект.
  3. использовать crypto_box_seal() С открытым ключом для шифрования сообщений на стороне клиента.
  4. в PHP, используйте \Sodium\crypto_box_seal_open() С соответствующим секретным ключом для открытого ключа для расшифровки сообщения.

мне нужно использовать RSA для решения этой проблемы.

пожалуйста, не. Криптография эллиптических кривых быстрее, проще и намного проще реализовать без боковых каналов. Большинство библиотек уже делают это за вас. (Libsodium!)

Но Я действительно хотите использовать RSA!

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

один вариант (который не поставляется с дополнительной реализацией JavaScript, и, пожалуйста, не просите один), который направлен на обеспечение простого и легкого шифрования RSA paragonie/easyrsa.

  • это позволяет избежать заполнения оракулов с помощью ОГА-УАМИАЭ с MGF1+SHA256 и вместо PKCS1v1.5.
  • он избегает режима ЕЦБ умным дизайном протокола:

Протокол Шифрования EasyRSA

  1. EasyRSA генерирует случайный 128-битный ключ для симметричной криптографии ключей (через AES).
  2. ваше текстовое сообщение зашифровано с помощью обезвредить / php-шифрование.
  3. ваш ключ AES зашифрован с помощью RSA, предоставленного phpseclib, используя соответствующий режим (см. выше).
  4. эта информация упакована вместе как простая строка (с контрольной суммой).

но, действительно,если вы найдете допустимый вариант использования для криптографии с открытым ключом, вам нужен libsodium.


пример использования RSA для pidCrypt (js) и phpseclib (php).

не использовать закрытый ключ в этом рабочем примере.

шифрование pidCrypt

//From the pidCrypt example sandbox
function certParser(cert) {
    var lines = cert.split('\n');
    var read = false;
    var b64 = false;
    var end = false;
    var flag = '';
    var retObj = {
    };
    retObj.info = '';
    retObj.salt = '';
    retObj.iv;
    retObj.b64 = '';
    retObj.aes = false;
    retObj.mode = '';
    retObj.bits = 0;
    for (var i = 0; i < lines.length; i++) {
        flag = lines[i].substr(0, 9);
        if (i == 1 && flag != 'Proc-Type' && flag.indexOf('M') == 0)//unencrypted cert?
        b64 = true;
        switch (flag) {
            case '-----BEGI':
                read = true;
                break;
            case 'Proc-Type':
                if (read)retObj.info = lines[i];
                break;
            case 'DEK-Info:':
                if (read) {
                    var tmp = lines[i].split(',');
                    var dek = tmp[0].split(': ');
                    var aes = dek[1].split('-');
                    retObj.aes = (aes[0] == 'AES') ? true : false;
                    retObj.mode = aes[2];
                    retObj.bits = parseInt(aes[1]);
                    retObj.salt = tmp[1].substr(0, 16);
                    retObj.iv = tmp[1];
                }
                break;
            case '':
                if (read)b64 = true;
                break;
            case '-----END ':
                if (read) {
                    b64 = false;
                    read = false;
                }
                break;
                default : if (read && b64)retObj.b64 += pidCryptUtil.stripLineFeeds(lines[i]);
        }
    }
    return retObj;
}

var strCreditCardPublicKey="-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC\/tI7cw+gnUPK2LqWp50XboJ1i\njrLDn+4\/gPOe+pB5kz4VJX2KWwg9iYMG9UJ1M+AeN33qT7xt9ob2dxgtTh7Mug2S\nn1TLz4donuIzxCmW+SZdU1Y+WNDINds194hWsAVhMC1ClMQTfldUGzQnI5sXvZTF\nJWp\/9jheCNLDRIkAnQIDAQAB\n-----END PUBLIC KEY-----\n";

var objParams=certParser(strCreditCardPublicKey);
var binaryPrivateKey=pidCryptUtil.decodeBase64(objParams.b64);

var rsa=new pidCrypt.RSA();

var asn=pidCrypt.ASN1.decode(pidCryptUtil.toByteArray(key));
var tree=asn.toHexTree();
rsa.setPublicKeyFromASN(tree);

var strHexSensitiveDataEncrypted=rsa.encrypt("4111111111111111");

var strBase64SensitiveDataEncrypted=pidCryptUtil.fragment(pidCryptUtil.encodeBase64(pidCryptUtil.convertFromHex(strHexSensitiveDataEncrypted)), 64))

console.log(strBase64SensitiveDataEncrypted);

.

расшифровка phpseclib

require_once("Crypt/RSA.php");

function decrypt($strBase64CipherText)
{
    //CRYPT_RSA_MODE_INTERNAL is slow
    //CRYPT_RSA_MODE_OPENSSL is fast, but requires openssl to be installed, configured and accessible.
    define("CRYPT_RSA_MODE", CRYPT_RSA_MODE_INTERNAL);

    $rsa=new Crypt_RSA();


    //$strPrivateKey=file_get_contents("private.pem");
    //This private key is for example purposes
    //DO NOT REUSE
    $strPrivateKey="-----BEGIN RSA PRIVATE KEY-----
        MIICXQIBAAKBgQDBNHK7R2CCYGqljipbPoj3Pwyz4cF4bL5rsm1t8S30gbEbMnKn
        1gpzteoPlKp7qp0TnsgKab13Fo1d+Yy8u3m7JUd/sBrUa9knY6dpreZ9VTNul8Bs
        p2LNnAXOIA5xwT10PU4uoWOo1v/wn8eMeBS7QsDFOzIm+dptHYorB3DOUQIDAQAB
        AoGBAKgwGyxy702v10b1omO55YuupEU3Yq+NopqoQeCyUnoGKIHvgaYfiwu9sdsM
        ZPiwxnqc/7Eo6Zlw1XGYWu61GTrOC8MqJKswJvzZ0LrO3oEb8IYRaPxvuRn3rrUz
        K7WnPJyQ2FPL+/D81NK6SH1eHZjemb1jV9d8uGb7ifvha5j9AkEA+4/dZV+dZebL
        dRKtyHLfbXaUhJcNmM+04hqN1DUhdLAfnFthoiSDw3i1EFixvPSiBfwuWC6h9mtL
        CeKgySaOkwJBAMSdBhn3C8NHhsJA8ihQbsPa6DyeZN+oitiU33HfuggO3SVIBN/7
        HmnuLibqdxpnDOtJT+9A+1D29TkNENlTWgsCQGjVIC8xtFcV4e2s1gz1ihSE2QmU
        JU9sJ3YeGMK5TXLiPpobHsnCK8LW16WzQIZ879RMrkeDT21wcvnwno6U6c8CQQCl
        dsiVvXUmyOE+Rc4F43r0VRwxN9QI7hy7nL5XZUN4WJoAMBX6Maos2Af7NEM78xHK
        SY59+aAHSW6irr5JR351AkBA+o7OZzHIhvJfaZLUSwTPsRhkdE9mx44rEjXoJsaT
        e8DYZKr84Cbm+OSmlApt/4d6M4YA581Os1eC8kopewpy
        -----END RSA PRIVATE KEY-----
    ";
    $strPrivateKey=preg_replace("/[ \t]/", "", $strPrivateKey);//this won't be necessary when loading from PEM


    $rsa->loadKey($strPrivateKey);

    $binaryCiphertext=base64_decode($strBase64CipherText);

    $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
    $strBase64DecryptedData=$rsa->decrypt($binaryCiphertext);

    return base64_decode($strBase64DecryptedData);
}

//The pidCrypt example implementation will output a base64 string of an encrypted base64 string which contains the original data, like this one:
$strBase64CipherText="JDlK7L/nGodDJodhCj4uMw0/LW329HhO2EvxNXNUuhe+C/PFcJBE7Gp5GWZ835fNekJDbotsUFpLvP187AFAcNEfP7VAH1xLhhlB2a9Uj/z4Hulr4E2EPs6XgvmLBS3MwiHALX2fES5hSKY/sfSUssRH10nBHHO9wBLHw5mRaeg=";

$binaryDecrypted=decrypt($strBase64CipherText);

//should output '4111111111111111'
var_export($binaryDecrypted);

это основано на Крошечный Алгоритм Шифрования, который является симметричной системой шифрования (закрытый ключ). Тем не менее, он может быть полезен вам из-за его легкого веса.

Это сейчас в: http://babelfish.nl/Projecten/JavascriptPhpEncryption