【发布时间】:2021-01-23 10:15:26
【问题描述】:
我已经用 c# 创建了 xml 键:
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider (2048);
string str = RSA.ToXmlString (true);
System.IO.File.WriteAllText (@"c:\path\to\keypair.xml", str);
然后使用this online tool,我将 XML 密钥转换为 pem 私钥。 然后使用开放的 SSL,我从私钥中提取了公钥:
openssl rsa -in ./private.pem -pubout -out public.pem
使用 public.pem 我正在加密 Node 中的秘密字符串:
const encryptWithRsa = (secretStringToEncrypt) => {
const publicKeyPath = path.join(appRoot, `${process.env.PUBLIC_KEY_PATH}`);
const publicKeyString = fs.readFileSync(publicKeyPath, 'utf8');
const buffer = Buffer.from(secretStringToEncrypt, 'utf8');
const encrypted = crypto.publicEncrypt({
key: publicKeyString,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
}, buffer);
const encryptedString = encrypted.toString('base64');
console.log("encryptWithRsa -> encryptedString", encryptedString);
return encryptedString;
};
然后我尝试在 c# 中解密字符串:
public string RSADecrypt (string encryptedStringFromNode) {
string keyPair = System.IO.File.ReadAllText (@"c:\path\to\keypair.xml");
using var csp = new RSACryptoServiceProvider ();
ImportKey (csp, keyPair);
var decrypted = csp.Decrypt (Convert.FromBase64String (encryptedStringFromNode), true);
return Encoding.UTF8.GetString (
decrypted
);
}
public void ImportKey (RSA rsa, string xmlKey) {
var parameters = new RSAParameters ();
var xmlDoc = new XmlDocument ();
xmlDoc.LoadXml (xmlKey);
if (xmlDoc.DocumentElement.Name.Equals ("RSAKeyValue")) {
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes) {
var value = ToByteArray (node.InnerText);
switch (node.Name) {
case nameof (parameters.Modulus):
parameters.Modulus = value;
break;
case nameof (parameters.Exponent):
parameters.Exponent = value;
break;
case nameof (parameters.P):
parameters.P = value;
break;
case nameof (parameters.Q):
parameters.Q = value;
break;
case nameof (parameters.DP):
parameters.DP = value;
break;
case nameof (parameters.DQ):
parameters.DQ = value;
break;
case nameof (parameters.InverseQ):
parameters.InverseQ = value;
break;
case nameof (parameters.D):
parameters.D = value;
break;
}
}
} else {
throw new Exception ("");
}
rsa.ImportParameters (parameters);
}
public byte[] ToByteArray (string input) {
return string.IsNullOrEmpty (input) ? null : Convert.FromBase64String (input);
}
但是当我尝试解密由 Node.js 加密的字符串时,出现以下错误:
Exception has occurred: CLR/Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException
An exception of type 'Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException' occurred in
System.Security.Cryptography.Csp.dll but was not handled in user code: 'The parameter is incorrect.'
但是,如果我尝试在 this online tool 上使用相同的公钥进行加密,然后使用我的 C# 代码进行解密,它会起作用并且我会得到原始未加密的字符串。
我在 Node.js 中用于 RSA 加密的 Padding 有什么问题吗?
【问题讨论】:
-
这是一个非常痛苦的 XML 处理。为什么不在 ImportKey 中使用
RSA.FromXMLString()? -
RSACryptoServiceProvider除 PKCS#1v1.5 外仅支持 SHA1 的 OAEP。在 NodeJS 代码中使用了带有 SHA256 的 OAEP,因此使用 C# 代码解密失败。为了解决这个问题,可以在 NodeJS 代码中使用 SHA1。或者,可以在 C# 代码中应用支持 SHA256 的 RSA 实现。这里RSACng是可能的,前提是您正在使用的.NET 版本中提供了它。由于双方也支持 PKCS#1 v1.5,这是另一种选择(见 Michael Fehr 的回答)。 -
哪行代码导致异常?
-
@Topaco - 使用 RSA_PKCS1_OAEP_PADDING 和 sha1 解决了这个问题。
标签: javascript c# node.js encryption rsa