C # RSA-Verschlüsselung / Entschlüsselung mit Übertragung


77

Ich habe in C # viele Tutorials und Beispiele für Verschlüsselung / Entschlüsselung im Internet gesehen, die den System.Security.Cryptography.RSACryptoServiceProvider verwenden, aber ich hoffe, dass ich dies tun kann:

  • Erstellen Sie ein öffentliches / privates RSA-Schlüsselpaar
  • Übertragen Sie den öffentlichen Schlüssel (oder verschieben Sie ihn zum Proof of Concept einfach in eine Zeichenfolgenvariable).
  • Erstellen Sie einen neuen RSA-Kryptoanbieter und verschlüsseln Sie eine Zeichenfolge mit dem öffentlichen Schlüssel
  • Übertragen Sie die verschlüsselte Zeichenfolge (oder die Daten) zurück an den ursprünglichen Kryptoanbieter und entschlüsseln Sie die Zeichenfolge

Könnte mich jemand auf eine nützliche Ressource dafür hinweisen?


2
Könnten Sie auf ein spezielles Tutorial hinweisen, in dem die Ver- und Entschlüsselung mit RSA in C # erläutert wird und das nicht Ihren spezifischen Anforderungen entspricht? Ich würde sagen, sie sind ziemlich einfach und es ist mir aus Ihrer Frage nicht klar, mit welchem ​​Teil Sie ein Problem haben.
Andrew Savinykh

Antworten:


213

Nun, es gibt wirklich genug Beispiele dafür, aber trotzdem, los geht's

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

Als Randnotiz: Die Aufrufe von Encrypt () und Decrypt () haben einen bool-Parameter, der zwischen OAEP- und PKCS # 1.5-Padding umschaltet. Möglicherweise möchten Sie OAEP auswählen, wenn es in Ihrer Situation verfügbar ist


7
Vielen Dank, mein Herr! Ich würde dich positiv bewerten, aber dafür brauche ich 15 Wiederholungen. Ich werde mich an dich erinnern, wenn ich es tue! :)
Übertragung

@Transmission: Bitte akzeptieren Sie die Antwort, wenn sie Ihre Frage beantwortet. Meta.stackexchange.com/a/5235/161449
Andrew Savinykh

Auf diese Weise wird der cypherText sehr lang! Gibt es einen Algorithmus, um es bei gleicher Sicherheit zu verkürzen? (Und enthält vorzugsweise nur Ziffern und Großbuchstaben)
SepehrM

16
@SepehrM RSA ist nicht zum Verschlüsseln großer Datenmengen gedacht. Sie sollten möglicherweise die Verwendung einer symetrischen Verschlüsselung wie AES oder Twofish für Ihre Daten und RSA (oder einer anderen asymetrischen Verschlüsselung) für die Verschlüsselung Ihres symetrischen Schlüssels in Betracht ziehen ... Hybrid-Krypto ...
DarkSquirrel42

1
@ DarkSquirrel42 Übrigens gelang es WannaCry, die Dateien so schnell zu verschlüsseln.
Eric Wu

14
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;
                }
            }
        }

Wie haben Sie die Schlüssel generiert
Sana

@Sana Sie können die Schlüssel mit der ToXmlStringMethode erhalten. Überprüfen Sie diese Antwort .
Neugier

5

Ehrlich gesagt habe ich Schwierigkeiten, es zu implementieren, da ich kaum Tutorials durchsucht habe, in denen die Schlüssel in die Dateien geschrieben werden. Die akzeptierte Antwort war "gut". Aber für mich musste ich es verbessern, damit beide Schlüssel in zwei separaten Dateien gespeichert werden. Ich habe eine Hilfsklasse geschrieben, also musst du sie einfach kopieren und einfügen. Hoffe das hilft 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);
        }
    }
}

1
Warum verwenden Sie XmlSerializer?
Mike Yang

0

Ich werde meinen sehr einfachen Code für Beispielzwecke teilen. Ich hoffe, es hilft jemandem wie mir bei der Suche nach einer schnellen Code-Referenz. Mein Ziel war es, eine rsa-Signatur vom Backend zu erhalten, dann mit einem öffentlichen Schlüssel anhand der Eingabezeichenfolge zu validieren und für zukünftige regelmäßige Überprüfungen lokal zu speichern. Hier ist der Hauptteil, der zur Überprüfung der Signatur verwendet wird:

        ...
        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;
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.