首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在JavaScript中解密OAEP RSA (如PHP的openssl_private_decrypt)

在JavaScript中解密OAEP RSA (如PHP的openssl_private_decrypt)
EN

Stack Overflow用户
提问于 2021-12-19 03:39:41
回答 1查看 705关注 0票数 2

我目前正在PHP中加密数据,如下所示:

代码语言:javascript
复制
//$sMessage is the input to encrypt.
//$sPublicKey is the public key in PEM format.
openssl_public_encrypt($sMessage, $sEncrypted, $PublicKey, OPENSSL_PKCS1_OAEP_PADDING);
//$sEncrypted will now store the resulting text.

下面是一个用于在PHP中生成密钥的代码示例:

代码语言:javascript
复制
  $aConfig = array(
    "digest_alg" => "sha256",
    "private_key_bits" => 4096,
    "private_key_type" => OPENSSL_KEYTYPE_RSA,
  );
  $res = openssl_pkey_new($aConfig);
  //$sPassPhrase is the pass phrase.
  openssl_pkey_export($res, $sPrivateKey, $sPassPhrase);
  //$sPrivateKey is the key (in PEM format).

我的解密是使用一个被密码保护的私钥。

代码语言:javascript
复制
//$sPrivateKeyWithPassPhrase is the protected private key in PEM format.
//$sPassPhrase is the pass phrase to protect the key.
$newRes = openssl_pkey_get_private($sPrivateKeyWithPassPhrase, $sPassPhrase);
//$sEncrypted is the encrypted text (ciphertext).
openssl_private_decrypt($sEncrypted, $sDecrypted, $newRes, OPENSSL_PKCS1_OAEP_PADDING);
//$sDecrypted is the decrypted text (plaintext)

我还了解了如何使用密码库(你可以在这里学到)对Python进行解密:

代码语言:javascript
复制
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

#passphrase is the pass phrase
passphrase_bytes = bytes(passphrase, 'utf-8')
#privatekey is the encrypted private key
private_key = serialization.load_pem_private_key(
    privatekey,
    password=passphrase_bytes,
)
#ciphertext is the text to be decrypted
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA1()),
        algorithm=hashes.SHA1(),
        label=None
    )
)
#plaintext will be the decrypted result.

然而,我一直在努力在JavaScript中找到一个类似的函数。

到目前为止,我找到的最好的答案是这个:RSA加密Javascript

然而,似乎键并不是PEM格式的,当我进入pidCrypt主页获取更多文档时,这是一个404错误。

我也找到了这个:Node JS中的符号等效

一般来说,NodeJS库似乎具有正确的功能,但当我浏览NodeJS文档时,快速启动指南似乎建议,为了使用NodeJS,必须首先安装软件并设置web服务器。根据如何在浏览器上运行node.js客户端的说法,不可能"Node.js不是浏览器javascript,其中有许多部分使用浏览器上下文中不可用的OS功能。“(我希望能在客户端的原生浏览器中运行。)

有人在评论中建议我可以使用WebCrypto。经过一番努力才找到下载它的地方,我发现它实际上是浏览器固有的(这是一个令人愉快的惊喜)。但是,我还没有弄清楚如何从文档中导入PEM密钥,当我生成一个键然后导出它时,唯一可用的格式是"jwk“(某种JavaScript对象)、"spki”(某种数组缓冲区)和"pkcs8“(我只得到了DOMException: key是不可提取的)。没有什么看起来像OpenSSL PEM格式。(我相信这是PKCS1。)

当我执行"crypto.subtle.importKey“时,它需要5个不同的参数(格式、keyData、算法、可提取性、keyUsages)。所有这些都不接受PEM字符串。经过一番挣扎之后,我确实找到了来自PEM的SubtleCrypto importKey,它证实,如果您想要通过操作导入一个PEM公钥,那么它是可能的,但是这是用于PEM格式的公钥,而且我不知道如何处理pass短语(实际上,我不想手工编写这些代码)。然后,我找到了如何导入PEM格式的RSA私钥以便与WebCrypto一起使用?crypto.subtle :如何导入RSA私钥?,但是那些人基本上告诉我,除非我使用命令行OpenSSL将私钥转换成PKCS8,否则这是不可能的(这也必须单独安装,我记得在Windows上是很痛苦的)。一旦我越过了这个障碍,我仍然不确定如何在PKCS8中获得一个等价的传球短语保护。我希望有类似的东西,在理想情况下支持PKCS1来执行上面的PHP和Python代码,并且我可以在本地浏览器中100%地运行它。(导入更多JavaScript代码是可以的。)

理想情况下,我希望找到一个简单的工作JavaScript示例,用于OpenSSL RSA解密,相当于上面的PHP或OpenSSL示例。如果我有私钥PEM字符串、pass短语和密码文本,它可以返回明文。

