使用Javascript加密,使用PHP解密,使用公钥加密

使用Javascript加密,使用PHP解密,使用公钥加密,javascript,php,rsa,public-key,pgp,Javascript,Php,Rsa,Public Key,Pgp,我想用JavaScript加密,用PHP解密,使用公钥加密。我一直在努力寻找能够实现这一点的库,但我遇到了一些问题 我目前正在查看,但我需要所有浏览器的支持,甚至测试页面在唯一列出的受支持浏览器(Google Chrome)上也有错误 关于最终目标的说明: TCP连接已受SSL保护。此保护层的主要目的是防止有意或无意的Web服务器日志记录、崩溃转储等。 在PHP端,将生成一个临时私钥(它将在短时间后过期)。调用方(Javascript)负责在公钥过期时请求新公钥。私钥过期的原因是为了防止记录的加

我想用JavaScript加密,用PHP解密,使用公钥加密。我一直在努力寻找能够实现这一点的库,但我遇到了一些问题

我目前正在查看,但我需要所有浏览器的支持,甚至测试页面在唯一列出的受支持浏览器(Google Chrome)上也有错误

关于最终目标的说明:

TCP连接已受SSL保护。此保护层的主要目的是防止有意或无意的Web服务器日志记录、崩溃转储等。

在PHP端,将生成一个临时私钥(它将在短时间后过期)。调用方(Javascript)负责在公钥过期时请求新公钥。私钥过期的原因是为了防止记录的加密数据解密,以防存储私钥的服务器稍后被破坏

服务器受损场景:有人获得了除数据库服务器之外的所有计算机的备份(并且由于防火墙而无法访问数据库,即使他发现了用户和密码)。由于对记录的数据进行加密的私钥已不存在,攻击者无法采取任何措施。

签出

这是一个node.js模块

此模块提供从OpenSSL访问RSA公钥例程的功能。 支持仅限于RSAES-OAEP和使用公钥加密、使用私钥解密

也许你可以把它移植到浏览器中运行

更新

RSA客户端javascript库:(pidcrypt已正式停止使用,网站域已过期-请参阅@jack's answer,其中包含与pidcrypt相同的库)

PHP服务器端组件:

祝你好运

RSA(js)和(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);
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);
这是基于,这是一个对称(私钥)加密系统。但由于重量轻,它可能对您有用


现在是:

我在我的登录页面上使用了类似的东西;它使用给定的公钥信息(N,e)加密登录凭证,这些信息可以在PHP中解密

它使用以下文件,这些文件是的一部分:

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

在实现RSA时要小心。事实上,您可能根本不应该使用RSA。()

即使您使用的是一个库(例如,PHP的OpenSSL扩展直接或直到最近),仍然有很多地方可能出错。特别是:

  • PKCS1v1.5填充是默认模式(在许多情况下是唯一受支持的填充模式),易受一类称为填充oracle的选定密文攻击的攻击。这是丹尼尔·布莱肯巴赫首先发现的1998年。
  • RSA不适合对大型消息进行加密,因此实现人员通常会将一条长消息拆分为固定大小的块,然后分别对每个块进行加密。这不仅速度慢,而且与对称密钥加密类似
最好的办法是用LibNa 在走这条路之前,你可能想读几遍。但那是说

  • 将TLSv1.2与HST和HPKP一起使用,最好与ChaCha20-Poly1305和/或AES-GCM以及ECDSA-P256证书一起使用(重要提示:当IETF命名为Curve2519和Ed25519时,切换到该证书)
  • 添加到您的项目中
  • 使用带有公钥的
    crypto\u box\u seal()
  • 在PHP中,使用公钥对应的密钥对消息进行解密
  • 我需要使用RSA来解决这个问题。 。椭圆曲线密码术更快、更简单,而且在没有旁道的情况下更容易实现。大多数库已经为您完成了这项工作。(利伯纳!)

    但是我真的很想使用RSA! 好的,跟着做,当你犯了一个错误(比如)使你的密码系统变得无用时,不要哭着来找StackOverflow

    一个旨在提供简单易用的RSA加密的选项(不附带补充的JavaScript实现,请不要要求)是

    • 它通过使用而不是PKCS1v1.5来避免填充oracle
    • 它通过巧妙的协议设计避免了ECB模式:
    EasyRSA加密协议
  • EasyRSA生成用于对称密钥加密的随机128位密钥(通过AES)
  • 您的明文信息是用加密的
  • 您的AES密钥使用RSA加密,RSA由提供,使用正确的模式(如上所述)
  • 此信息打包为一个简单字符串(带校验和)
  • 但是,事实上,如果您找到了一个有效的公钥加密用例,那么您需要的是libnail

    好处:用JavaScript加密,用PHP解密 我们将用它来实现这个目标。(摘自)

    const publicKey=x25519 publicKey.from('FB1A219011C1E0D1769990EF22723E8A2B6E3B52DBC268D763DF4B0C002E73','hex');
    异步函数sendEncryptedMessage(){
    let key=等待getExampleKey();
    let message=$(“#用户输入”).val();
    let encrypted=等待钠。加密箱密封(消息、公钥);
    $.post(“/send message”,{“message”:加密的.toString('hex')},函数(响应){
    控制台日志(响应);
    $(“#输出”).append(“
  • ”+response.message+”
  • ”); }); }
    然后是一致的PHP代码:


    node.js是服务器端。服务器端javascript模块不能在浏览器端重用,因为它依赖于
    
    $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;
    }
    
    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>");
        });
    }
    
    <?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
    );