簡體   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