非常感谢!我很感激你的帮助,你能帮我节省很多时间!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-23 04:35:19

PKCS#1与PKCS#8

请注意,虽然在PHP中生成的不带pass短语的私钥是PKCS#1,但是使用pass短语生成的私钥实际上是PKCS#8 (关于如何确定哪种标准适用于私钥,请参见此链接 )。

第三方图书馆需要

为了使用PEM格式的密钥,需要一个自定义JavaScript库(或其他自定义代码)。在这个链接上有各种各样的库,您可以查看。很多已经不再维护了。

本例使用Forge JavaScript库,但也可以使用不同的库。

安装/导入Forge

虽然有构建Forge环境的各种方法,但最简单的方法是在需要进行加密/解密之前添加以下HTML代码:

代码语言:javascript
复制
<script src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js"></script>

实现RSA解密

以下JavaScript代码将使用具有密码保护的私钥的Forge库执行解密:

代码语言:javascript
复制
// Import an PKCS#8 encrypted key from PHP
//sEncPkcs8Pem = The encrypted PEM key in a string.
//sPassPhrase = A pass phrase string to use for decryption.
//bCipherText = The encrypted cipher text (string of bytes).
var encryptedPrivateKeyInfo = forge.pki.encryptedPrivateKeyFromPem(sEncPkcs8Pem);
var privateKeyInfo = forge.pki.decryptPrivateKeyInfo(encryptedPrivateKeyInfo, sPassPhrase);
var pkcs8Pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);
var privateKey = forge.pki.privateKeyFromPem(pkcs8Pem);
var sDecrypted = privateKey.decrypt(bCipherText, 'RSA-OAEP');
//sDecrypted will store the result.

全工作示例

下面是一个带有4096位键的完整工作示例.JavaScript导入加密私钥(PKCS#8格式,PEM编码)并成功解密密文。

加密密钥和密文都是使用已发布的PHP代码生成的。

应用的JavaScript库是https://github.com/digitalbazaar/forge

代码语言:javascript
复制
<script src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js"></script>

<p style="font-family:'Courier New', monospace;" id="pt"></p>

<script>
var encPkcs8Pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----
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
ij9mm4GhutigIoP4Wx/NUA==
-----END ENCRYPTED PRIVATE KEY-----`; // 4096 bit key!

// Import an PKCS#8 encrypted key from PHP
var encryptedPrivateKeyInfo = forge.pki.encryptedPrivateKeyFromPem(encPkcs8Pem);
var privateKeyInfo = forge.pki.decryptPrivateKeyInfo(encryptedPrivateKeyInfo, prompt("Enter pass phrase", "testkey"));
var pkcs8Pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);
var privateKey = forge.pki.privateKeyFromPem(pkcs8Pem);

// Decrypt ciphertext from PHP
var ciphertext = forge.util.decode64("lHIspL7aAlnbUdQn6VVY2AS3Ybs/H0fK7N4owfPe6OtzMmX88XOI+2FyEnNyCal6krnfdHYa2JWeWAsyLf484sT2BmvNPxWyYsrnpulKog0lhkeUFppGdhdOHCf7KU47L5p6uYtZmv926ACfhwqMo4M66n/Gkliocol+esavVcfZcjuAw+ELnYkx/TufinR772jBLxVWueGyGcEokI9osDCDpXptmJqpiNRzIrf2kHdk2F/bXRPyE+vrQKFzbyMSpBj3xKtsYDiJ5xDq0qtYY+GCRJNMucPFqOTiFN18EE3z8y/tq5n9Ae/VS8wMxn51rB5JBRmYg3vlM4JLolqNnP3t8OD+DqAeavYjAnairLV0esxzjdkUDpfmFrsYBZWfe5rMzO55drDdsQpGI9LGeX5/TUQpqJWBNZ7QXnbxEiQ2ATXH+ToaeZe3mMkPKuogKM2aEViLzdYB0plbQnoWPAG4OH9pYPGj1KYwdQG5UoF0Ew6Y93uSG3uJ6mcdZZ9gJA0+hpVHOchuAvtZ+vuIV4tzWGfvvnAND54U5sS95EGRj8w/ukgswgOfg/k9iKN3Xlh5N23BYyoLajZVN92cVw6I3XpNOWjlHcO04EhLXaxIeaEMsYYqq3GDBtxpbXfARVjokMeKkKUKNwVscpVneq6WXGtfiMGwXpF8MfoGigE=");
var decrypted = privateKey.decrypt(ciphertext, 'RSA-OAEP');
document.getElementById("pt").innerHTML = "Decrypted: " + decrypted;
</script>

备注:,我想感谢Topaco的帮助和最初的答案,这是基于这个。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70408813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档