C# RSA 加密/解密带传输

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17128038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:40:14  来源:igfitidea点击:

C# RSA encryption/decryption with transmission

c#cryptographyrsa

提问by Transmission

I've seen plenty of encryption/decryption tutorials and examples on the net in C# that use the System.Security.Cryptography.RSACryptoServiceProvider, but what I'm hoping to be able to do is:

我在 C# 网络上看到了大量使用 System.Security.Cryptography.RSACryptoServiceProvider 的加密/解密教程和示例,但我希望能够做的是:

  • Create an RSA public/private keypair
  • Transmit the public key (or for proof of concept, just move it in a string variable)
  • Create a new RSA crypto provider and encrypt a string with the public key
  • Transmit the encrypted string (or data) back to the original crypto provider and decrypt the string
  • 创建 RSA 公钥/私钥对
  • 传输公钥(或用于概念证明,只需将其移动到字符串变量中)
  • 创建一个新的 RSA 加密提供程序并使用公钥加密一个字符串
  • 将加密的字符串(或数据)传输回原始加密提供程序并解密字符串

Could anyone point me to a useful resource for this?

任何人都可以指出我对此有用的资源吗?

采纳答案by DarkSquirrel42

well there are really enough examples for this, but anyway, here you go

好吧,确实有足够的例子,但无论如何,你去吧

using System;
using System.Security.Cryptography;

namespace RsaCryptoExample
{
  static class Program
  {
    static void Main()
    {
      //lets take a new CSP with a new 2048 bit rsa key pair
      var csp = new RSACryptoServiceProvider(2048);

      //how to get the private key
      var privKey = csp.ExportParameters(true);

      //and the public key ...
      var pubKey = csp.ExportParameters(false);

      //converting the public key into a string representation
      string pubKeyString;
      {
        //we need some buffer
        var sw = new System.IO.StringWriter();
        //we need a serializer
        var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
        //serialize the key into the stream
        xs.Serialize(sw, pubKey);
        //get the string from the stream
        pubKeyString = sw.ToString();
      }

      //converting it back
      {
        //get a stream from the string
        var sr = new System.IO.StringReader(pubKeyString);
        //we need a deserializer
        var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
        //get the object back from the stream
        pubKey = (RSAParameters)xs.Deserialize(sr);
      }

      //conversion for the private key is no black magic either ... omitted

      //we have a public key ... let's get a new csp and load that key
      csp = new RSACryptoServiceProvider();
      csp.ImportParameters(pubKey);

      //we need some data to encrypt
      var plainTextData = "foobar";

      //for encryption, always handle bytes...
      var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);

      //apply pkcs#1.5 padding and encrypt our data 
      var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);

      //we might want a string representation of our cypher text... base64 will do
      var cypherText = Convert.ToBase64String(bytesCypherText);


      /*
       * some transmission / storage / retrieval
       * 
       * and we want to decrypt our cypherText
       */

      //first, get our bytes back from the base64 string ...
      bytesCypherText = Convert.FromBase64String(cypherText);

      //we want to decrypt, therefore we need a csp and load our private key
      csp = new RSACryptoServiceProvider();
      csp.ImportParameters(privKey);

      //decrypt and strip pkcs#1.5 padding
      bytesPlainTextData = csp.Decrypt(bytesCypherText, false);

      //get our original plainText back...
      plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
    }
  }
}

as a side note: the calls to Encrypt() and Decrypt() have a bool parameter that switches between OAEP and PKCS#1.5 padding ... you might want to choose OAEP if it's available in your situation

作为旁注:对 Encrypt() 和 Decrypt() 的调用有一个 bool 参数,可以在 OAEP 和 PKCS#1.5 填充之间切换……如果在您的情况下可用,您可能想要选择 OAEP

回答by Mukund

public static string Encryption(string strText)
        {
            var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

            var testData = Encoding.UTF8.GetBytes(strText);

            using (var rsa = new RSACryptoServiceProvider(1024))
            {
                try
                {
                    // client encrypting data with public key issued by server                    
                    rsa.FromXmlString(publicKey.ToString());

                    var encryptedData = rsa.Encrypt(testData, true);

                    var base64Encrypted = Convert.ToBase64String(encryptedData);

                    return base64Encrypted;
                }
                finally
                {
                    rsa.PersistKeyInCsp = false;
                }
            }
        }

        public static string Decryption(string strText)
        {
            var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";

            var testData = Encoding.UTF8.GetBytes(strText);

            using (var rsa = new RSACryptoServiceProvider(1024))
            {
                try
                {                    
                    var base64Encrypted = strText;

                    // server decrypting data with private key                    
                    rsa.FromXmlString(privateKey);

                    var resultBytes = Convert.FromBase64String(base64Encrypted);
                    var decryptedBytes = rsa.Decrypt(resultBytes, true);
                    var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
                    return decryptedData.ToString();
                }
                finally
                {
                    rsa.PersistKeyInCsp = false;
                }
            }
        }

