3

Ich fühle mich wie das, was ich versuche, ist sehr einfach. Aber aus irgendeinem Grunde nicht will, dass es nicht arbeiten:RSA Encryption öffentlicher Schlüssel nicht aus dem Container zurückgegeben?

Dies ist der komplette Code-Schnipsel zu testen, was ich zu tun versucht:

using System; 
using System.Xml; 
using System.Security.Cryptography; 
using System.Security.Cryptography.Xml; 

namespace XmlCryptographySendingTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string fullKeyContainer = "fullKeyContainer"; 
      string publicKeyContainer = "publicKeyContainer"; 
     //create the two providers 
     RSACryptoServiceProvider serverRSA = GetKeyFromContainer(fullKeyContainer); 

     //save public and full key pairs 
     SaveKeyToContainer(fullKeyContainer, serverRSA.ExportParameters(true)); 
     SaveKeyToContainer(publicKeyContainer, serverRSA.ExportParameters(false)); 

     //get rid of them from memory 
     serverRSA.Clear(); 
     serverRSA = null; 
     GC.Collect(); 

     //retrieve a full server set and a private client set 
     serverRSA = GetKeyFromContainer(fullKeyContainer); 
     RSACryptoServiceProvider clientRSA = GetKeyFromContainer(publicKeyContainer); 

     //at this point the public key should be the same for both RSA providers 
     string clientPublicKey = clientRSA.ToXmlString(false); 
     string serverPublicKey = serverRSA.ToXmlString(false); 

     if (clientPublicKey.Equals(serverPublicKey)) 
     {//they have the same public key. 

      // Create an XmlDocument object. 
      XmlDocument xmlDoc = new XmlDocument(); 

      // Load an XML file into the XmlDocument object. 
      try 
      { 
       xmlDoc.PreserveWhitespace = true; 
       xmlDoc.Load("test.xml"); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 

      //we can encypt with the clientRSA using the public key 
      Encrypt(xmlDoc, "Fields", "DataFields", clientRSA, "test"); 

      Console.WriteLine("Encrypted: \r\n" + xmlDoc.OuterXml); 

      //and should be able to decrypt with the serverRSA using the private key 
      Decrypt(xmlDoc, serverRSA, "test"); 

      Console.WriteLine("Decrypted : \r\n" + xmlDoc.OuterXml); 
     } 
     else 
     { 
      Console.WriteLine("The two RSA have different public keys..."); 
     } 

     Console.ReadLine(); 
    } 



    private static CspParameters GetCspParameters(string containerName) 
    { 
     // Create the CspParameters object and set the key container 
     // name used to store the RSA key pair. 
     CspParameters tmpParameters = new CspParameters(); 
     tmpParameters.Flags = CspProviderFlags.UseMachineKeyStore; //use the machine key store--this allows us to use the machine level container when applications run without a logged-in user 
     tmpParameters.ProviderType = 1; 
     tmpParameters.KeyNumber = (int)KeyNumber.Exchange; 
     tmpParameters.KeyContainerName = containerName; 
     return tmpParameters; 
    } 


    public static void SaveKeyToContainer(string containerName, RSAParameters rsaParameters) 
    { 
     CspParameters tmpParameters = GetCspParameters(containerName); 

     // Create a new instance of RSACryptoServiceProvider that accesses 
     // the key container 
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(tmpParameters); 

     //set the key information from the text 
     rsa.ImportParameters(rsaParameters); 
    } 

    public static RSACryptoServiceProvider GetKeyFromContainer(string containerName) 
    { 
     // Create the CspParameters object and set the key container 
     // name used to store the RSA key pair. 
     CspParameters tmpParameters = GetCspParameters(containerName); 

     // Create a new instance of RSACryptoServiceProvider that accesses 
     // the key container. 
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(tmpParameters); 

     return rsa; 
    } 

    public static void DeleteKeyFromContainer(string containerName) 
    { 
     // Create the CspParameters object and set the key container 
     // name used to store the RSA key pair. 
     CspParameters tmpParameters = GetCspParameters(containerName); 

     // Create a new instance of RSACryptoServiceProvider that accesses 
     // the key container. 
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(tmpParameters); 

     // Delete the key entry in the container. 
     rsa.PersistKeyInCsp = false; 

     // Call Clear to release resources and delete the key from the container. 
     rsa.Clear(); 
    } 



    public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName) 
    { 
     // Check the arguments. 
     if (Doc == null) 
      throw new ArgumentNullException("Doc"); 
     if (ElementToEncrypt == null) 
      throw new ArgumentNullException("ElementToEncrypt"); 
     if (EncryptionElementID == null) 
      throw new ArgumentNullException("EncryptionElementID"); 
     if (Alg == null) 
      throw new ArgumentNullException("Alg"); 
     if (KeyName == null) 
      throw new ArgumentNullException("KeyName"); 

     //////////////////////////////////////////////// 
     // Find the specified element in the XmlDocument 
     // object and create a new XmlElemnt object. 
     //////////////////////////////////////////////// 
     XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement; 

     // Throw an XmlException if the element was not found. 
     if (elementToEncrypt == null) 
     { 
      throw new XmlException("The specified element was not found"); 

     } 
     RijndaelManaged sessionKey = null; 

     try 
     { 
      ////////////////////////////////////////////////// 
      // Create a new instance of the EncryptedXml class 
      // and use it to encrypt the XmlElement with the 
      // a new random symmetric key. 
      ////////////////////////////////////////////////// 

      // Create a 256 bit Rijndael key. 
      sessionKey = new RijndaelManaged(); 
      sessionKey.KeySize = 256; 

      EncryptedXml eXml = new EncryptedXml(); 

      byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false); 
      //////////////////////////////////////////////// 
      // Construct an EncryptedData object and populate 
      // it with the desired encryption information. 
      //////////////////////////////////////////////// 

      EncryptedData edElement = new EncryptedData(); 
      edElement.Type = EncryptedXml.XmlEncElementUrl; 
      edElement.Id = EncryptionElementID; 
      // Create an EncryptionMethod element so that the 
      // receiver knows which algorithm to use for decryption. 

      edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url); 
      // Encrypt the session key and add it to an EncryptedKey element. 
      EncryptedKey ek = new EncryptedKey(); 

      byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false); 

      ek.CipherData = new CipherData(encryptedKey); 

      ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url); 

      // Create a new DataReference element 
      // for the KeyInfo element. This optional 
      // element specifies which EncryptedData 
      // uses this key. An XML document can have 
      // multiple EncryptedData elements that use 
      // different keys. 
      DataReference dRef = new DataReference(); 

      // Specify the EncryptedData URI. 
      dRef.Uri = "#" + EncryptionElementID; 

      // Add the DataReference to the EncryptedKey. 
      ek.AddReference(dRef); 
      // Add the encrypted key to the 
      // EncryptedData object. 

      edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek)); 
      // Set the KeyInfo element to specify the 
      // name of the RSA key. 


      // Create a new KeyInfoName element. 
      KeyInfoName kin = new KeyInfoName(); 

      // Specify a name for the key. 
      kin.Value = KeyName; 

      // Add the KeyInfoName element to the 
      // EncryptedKey object. 
      ek.KeyInfo.AddClause(kin); 
      // Add the encrypted element data to the 
      // EncryptedData object. 
      edElement.CipherData.CipherValue = encryptedElement; 
      //////////////////////////////////////////////////// 
      // Replace the element from the original XmlDocument 
      // object with the EncryptedData element. 
      //////////////////////////////////////////////////// 
      EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false); 
     } 
     catch (Exception e) 
     { 
      // re-throw the exception. 
      throw e; 
     } 
     finally 
     { 
      if (sessionKey != null) 
      { 
       sessionKey.Clear(); 
      } 

     } 

    } 

    public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName) 
    { 
     // Check the arguments. 
     if (Doc == null) 
      throw new ArgumentNullException("Doc"); 
     if (Alg == null) 
      throw new ArgumentNullException("Alg"); 
     if (KeyName == null) 
      throw new ArgumentNullException("KeyName"); 

     // Create a new EncryptedXml object. 
     EncryptedXml exml = new EncryptedXml(Doc); 

     // Add a key-name mapping. 
     // This method can only decrypt documents 
     // that present the specified key name. 
     exml.AddKeyNameMapping(KeyName, Alg); 

     // Decrypt the element. 
     exml.DecryptDocument(); 

     } 

    } 
} 

