当前位置: 首页 > 知识库问答 >
问题:

无法解密节点中使用RSA公钥加密的C#中的字符串。js

丁曦
2023-03-14

我已经用c#创建了xml密钥:

RSACryptoServiceProvider RSA = new RSACryptoServiceProvider (2048);
string str = RSA.ToXmlString (true);
System.IO.File.WriteAllText (@"c:\path\to\keypair.xml", str);

然后使用这个在线工具,我将XML密钥转换为pem私钥。然后使用open 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);
        }

但当我试图解密由节点加密的字符串时。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.'

但是,如果我尝试在这个在线工具上用相同的公钥加密,然后用我的C#代码解密,它会工作,我会得到原始的未加密字符串。

我在N中用于RSA加密的填充有任何问题ode.js?

共有1个答案

南门英飙
2023-03-14

首先,很抱歉,我懒得分析代码来找出失败的真正原因。大多数情况下,平台之间的填充不匹配,定义参数始终是一种很好的编程技术,即使这些参数被称为“标准”或“默认”,因为它们在将来可能会更改。

在我的示例中,我将PKCS1填充用于RSA加密,这在两种平台上都可用。

第二:我想使用在线编译器进行演示,所以我使用固定/字符串公钥和私有RSA密钥。请注意,我使用的是*不安全的RSA密钥对,密钥长度为512位(只是为了缩短密钥字符串),是-密钥是示例密钥。

第三:这两种解决方案仅用于教育目的,因为它们没有任何异常处理。

第四:这两种解决方案都提供了“整轮”意味着既进行加密又进行解密,C#程序用来自节点的加密字符串进行第二次解密。JS-解决方案。

