C# RSA 加密/解密与传输

Posted

技术标签:

【中文标题】C# RSA 加密/解密与传输【英文标题】:C# RSA encryption/decryption with transmission 【发布时间】:2013-06-12 06:10:02 【问题描述】:

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

创建 RSA 公钥/私钥对 传输公钥(或者为了概念验证,只需将其移动到字符串变量中) 创建新的 RSA 加密提供程序并使用公钥加密字符串 将加密的字符串(或数据)传输回原始加密提供者并解密该字符串

谁能给我指出一个有用的资源?

【问题讨论】:

您能否指出一个具体的教程来解释在 C# 中使用 RSA 进行加密和解密,但不能满足您的特定需求?我想说它们非常简单,从你的问题中我不清楚你在哪一部分有问题。 同样在第 1 点上,将私钥存储在机器上的本地存储/容器中的最佳做法是,数据最终会被解密。 【参考方案1】:

确实有足够多的例子,但无论如何,给你

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);
    
  

附带说明:对 Encrypt() 和 Decrypt() 的调用有一个 bool 参数,可在 OAEP 和 PKCS#1.5 填充之间切换……如果您的情况可用,您可能希望选择 OAEP

【讨论】:

非常感谢您,先生!我会支持你,但我需要 15 个代表。当我这样做时,我会记住你的! :) @Transmission:如果回答了您的问题,请考虑接受meta.stackexchange.com/a/5235/161449 这样 cypherText 会变得很长!是否有任何算法可以在具有相同安全性的同时缩短它? (最好只包含数字和大写字母) @SepehrM RSA 并非旨在加密大量数据......您可能应该考虑使用 AES 或 Twofish 等对称密码来加密数据,并使用 RSA(或其他不对称密码)来加密你的对称密钥......混合加密...... @DarkSquirrel42 顺便说一句,WannaCry 就是这样快速加密文件的。【参考方案2】:
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;
                
            
        

【讨论】:

你是如何生成密钥的 @Sana 您可以使用ToXmlString 方法获取密钥。检查this answer。【参考方案3】:

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

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);
        
    

【讨论】:

为什么要使用 XmlSerializer?【参考方案4】:

我将分享我非常简单的代码用于示例目的。希望它能帮助像我这样的人搜索快速代码参考。 我的目标是从后端接收 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;
    

【讨论】:

以上是关于C# RSA 加密/解密与传输的主要内容,如果未能解决你的问题,请参考以下文章

C#中RSA加密解密和签名与验证的实现

RSA算法加密解密,数据传输,前台与后台数据交互

C#中RSA加密解密

RSA数据加密解密(各种语言)

基于C#的RSA非对称加密算法

C#常用的加密解密方法