在 Javascript 中加密数据,使用 private/public 密钥在 C# 中解密数据
Encrypt data in Javascript, Decrypt data in C# using private/public keys
我想在发送到我的 C# 后端并在那里解密的 Web 浏览器中加密数据。
失败,因为我无法在后端解密前端生成的数据。
这是我目前所做的。
首先,我创建了一个 private/public 密钥对(XmlString 格式)。我使用 ExportPublicKey
函数从这里生成 public 密钥文件:
private static void GeneratePrivatePublicKeyPair() {
var name = "test";
var privateKeyXmlFile = name + "_priv.xml";
var publicKeyXmlFile = name + "_pub.xml";
var publicKeyFile = name + ".pub";
using var provider = new RSACryptoServiceProvider(1024);
File.WriteAllText(privateKeyXmlFile, provider.ToXmlString(true));
File.WriteAllText(publicKeyXmlFile, provider.ToXmlString(false));
using var publicKeyWriter = File.CreateText(publicKeyFile);
ExportPublicKey(provider, publicKeyWriter);
}
现在我可以使用 public 密钥在我的前端加密数据。
(() => {
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg
28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b
uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS
al4bIU7XMwppkR3KNQIDAQAB
-----END PUBLIC KEY-----`;
function getSpkiDer(spkiPem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
var pemContents = spkiPem.substring(
pemHeader.length,
spkiPem.length - pemFooter.length
);
var binaryDerString = window.atob(pemContents);
return str2ab(binaryDerString);
}
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
"spki",
getSpkiDer(spkiPem),
{
name: "RSA-OAEP",
hash: "SHA-256",
},
true,
["encrypt"]
);
}
async function encryptRSA(key, plaintext) {
let encrypted = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
},
key,
plaintext
);
return encrypted;
}
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));
}
async function encrypt(plaintext) {
const pub = await importPublicKey(publicKey);
const encrypted = await encryptRSA(
pub,
new TextEncoder().encode(plaintext)
);
const encryptedBase64 = window.btoa(ab2str(encrypted));
console.log(encryptedBase64);
}
encrypt("I want to decrypt this string in C#");
})();
但是:如果我想在我的后端再次解密代码,这会失败
private static void Decrypt()
{
var name = "test";
var encryptedBase64 = @"Rzabx5380rkx2+KKB+HaJP2dOXDcOC7SkYOy4HN8+Nb9HmjqeZfGQlf+ZUa6uAfAJ3oAB2iIlHlnx+iXK3XDIX3izjoW1eeiNmdOWieNCu6YXqW4denUVEv0Z4EpAmEYgVImnEzoMdmPDEcl9UHgdWUmS4Bnq6T8Yqh3UZ/4NOc=";
var encrypted = Convert.FromBase64String(encryptedBase64);
using var privateKey = new RSACryptoServiceProvider();
privateKey.FromXmlString(File.ReadAllText(name + "_priv.xml"));
var decryptedBytes = privateKey.Decrypt(encrypted, false);
var dectryptedText = Encoding.UTF8.GetString(decryptedBytes);
}
我试过 privateKey.Decrypt(encrypted, false);
抛出
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Wrong parameter
CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData)
RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
和 privateKey.Decrypt(encrypted, false);
抛出
System.Security.Cryptography.CryptographicException: Cryptography_OAEPDecoding,
CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData)
RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
注意:我验证了我可以使用 xml 格式的 private_key/public 键在后端成功 encrypt/decrypt 数据。
并且我验证了我可以使用
在前端成功地 encrypt/decrypt 数据
private/public PEM 格式的密钥。
不起作用的是用 C# 解密在前端用 javascript 加密的字符串。
我做错了什么?
供参考(为此目的而生成)
私钥
-----BEGIN PRIVATE KEY-----
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMbLxu2tudI0/Pu9
Yp9BcrEpfODbxkPyMIB3uAZh9QgWoqpRyiAda3mDIa9OASHAHAE/WRitWcGWEHae
5YctikkMjpu4Gioqse2tx2Bewq6ZI/Q4qmfSdtjGSc681hWNRRHqmUxuhQFpZfWg
qhHqk3NMQdJqXhshTtczCmmRHco1AgMBAAECgYEAokAVN02wOQm4ZPp4cMSpCEF1
Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZ
GOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/
UdQm3jho086iQF9UOo0CQQDjjhZl/fOqqb9nvW3rvSNwsdzSYoGpfx22uzrJplN2
wpFO6XCorAGMO6lHI3Ua8A0OSNO1ybkhG2iZOkPoEGWHAkEA36VhsUFNQr4RO7gL
oWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6
EtcBYwJBAKRTtIsc1D0XbljdLCcEJDa6yuvHJTmgyXVvSenbSgTGRycEX03/QPLj
FsB/s46rcdIx92kc7qsg3u1gbS+Fv7sCQQC5QHaxqxPiayo/O2524FuQ0v5hda6s
rXDTZhdACnF3sKQPdgGeeeKPlXshczDxOVERh0BnnwEXZlwE4rzZijtdAkEA2gXb
e/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5
LrC2qjX4SMEUbMTkNg==
-----END PRIVATE KEY-----`
public键
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg
28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b
uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS
al4bIU7XMwppkR3KNQIDAQAB
-----END PUBLIC KEY-----
私钥xml
<RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent><P>444WZf3zqqm/Z71t670jcLHc0mKBqX8dtrs6yaZTdsKRTulwqKwBjDupRyN1GvANDkjTtcm5IRtomTpD6BBlhw==</P><Q>36VhsUFNQr4RO7gLoWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6EtcBYw==</Q><DP>pFO0ixzUPRduWN0sJwQkNrrK68clOaDJdW9J6dtKBMZHJwRfTf9A8uMWwH+zjqtx0jH3aRzuqyDe7WBtL4W/uw==</DP><DQ>uUB2sasT4msqPztuduBbkNL+YXWurK1w02YXQApxd7CkD3YBnnnij5V7IXMw8TlREYdAZ58BF2ZcBOK82Yo7XQ==</DQ><InverseQ>2gXbe/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5LrC2qjX4SMEUbMTkNg==</InverseQ><D>okAVN02wOQm4ZPp4cMSpCEF1Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZGOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/UdQm3jho086iQF9UOo0=</D></RSAKeyValue>
public键xml
<RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
更新
只是为了明确我想要实现的目标。我知道在浏览器中使用 private 可能不是一个好主意。但就我而言,这是必需的:
应用 1
需要使用 Web NFC 将加密数据写入 NDEF 标签的内部 Web 应用 API 并且需要私钥。
应用 2
从 NEDF 标签读取加密数据并将其传输到 .NET Web 应用程序(应用程序 3)的 Webapp
应用 3
从App 2读取加密数据并解密。
您需要使用私钥加密,然后使用public密钥
解密
两个代码使用不同的填充,在 JavaScript 端 OAEP(使用 SHA256),在 C# 端 PKCS#1 v1.5。为了能够在 C# 端进行解密,还必须在那里使用带有 SHA256 的 OAEP。
您没有指定 .NET 版本。在 .NET Core 3.0+ 或 .NET 5+ 下解密是可能的,例如与:
...
using var privateKey = RSA.Create();
...
var decryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA256);
...
并以明文形式提供已发布的密文和密钥:下午茶时间的兔子跳。
如果第二个参数设置为 false
,RSACryptoServiceProvider.Decrypt(Byte[], Boolean)
使用 PKCS#1 v1.5。如果第二个参数设置为 true
,则应用 OAEP,但使用 SHA1。
RSACryptoServiceProvider.Decrypt(Byte[], RSAEncryptionPadding)
allows setting OAEP with SHA256, but a runtime error occurs because only SHA1 is supported (s. Remarks).
因此更改为例如RSA.Decrypt(Byte[], RSAEncryptionPadding)
对于使用 SHA256 的 OAEP 是必需的。
除了@Topaco 的正确答案之外,通过在 Javascript 和 C# 中将散列算法更改为 SHA-1,仍然可以在旧版本的 .NET 上解密:
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
"spki",
getSpkiDer(spkiPem),
{
name: "RSA-OAEP",
hash: "SHA-1", //// <- SHA-1 here for older .NET decryption
},
true,
["encrypt"]
);
}
和
using (var privateKey = RSA.Create())
{
privateKey.FromXmlString(privKey);
var dectryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA1);
// ^^^^^^^^^ OaepSHA1 here for older versions of .NET ^^^^^^
var dectryptedText = Encoding.UTF8.GetString(dectryptedBytes);
}
我想在发送到我的 C# 后端并在那里解密的 Web 浏览器中加密数据。
失败,因为我无法在后端解密前端生成的数据。
这是我目前所做的。
首先,我创建了一个 private/public 密钥对(XmlString 格式)。我使用 ExportPublicKey
函数从这里生成 public 密钥文件:
private static void GeneratePrivatePublicKeyPair() {
var name = "test";
var privateKeyXmlFile = name + "_priv.xml";
var publicKeyXmlFile = name + "_pub.xml";
var publicKeyFile = name + ".pub";
using var provider = new RSACryptoServiceProvider(1024);
File.WriteAllText(privateKeyXmlFile, provider.ToXmlString(true));
File.WriteAllText(publicKeyXmlFile, provider.ToXmlString(false));
using var publicKeyWriter = File.CreateText(publicKeyFile);
ExportPublicKey(provider, publicKeyWriter);
}
现在我可以使用 public 密钥在我的前端加密数据。
(() => {
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg
28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b
uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS
al4bIU7XMwppkR3KNQIDAQAB
-----END PUBLIC KEY-----`;
function getSpkiDer(spkiPem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
var pemContents = spkiPem.substring(
pemHeader.length,
spkiPem.length - pemFooter.length
);
var binaryDerString = window.atob(pemContents);
return str2ab(binaryDerString);
}
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
"spki",
getSpkiDer(spkiPem),
{
name: "RSA-OAEP",
hash: "SHA-256",
},
true,
["encrypt"]
);
}
async function encryptRSA(key, plaintext) {
let encrypted = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
},
key,
plaintext
);
return encrypted;
}
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));
}
async function encrypt(plaintext) {
const pub = await importPublicKey(publicKey);
const encrypted = await encryptRSA(
pub,
new TextEncoder().encode(plaintext)
);
const encryptedBase64 = window.btoa(ab2str(encrypted));
console.log(encryptedBase64);
}
encrypt("I want to decrypt this string in C#");
})();
但是:如果我想在我的后端再次解密代码,这会失败
private static void Decrypt()
{
var name = "test";
var encryptedBase64 = @"Rzabx5380rkx2+KKB+HaJP2dOXDcOC7SkYOy4HN8+Nb9HmjqeZfGQlf+ZUa6uAfAJ3oAB2iIlHlnx+iXK3XDIX3izjoW1eeiNmdOWieNCu6YXqW4denUVEv0Z4EpAmEYgVImnEzoMdmPDEcl9UHgdWUmS4Bnq6T8Yqh3UZ/4NOc=";
var encrypted = Convert.FromBase64String(encryptedBase64);
using var privateKey = new RSACryptoServiceProvider();
privateKey.FromXmlString(File.ReadAllText(name + "_priv.xml"));
var decryptedBytes = privateKey.Decrypt(encrypted, false);
var dectryptedText = Encoding.UTF8.GetString(decryptedBytes);
}
我试过 privateKey.Decrypt(encrypted, false);
抛出
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Wrong parameter
CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData)
RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
和 privateKey.Decrypt(encrypted, false);
抛出
System.Security.Cryptography.CryptographicException: Cryptography_OAEPDecoding,
CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData)
RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
注意:我验证了我可以使用 xml 格式的 private_key/public 键在后端成功 encrypt/decrypt 数据。
并且我验证了我可以使用
在前端成功地 encrypt/decrypt 数据private/public PEM 格式的密钥。
不起作用的是用 C# 解密在前端用 javascript 加密的字符串。
我做错了什么?
供参考(为此目的而生成)
私钥
-----BEGIN PRIVATE KEY-----
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMbLxu2tudI0/Pu9
Yp9BcrEpfODbxkPyMIB3uAZh9QgWoqpRyiAda3mDIa9OASHAHAE/WRitWcGWEHae
5YctikkMjpu4Gioqse2tx2Bewq6ZI/Q4qmfSdtjGSc681hWNRRHqmUxuhQFpZfWg
qhHqk3NMQdJqXhshTtczCmmRHco1AgMBAAECgYEAokAVN02wOQm4ZPp4cMSpCEF1
Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZ
GOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/
UdQm3jho086iQF9UOo0CQQDjjhZl/fOqqb9nvW3rvSNwsdzSYoGpfx22uzrJplN2
wpFO6XCorAGMO6lHI3Ua8A0OSNO1ybkhG2iZOkPoEGWHAkEA36VhsUFNQr4RO7gL
oWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6
EtcBYwJBAKRTtIsc1D0XbljdLCcEJDa6yuvHJTmgyXVvSenbSgTGRycEX03/QPLj
FsB/s46rcdIx92kc7qsg3u1gbS+Fv7sCQQC5QHaxqxPiayo/O2524FuQ0v5hda6s
rXDTZhdACnF3sKQPdgGeeeKPlXshczDxOVERh0BnnwEXZlwE4rzZijtdAkEA2gXb
e/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5
LrC2qjX4SMEUbMTkNg==
-----END PRIVATE KEY-----`
public键
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg
28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b
uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS
al4bIU7XMwppkR3KNQIDAQAB
-----END PUBLIC KEY-----
私钥xml
<RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent><P>444WZf3zqqm/Z71t670jcLHc0mKBqX8dtrs6yaZTdsKRTulwqKwBjDupRyN1GvANDkjTtcm5IRtomTpD6BBlhw==</P><Q>36VhsUFNQr4RO7gLoWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6EtcBYw==</Q><DP>pFO0ixzUPRduWN0sJwQkNrrK68clOaDJdW9J6dtKBMZHJwRfTf9A8uMWwH+zjqtx0jH3aRzuqyDe7WBtL4W/uw==</DP><DQ>uUB2sasT4msqPztuduBbkNL+YXWurK1w02YXQApxd7CkD3YBnnnij5V7IXMw8TlREYdAZ58BF2ZcBOK82Yo7XQ==</DQ><InverseQ>2gXbe/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5LrC2qjX4SMEUbMTkNg==</InverseQ><D>okAVN02wOQm4ZPp4cMSpCEF1Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZGOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/UdQm3jho086iQF9UOo0=</D></RSAKeyValue>
public键xml
<RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
更新
只是为了明确我想要实现的目标。我知道在浏览器中使用 private 可能不是一个好主意。但就我而言,这是必需的:
应用 1
需要使用 Web NFC 将加密数据写入 NDEF 标签的内部 Web 应用 API 并且需要私钥。
应用 2
从 NEDF 标签读取加密数据并将其传输到 .NET Web 应用程序(应用程序 3)的 Webapp
应用 3
从App 2读取加密数据并解密。
您需要使用私钥加密,然后使用public密钥
解密两个代码使用不同的填充,在 JavaScript 端 OAEP(使用 SHA256),在 C# 端 PKCS#1 v1.5。为了能够在 C# 端进行解密,还必须在那里使用带有 SHA256 的 OAEP。
您没有指定 .NET 版本。在 .NET Core 3.0+ 或 .NET 5+ 下解密是可能的,例如与:
...
using var privateKey = RSA.Create();
...
var decryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA256);
...
并以明文形式提供已发布的密文和密钥:下午茶时间的兔子跳。
如果第二个参数设置为
false
,RSACryptoServiceProvider.Decrypt(Byte[], Boolean)
使用 PKCS#1 v1.5。如果第二个参数设置为 true
,则应用 OAEP,但使用 SHA1。
RSACryptoServiceProvider.Decrypt(Byte[], RSAEncryptionPadding)
allows setting OAEP with SHA256, but a runtime error occurs because only SHA1 is supported (s. Remarks).
因此更改为例如RSA.Decrypt(Byte[], RSAEncryptionPadding)
对于使用 SHA256 的 OAEP 是必需的。
除了@Topaco 的正确答案之外,通过在 Javascript 和 C# 中将散列算法更改为 SHA-1,仍然可以在旧版本的 .NET 上解密:
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
"spki",
getSpkiDer(spkiPem),
{
name: "RSA-OAEP",
hash: "SHA-1", //// <- SHA-1 here for older .NET decryption
},
true,
["encrypt"]
);
}
和
using (var privateKey = RSA.Create())
{
privateKey.FromXmlString(privKey);
var dectryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA1);
// ^^^^^^^^^ OaepSHA1 here for older versions of .NET ^^^^^^
var dectryptedText = Encoding.UTF8.GetString(dectryptedBytes);
}