这是节点的输出。JS程序(在这里运行它:https://repl.it/@jav丙烯酸/RSAEnCryptionNodeJstoC):

enc: QPCE4WtNPLFGjWvwpN/JTITdr2k9IhGrsohuW0yPue4dQ2Cv63i+LlohmjsSUcnaiB/zbeItGDIx3s11ayBIUA==
dec: The quick brown fox jumps over the lazy dog

如果运行C#版本,您将获得以下输出(在此处运行:https://repl.it/@javacrypto/RSADecryptionCfromNodeJs-1)

encryptedData: jnAyBvjvjG/NXc/HUmfrTks3SWgeYz3HEksPvk9D9eH/DF0PK6nZu36wTAeZ/fHr3v8dWYwXtT8nXZgvokJJYg==
decryptedData: The quick brown fox jumps over the lazy dog
original Data: VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==
*** enc string from NodeJs ***
decryptedData: The quick brown fox jumps over the lazy dog

节点。JS代码:

const crypto = require('crypto')

// SECURITY WARNING: these sample keys are UNSECURE 512 bit long RSA keys
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJn4LYaoLyuT+pD9NKI8wOvPrRjMIxGn
HbqIxUrpGsyj162fEOV4836oCZg0N8HFnt4Vivdjt8/7ZgLjeOygNGUCAwEAAQ==
-----END PUBLIC KEY-----`;

const privateKey = `-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAmfgthqgvK5P6kP00
ojzA68+tGMwjEacduojFSukazKPXrZ8Q5XjzfqgJmDQ3wcWe3hWK92O3z/tmAuN4
7KA0ZQIDAQABAkEAmCpGy/rxS08e5iXn26LRQvvm5UfyLKMNZWmAGk2QF8cRGFB7
dds/SI9wGTC9xyOoF4N2kWzYdLx+dYbR9lqwbQIhAPFQkWqNIWZiL+YFRhS6jg/+
5+k0CpXpAPelNUFc4pijAiEAo1bchWA5ddDd59FED37QcrakoTXNoxRspFtsLDKE
p1cCIQC6AXRVQTvBg2WQU/hU+geO5Nk1tFuEefm46atHGqW/KQIgXoGggC9Hr8pU
yo9DIPAP7X+Ny5TU0Vm87m/TK9Ni+2sCIGKjhxD/HYAr8+UPJ4aUIHayn3ZZo5DQ
BcShe496ZtPS
-----END PRIVATE KEY-----`;

function encrypt(toEncrypt, relativeOrAbsolutePathToPublicKey) {
  //const absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey)
  //const publicKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toEncrypt, 'utf8')
  var constants = require("constants");
  const encrypted = crypto.publicEncrypt(
  {"key":publicKey, padding:constants.RSA_PKCS1_PADDING}, buffer)
  return encrypted.toString('base64')
}

function decrypt(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
  //const absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey)
  //const privateKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toDecrypt, 'base64')
  var constants = require("constants");
  const decrypted = crypto.privateDecrypt(
    {
      key: privateKey.toString(),
      passphrase: '',
      padding:constants.RSA_PKCS1_PADDING,
    },
    buffer,
  )
  return decrypted.toString('utf8')
}

const enc = encrypt('The quick brown fox jumps over the lazy dog')
console.log('enc:', enc)
const dec = decrypt(enc)
console.log('dec:', dec)

C#代码:

using System;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;

class RSACSPSample {
    static void Main() {

        try {
            ASCIIEncoding ByteConverter = new ASCIIEncoding();
            string dataString = "The quick brown fox jumps over the lazy dog";

            // Create byte arrays to hold original, encrypted, and decrypted data.
            byte[] originalData = ByteConverter.GetBytes(dataString);
            byte[] encryptedData;
            byte[] decryptedData;

      // SECURITY WARNING: these sample keys are UNSECURE 512 bit long RSA keys
            // get private and public key
            var publicKey = "<RSAKeyValue><Modulus>mfgthqgvK5P6kP00ojzA68+tGMwjEacduojFSukazKPXrZ8Q5XjzfqgJmDQ3wcWe3hWK92O3z/tmAuN47KA0ZQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
            var privateKey = "<RSAKeyValue><Modulus>mfgthqgvK5P6kP00ojzA68+tGMwjEacduojFSukazKPXrZ8Q5XjzfqgJmDQ3wcWe3hWK92O3z/tmAuN47KA0ZQ==</Modulus><Exponent>AQAB</Exponent><P>8VCRao0hZmIv5gVGFLqOD/7n6TQKlekA96U1QVzimKM=</P><Q>o1bchWA5ddDd59FED37QcrakoTXNoxRspFtsLDKEp1c=</Q><DP>ugF0VUE7wYNlkFP4VPoHjuTZNbRbhHn5uOmrRxqlvyk=</DP><DQ>XoGggC9Hr8pUyo9DIPAP7X+Ny5TU0Vm87m/TK9Ni+2s=</DQ><InverseQ>YqOHEP8dgCvz5Q8nhpQgdrKfdlmjkNAFxKF7j3pm09I=</InverseQ><D>mCpGy/rxS08e5iXn26LRQvvm5UfyLKMNZWmAGk2QF8cRGFB7dds/SI9wGTC9xyOoF4N2kWzYdLx+dYbR9lqwbQ==</D></RSAKeyValue>";

            RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(512); // SECURITY WARNING: 512 is UNSECURE
            RSAalg.PersistKeyInCsp = false;
            // encrypt with xml-public key
      RSAalg.FromXmlString(publicKey);
            encryptedData = RSAalg.Encrypt(originalData, false);
            string encryptedDataBase64 = Convert.ToBase64String(encryptedData);
            Console.WriteLine("encryptedData: " + encryptedDataBase64);

            // decrypt with xml-private key
            RSAalg.FromXmlString(privateKey);
            decryptedData = RSAalg.Decrypt(encryptedData, false);
            Console.WriteLine("decryptedData: " + ByteArrayToString(decryptedData));
            Console.WriteLine("original Data: " + Convert.ToBase64String(originalData));

      Console.WriteLine("*** enc string from NodeJs ***");

      string b64string = "QPCE4WtNPLFGjWvwpN/JTITdr2k9IhGrsohuW0yPue4dQ2Cv63i+LlohmjsSUcnaiB/zbeItGDIx3s11ayBIUA==";
      encryptedData = Convert.FromBase64String(b64string);
      decryptedData = RSAalg.Decrypt(encryptedData, false);
            Console.WriteLine("decryptedData: " + ByteArrayToString(decryptedData));
        }
        catch(ArgumentNullException) {
            Console.WriteLine("error in data en-/decryption");
        }
    }
    
  private static string ByteArrayToString(byte[] arr)
  {
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetString(arr);
  }
}
 类似资料:
  • 在那里~我是新来的flutter开发,我试图使用Node.js服务器发送一个公钥到flutter加密密码但是,它就是不工作,我试图通过JSON格式或通过PEM文件的flutter和使用[Flutter]-加密和[Flutter]-simple_rsa库做加密,但它仍然不能工作。我怎么能这么做?请帮忙,多谢。 [Node.js]-使用[Node rsa]创建密钥[Flatter]-使用[encryp

  • 我找到了几个可以使用的解决方案。Net RSA Provider使用公钥对消息进行加密,并使用私钥对其解密。 但我想要的是用私钥加密,用公钥解密。 我希望在我的应用程序中存储公钥,并使用私钥加密许可证,例如在我的开发人员计算机上,将其发送到应用程序,并让信息使用公钥解密。 我怎样才能做到这一点?

  • 我有一个RSA公钥证书。我可以使用具有。PEM扩展名或仅将其用作具有以下格式的字符串: 启动RSA公共密钥 {KEY} -----结束RSA公钥----- 我试图使用此密钥向服务器发送加密的JSON。我尝试了许多其他相关堆栈溢出问题的解决方案,但没有一个答案不适合我。这个答案似乎有道理https://stackoverflow.com/a/43534042,但有些东西不能正常工作,可能是因为X50

  • 问题内容: 我想用我的公钥输入一个字符串(纯文本)。我有一个,作为从服务器发送来的,并创建了一个公共密钥。现在我想使用该键填充文本。我怎样才能做到这一点。我经历了很多堆栈溢出问题,但没有获得任何成功。 我这是怎么创建, 这将创建一个成功。现在我想用这个密钥来加密另一个。我怎样才能做到这一点。 问题答案: 希望这个能对您有所帮助:

  • 如何从Go中的字符串导入RSA公钥,以便用于加密数据? 我的程序应该执行以下操作: > 接收一个用Base64编码的公钥 将此公钥从Base64解码为字节 导入公钥,以便Go的RSA实现可以使用(问题在这个阶段) 加密AES密钥: 提前谢谢! 解决方案: 公钥必须使用crypto/x509包进行解码。 例如: 然后可以使用带有RSA的进行加密。