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

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

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

Заметки о конечной цели:

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

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

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

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

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

  • jsbn.js – работать с большими целыми числами
  • rsa.js – только для шифрования RSA (использует jsbn.js)
  • rng.js – основной сборщик энтропии
  • prng4.js – сервер prng4.js 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 .

Это модуль node.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 padding, который является стандартным (и во многих случаях единственным поддерживаемым режимом заполнения), уязвим для класса выбранных-зашифрованных текстовых атак, называемых прописными буквами. Это было впервые обнаружено Даниэлем Блейхенбахером. В 1998 году.
  • RSA не подходит для шифрования больших сообщений, поэтому разработчики часто делают длинное сообщение, разбивают его на блоки фиксированного размера и шифруют каждый блок отдельно. Это не только медленно, но и похоже на ужасный режим ECB для криптографии с симметричным ключом.

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

Возможно, вы захотите прочитать криптографию JavaScript, считающуюся вредной, несколько раз, прежде чем идти по этому маршруту. Но это сказало …

  1. Используйте TLSv1.2 с HSTS и HPKP, предпочтительно с ChaCha20-Poly1305 и / или AES-GCM и сертификатом ECDSA-P256 (важно: когда IETF christens 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 .

  • Он избегает прописных оракулов с помощью RSA-OAEP с MGF1 + SHA256 вместо PKCS1v1.5.
  • Он избегает режима ECB с помощью умного дизайна протокола:

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

  1. EasyRSA генерирует случайный 128-битный ключ для криптографии с симметричным ключом (через AES).
  2. Ваше текстовое сообщение шифруется с помощью defuse / php-encryption .
  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); , //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); 

Это основано на алгоритме Tiny Encryption Algorithm , который представляет собой симметричную (закрытый ключ) систему шифрования. Тем не менее он может быть вам полезен из-за его небольшого веса.

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