回答by CraftedGaming

Honestly, I have difficulty implementing it because there's barely any tutorials I've searched that displays writing the keys into the files. The accepted answer was "fine". But for me I had to improve it so that both keys gets saved into two separate files. I've written a helper class so y'all just gotta copy and paste it. Hope this helps lol.

老实说,我很难实现它,因为我搜索过的几乎没有任何教程显示将密钥写入文件。接受的答案是“很好”。但对我来说,我必须改进它,以便将两个键都保存到两个单独的文件中。我写了一个助手类,所以你们只需要复制并粘贴它。希望这有助于大声笑。

using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;

namespace RsaCryptoExample
{
    class RSAFileHelper
    {
        readonly string pubKeyPath = "public.key";//change as needed
        readonly string priKeyPath = "private.key";//change as needed
        public void MakeKey()
        {
            //lets take a new CSP with a new 2048 bit rsa key pair
            RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);

            //how to get the private key
            RSAParameters privKey = csp.ExportParameters(true);

            //and the public key ...
            RSAParameters pubKey = csp.ExportParameters(false);
            //converting the public key into a string representation
            string pubKeyString;
            {
                //we need some buffer
                var sw = new StringWriter();
                //we need a serializer
                var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
                //serialize the key into the stream
                xs.Serialize(sw, pubKey);
                //get the string from the stream
                pubKeyString = sw.ToString();
                File.WriteAllText(pubKeyPath, pubKeyString);
            }
            string privKeyString;
            {
                //we need some buffer
                var sw = new StringWriter();
                //we need a serializer
                var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
                //serialize the key into the stream
                xs.Serialize(sw, privKey);
                //get the string from the stream
                privKeyString = sw.ToString();
                File.WriteAllText(priKeyPath, privKeyString);
            }
        }
        public void EncryptFile(string filePath)
        {
            //converting the public key into a string representation
            string pubKeyString;
            {
                using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
            }
            //get a stream from the string
            var sr = new StringReader(pubKeyString);

            //we need a deserializer
            var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));

            //get the object back from the stream
            RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
            csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
            byte[] bytesPlainTextData = File.ReadAllBytes(filePath);

            //apply pkcs#1.5 padding and encrypt our data 
            var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
            //we might want a string representation of our cypher text... base64 will do
            string encryptedText = Convert.ToBase64String(bytesCipherText);
            File.WriteAllText(filePath,encryptedText);
        }
        public void DecryptFile(string filePath)
        {
            //we want to decrypt, therefore we need a csp and load our private key
            RSACryptoServiceProvider csp = new RSACryptoServiceProvider();

            string privKeyString;
            {
                privKeyString = File.ReadAllText(priKeyPath);
                //get a stream from the string
                var sr = new StringReader(privKeyString);
                //we need a deserializer
                var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
                //get the object back from the stream
                RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
                csp.ImportParameters(privKey);
            }
            string encryptedText;
            using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
            byte[] bytesCipherText = Convert.FromBase64String(encryptedText);

            //decrypt and strip pkcs#1.5 padding
            byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);

            //get our original plainText back...
            File.WriteAllBytes(filePath, bytesPlainTextData);
        }
    }
}

回答by Tigran

I'll share my very simple code for sample purpose. Hope it will help someone like me searching for quick code reference. My goal was to receive rsa signature from backend, then validate against input string using public key and store locally for future periodic verifications. Here is main part used for signature verification:

出于示例目的,我将分享我的非常简单的代码。希望它能帮助像我这样搜索快速代码参考的人。我的目标是从后端接收 rsa 签名,然后使用公钥验证输入字符串并在本地存储以备将来定期验证。这是用于签名验证的主要部分:

        ...
        var signature = Get(url); // base64_encoded signature received from server
        var inputtext= "inputtext"; // this is main text signature was created for
        bool result = VerifySignature(inputtext, signature);
        ...

    private bool VerifySignature(string input, string signature)
    {
        var result = false;
        using (var cps=new RSACryptoServiceProvider())
        {
            // converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
            byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
            byte[] signatureBytes  = Convert.FromBase64String(signature);

            cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
            result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes  );
        }

        return result;
    }