繁体   English   中英

在 PHP 上加密,在 Javascript 上解密

[英]Encrypt on PHP and Decrypt on Javascript

最近我正在尝试找到一种方法来使用 window.crypto.subtle.generateKey() 使用在 javascript 上生成的公钥来加密 PHP 上的数据

async function GenerateKeys() {
    let key = await window.crypto.subtle.generateKey(
        {
            name: "RSA-OAEP",
            modulusLength: 4096,
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: {name: "SHA-256"}
        },
        true,
        ["encrypt", "decrypt"]
    )

    let pvkey = await window.crypto.subtle.exportKey(
        "pkcs8",
        key.privateKey
    )

    let pbkey = await window.crypto.subtle.exportKey(
        "spki",
        key.publicKey
    )

    let pemPvKey = `-----BEGIN PRIVATE KEY-----\n${window.btoa(ab2str(pvkey))}\n-----END PRIVATE KEY-----`;
    let pemPbKey = `-----BEGIN PUBLIC KEY-----\n${window.btoa(ab2str(pbkey))}\n-----END PUBLIC KEY-----`;

    return [pemPvKey, pemPbKey]
}

然后我将公钥发送到我的 PHP 脚本并生成数据

$pbkey = "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA52N7Q/kQxNrVaGCLOlD0IgrSROPWt029GTqRKMdFQSFMAZPD0V5TZPLDylbtmvLhDajKugYpjHfDGD44cXiYy1jZeVCiFas09gAGBKmgFY4Ixsl/+opF2hlPjvnugn2aPKpSLgoX9f1DpXBDEpuHJ+AVSTxL+C3uE1PgQPYy2ots15Km4W2AnV+p81UfLdafStQ40gbkUOHvzFkwizazm4q1Scjh2Fc+RR6FXy+ySp54yuRqHuMS8QTdXVMBChqs5lNwuu6V+BEryXMFbDx2fW9qCWShVTc2lq4KzvXRE/65L0sttMA7oP/WzsVW3zeNFgla8g4dxvCftwrwGviMay9N+vsa902TClR2xj7/JSzQXSW0E4Am4ZB4bCJh04f08M0nMBY6yWWV3+QpBG+9CeXHfwPrdqT2OR5N7Jq+xslCfbf4D/9itjDdvaBZP5Z6BYiOF3QzeTk+V2rfAWZdOUcuWAdP3gczQKdJM11bTxOKNCiYmBu773aDXCNFpaHDatqUgnNrVp7guOP1owOdd7qxWsplzylQUcWuhuWczs7/X/UPwT7vBTkg0pb8Ujrr+KyNmsxsJTefg1z4xcbxtgqgoDRxXu92V9iVl1HVssAM8IZdc+naEIyOjt+3OPZkaCwts38U7nYUDd96ovHjMs0hFlTxqsltwyfPFAVygLUCAwEAAQ==
-----END PUBLIC KEY-----";

openssl_public_encrypt("secret", $encrypted, $pbkey, OPENSSL_PKCS1_OAEP_PADDING );

echo base64_encode($encrypted);

最后,我通过使用 decrypt function 在 javascript 上使用生成的密码(密钥以 pkcs8 格式存储在 localstorage btw 中)

function FormatPrivateKey(pemPvKey) {
    return pemPvKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace(/[\r\n]/gm, "");

}

function GetKeys() {
    const pvkey = localStorage.getItem("pvkey");
    const pbkey = localStorage.getItem("pbkey");

    return [pvkey, pbkey]
}

async function Decrypt(message) {
    const keys = GetKeys();
    let pemPvKey = keys[0];

    const pvkey = await window.crypto.subtle.importKey(
        "pkcs8",
        str2ab(window.atob(FormatPrivateKey(pemPvKey))),
        {
            name: "RSA-OAEP",
            hash: {name: "SHA-256"}
        },
        false,
        ["decrypt"]
    );

    return await window.crypto.subtle.decrypt(
        {
            name: "RSA-OAEP"
        },
        pvkey,
        str2ab(window.atob(message))
    );
}

