3

私がやっているような気がするのはとても簡単です。しかし、それが動作するように望んでいない何らかの理由:RSA暗号化の公開鍵がコンテナから返されませんか?

をここで私が何をしようとしていますかをテストするための完全なコードスニペットです:

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

     } 

    } 
} 

はこれがある限り、私は/保存していて正常に動作するようですRSACryptoServiceProviderをプライベートキーと公開キーの両方で取得する。 RSACryptoServiceProviderを公開鍵で保存すると、次に取得しようとするときには、新しく異なるRSACryptoServiceProviderが得られます。

あなたが想像しているように、あるセットの鍵で何かを暗号化できないし、まったく新しいセットで解読しようとします!

これはなぜ起こっているのですか?パブリック専用キーを保存するのが正しい方法は何でしょうか?

+0

正しいということです:私は、秘密鍵 とRSACryptoServiceProviderを保存 たら、私はJUST公開鍵 – Christian

+0

はい、私はありタイプミス –

答えて

0

私の理解では、SaveKeyToContainerImportParametersへのお電話は、ストア内のキーに影響を与えていないことです。 SaveKeyToContainerの実装では、RSACryptoServiceProviderのインスタンスを初期化しています(コンテナが存在しない場合は新しいキーペアを生成します)。次に、インスタンスではなくストアに影響するパラメータをインポートします。

publicKeyContainerを後で取得すると、インポートしようとしたときに生成され、インポートされたパブリックフラグメントではない新しいキーペアが与えられます。

申し訳ありませんが、私は、暗号化APIを使用してキーをストアにインポートする際の詳細についてお手伝いできません。私はストアが鍵ペアのみをサポートしている、つまり公開鍵だけをインポートできるとは思わないと思います。

+0

ごめんなさいとRSACryptoServiceProviderを保存すると、あなたが をもしかしてプロパティを使用して、インスタンスがストア内に存続するかどうかを判断できます。私は、これが持続するように設定されていると、RSAキーの変更もキーストアで維持されるという印象を受けましたか? –

+0

私の答えが不正確で、ImportParametersを呼び出すときにPersistKeyInCspが正確に行うべきであると仮定することは安全です。 Export/ImportCspBlobメソッドまたはTo/FromXmlStringメソッドを使用しようとしているかどうかを知ることに興味があります。公開鍵のモジュラスと指数がserverKeyとclientKey(RSAParameters)のどこで一致しないのか知っていますか?あなたはモノでコードをテストすることができますか? – Ajw

0

.NET Crypto Classesのドキュメントは非常に貧弱です。

私は同じ問題で私の頭を打ち負かされており、ドキュメントに明確に述べられていないのに同じ結論に達しています。

RSAプロバイダのインスタンスを作成すると、新しいキーペアが取得されます。 パラメータオブジェクトを指定してキーコンテナに名前を付けると、新しいキーペアがそこに格納されます。

公開鍵をインポートすると、ではなく、 get persisted!

ダン

3

私はa very similar questionでした。

キーコンテナを公開キーの格納に使用できないことはほぼ確実です。主な目的は、鍵のペアを格納するためです。キーコンテナは最初に生成されたキーのみを格納し、PublicOnlyキーをインポートすると、インスタンスではなくストレージに影響します。

「キーのコンテナへの非対称キーの格納方法」のページ。NET開発者ガイドは、あなたが秘密鍵を格納する必要がある場合、あなたは私が見つけることができましたとして明確なAA声明についてですキーコンテナ

を...使用する必要があります

と述べていますMSDNを介して。

私が使用した代替メカニズムは、XMLファイルにキーを格納することでした(公開キーなので簡単に見えるようにしてください)。不要な変更を防ぐためにファイルシステムアクセスルールを使用してアクセス許可が設定されています。

関連する問題