Diese feinen, so lange zu arbeiten scheint, wie ich bin Speicher/Abrufen eines RSACryptoServiceProvider mit einem privaten und einem öffentlichen Schlüssel Sobald ich einen RSACryptoServiceProvider mit JUST einen öffentlichen Schlüssel speichere, das nächste Mal, wenn ich versuche, alles abzurufen, bekomme ich einen NEUEN und UNTERSCHIEDLICHEN RSACryptoServiceProvider!

Wie Sie sich vorstellen können, können Sie nicht etwas mit einem Schlüsselsatz verschlüsseln und dann versuchen, mit einem ganz neuen Satz zu entschlüsseln!

Alle Ideen, warum dies geschieht? oder was wäre der richtige Weg, einen öffentlichen Schlüssel zu speichern?

+0

Ist das richtig: Einmal speichere ich eine RSACryptoServiceProvider nur mit einem privaten Schlüssel Meinten Sie Sobald ich eine RSACryptoServiceProvider nur mit einem öffentlichen Schlüssel speichern – Christian

+0

Ja, ich bin für die Tippfehler leider –

Antwort

0

Mein Verständnis ist, dass Ihr Anruf zu ImportParameters in SaveKeyToContainer nicht den Schlüssel im Speicher zu beeinflussen. Ihre Implementierung von SaveKeyToContainer initialisiert eine Instanz von RSACryptoServiceProvider mithilfe des Schlüssels im Speicher (Erstellen eines neuen Schlüsselpaars, wenn der Container nicht vorhanden ist) und dann Importieren der Parameter, die die Instanz und nicht den Speicher betrifft.

Wenn Sie später publicKeyContainer abrufen, erhalten Sie das neue Schlüsselpaar, das generiert wurde, als Sie versuchten, es zu speichern, und nicht das importierte öffentliche Fragment.

Entschuldigung, ich kann nicht mit irgendwelchen Details über das Importieren des Schlüssels in den Speicher mit der Kryptographie-API helfen. Ich glaube, dass der Speicher nur Schlüsselpaare unterstützt, d. H. Nicht erwarten, dass nur der öffentliche Schlüssel importiert werden kann.

+0

Es ist ein Eigenschaft, die Sie festlegen können, um festzustellen, ob eine Instanz im Speicher vorhanden ist oder nicht. Ich hatte den Eindruck, dass die Änderungen, die Sie an den RSA-Schlüsseln vornehmen, auch im Keystore beibehalten werden, wenn diese Option beibehalten wird. –

+0

Es kann davon ausgegangen werden, dass meine Antwort ungenau ist und dass PersistKeyInCsp genau das tun sollte, wenn Sie ImportParameters aufrufen. Ich würde gerne wissen, ob Sie versucht haben, die Methoden Export/ImportCspBlob oder To/FromXmlString zu verwenden. Wissen Sie, wo der Modulus und der Exponent des öffentlichen Schlüssels nicht mehr mit serverKey und clientKey (RSAParameters) übereinstimmen? Kannst du den Code auf Mono testen? – Ajw

0

Die Dokumentation für die .NET-Crypto-Klassen ist sehr schlecht.

Ich habe mir mit demselben Thema den Kopf zerbrochen und bin zum selben Schluss gekommen, obwohl es in den Dokumenten nicht eindeutig steht.

Wenn Sie eine Instanz des RSA-Anbieters erstellen, erhalten Sie ein neues Schlüsselpaar. Wenn Sie ein Parameterobjekt angeben und einen Schlüsselcontainer benennen, wird das neue Schlüsselpaar dort gespeichert.

Wenn Sie einen öffentlichen Schlüssel importieren, wird nicht erhalten bleiben!

Dan

3

Ich hatte a very similar question.

Ich bin jetzt fast sicher, dass die Schlüssel-Container nicht verwendet werden können, um öffentliche Schlüssel zu speichern. Ihr primärer Zweck scheint darin zu liegen, Schlüsselpaare zu speichern. Der Schlüsselcontainer speichert nur den Schlüssel, der ursprünglich generiert wurde, und das Importieren eines Schlüssels PublicOnly betrifft nur die Instanz und nicht den Speicher.

Die Seite "So speichern Sie: Asymmetrische Schlüssel in einem Schlüsselbehälter" der.NET-Entwicklerhandbuch heißt es, dass

Wenn Sie einen privaten Schlüssel speichern müssen, sollten Sie einen Schlüsselcontainer verwenden

... die etwa so klar aa Aussage ist wie ich in der Lage gewesen zu finden über MSDN. Der Ersatzmechanismus, den ich verwendet habe, war, den Schlüssel in einer XML-Datei zu speichern (da es ein öffentlicher Schlüssel ist, sollte es keine Rolle spielen, wenn er leicht sichtbar ist), mit Berechtigungen, die mithilfe von Dateisystemzugriffsregeln vorgenommen werden.