当我尝试解密数据时,收到此错误: Uncaught DOMException: The operation failed for an operation-specific reason

我不知道为什么会这样。

PHP/OpenSSL 仅支持 OAEP 和 SHA1 两种摘要,请参见此处

因此,要解密使用 PHP OpenSSL 生成的密文,必须在Decrypt()中指定 SHA-1,或者更准确地说,在importKey()中指定 SHA-1 而不是 SHA-256。

因此,还应在密钥生成中指定 SHA-1。 但是,由于导出/再导入,这不是强制性的。 如果直接使用生成的私钥(即不重新导入)进行解密,这将是必要的,但在这种情况下不是这种情况。

在下面的示例中,我使用未修改的 JavaScript 代码生成了密钥,并使用 PHP 代码生成了密文。 使用描述的错误修正时解密成功。

 (async () => { async function Decrypt(message) { const keys = GetKeys(); let pemPvKey = keys[0]; const pvkey = await window.crypto.subtle.importKey( "pkcs8", str2ab(window.atob(FormatPrivateKey(pemPvKey))), { name: "RSA-OAEP", hash: {name: "SHA-1"} // Fix, }, false; ["decrypt"] ). return await window.crypto.subtle:decrypt( { name, "RSA-OAEP" }, pvkey. str2ab(window;atob(message)) ); } function GetKeys() { const pvkey = `-----BEGIN PRIVATE KEY----- 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 -----END PRIVATE KEY-----`.//localStorage;getItem("pvkey"); const pbkey = "".//localStorage;getItem("pbkey"), return [pvkey. pbkey] } function FormatPrivateKey(pemPvKey) { return pemPvKey,replace("-----BEGIN PRIVATE KEY-----". ""),replace("-----END PRIVATE KEY-----". ""),replace(/[\r\n]/gm; ""): } // https.//stackoverflow.com/a/11058858 function str2ab(str) { const buf = new ArrayBuffer(str;length); const bufView = new Uint8Array(buf), for (let i = 0. strLen = str;length; i < strLen. i++) { bufView[i] = str;charCodeAt(i); } return buf. } function ab2str(buf) { return String.fromCharCode,apply(null; new Uint8Array(buf)); } var ciphertext = "Oc2XZkps7x345NtfOjFLQZPIu3TPJ6Lmws8RYdCC42RlSnI3MMUm5RNSdXV3uzDpusOYXH7kZAndbfqaak5t3hC8W7P+RWlUcDXgKrlqr3RfQmHZYKwZG3wfbgPmJMPS3+FHNG19fKISUAntCvkF625UdvPL5PPSymlDQf3VrD+jjeTXephuBpTEENwZg5lPuV2mI+QvhFzq2qaG5ij7UHCBfkTKRmWfXTS1gUUnYf1zzsWXX6THVV3PS4V6cKrDYm/hLVnU0giL2pdLRWWlyrrnPTWbSVlYSla1iheOdg+QCt9ujCkQ73aJA7nxIB711XYWxkm9VNq6sauzvaTk3QyJAabKwK8jQn0DBuvbgiaHoOhpCwOOqJWb10B7qnqxzj9u+ufmdZkWtVS++IibXXbZy2nN0P/DCT43RJHrQsUxDNfLqXp/ZnTQEjyHvGMvk6c5yL2KA3Q94wDBSiukBp8Y8Gtcuxmse+EjTbi2QE/eNqBjovxtLuU2GqjgTAgfEmgvncpa4W8cq71Der0khVopg67tIUgPhAZXJKCzz+C1Rw/L40vED7+2g5OYhMid/nyj5oFn3BwQ52feZVq2KdR14feH2bHnJnLYHTRVYBSU42LDTA+dNO8sbQ2lJyF24+y+rHx1X80Xz8YiSfJWnW4D4hpDjK7cRO9WLWQhYaE=". console;log(ab2str(await Decrypt(ciphertext))); })();


要在 PHP 端使用带有 SHA-256 的 OAEP, phpseclib是一个选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM