title: How to Generate Unique Public and Private Key via RSA
body: <p>I am building a custom shopping cart where CC numbers and Exp date will be stored in a database until processing (then deleted). I need to encrypt this data (obviously).</p>
  
  <p>I want to use the RSACryptoServiceProvider class.</p>
  
  <p>Here is my code to create my keys.</p>
  
  <pre><code>public static void AssignNewKey(){
      const int PROVIDER_RSA_FULL = 1;
      const string CONTAINER_NAME = "KeyContainer";
      CspParameters cspParams;
      cspParams = new CspParameters(PROVIDER_RSA_FULL);
      cspParams.KeyContainerName = CONTAINER_NAME;
      cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
      cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
      rsa = new RSACryptoServiceProvider(cspParams);
  
      string publicPrivateKeyXML = rsa.ToXmlString(true);
      string publicOnlyKeyXML = rsa.ToXmlString(false);
      // do stuff with keys...
  }
  </code></pre>
  
  <p>Now the plan is to store the private key xml on a USB drive attached to the managers key chain.</p>
  
  <p>Whenever a manager leaves the company I want to be able to generate new public and private keys (and re-encrypt all currently stored CC numbers with the new public key).</p>
  
  <p>My problem is that the keys generated by this code are always the same. How would I generate a unique set of keys every time?</p>
  
  <p><strong>UPDATE.</strong> My test code is below.:<br />
  <em>note: the "privatekey" parameter here is the original private key. In order for the keys to be changed I need to verify that the private key is valid.</em></p>
  
  <p>In Default.aspx.cs</p>
  
  <pre><code>public void DownloadNewPrivateKey_Click(object sender, EventArgs e)
  {
      StreamReader reader = new StreamReader(fileUpload.FileContent);
      string privateKey = reader.ReadToEnd();
      Response.Clear();
      Response.ContentType = "text/xml";
      Response.End();
      Response.Write(ChangeKeysAndReturnNewPrivateKey(privateKey));
  }
  </code></pre>
  
  <p>In Crytpography.cs:</p>
  
  <pre><code>public static privateKey;
  public static publicKey;
  public static RSACryptoServiceProvider rsa;
  
  public static string ChangeKeysAndReturnNewPrivateKey(string _privatekey)
  {
  
      string testData = "TestData";
      string testSalt = "salt";
      // encrypt the test data using the exisiting public key...
      string encryptedTestData = EncryptData(testData, testSalt);
      try
      {
          // try to decrypt the test data using the _privatekey provided by user...
          string decryptTestData = DecryptData(encryptedTestData, _privatekey, testSalt);
          // if the data is successfully decrypted assign new keys...
          if (decryptTestData == testData)
          {
              AssignNewKey();
              // "AssignNewKey()" should set "privateKey" to the newly created private key...
              return privateKey;
          }
          else
          {
              return string.Empty;
          }
      }
      catch (Exception ex)
      {
          return string.Empty;
      }
  }
  public static void AssignParameter(){
      const int PROVIDER_RSA_FULL = 1;
      const string CONTAINER_NAME = "KeyContainer";
      CspParameters cspParams;
      cspParams = new CspParameters(PROVIDER_RSA_FULL);
      cspParams.KeyContainerName = CONTAINER_NAME;
      cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
      cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
      rsa = new RSACryptoServiceProvider(cspParams);
  }
  public static void AssignNewKey()
  {
      AssignParameter();
  
      using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
      {
          SqlCommand myCmd = myConn.CreateCommand();
  
          string publicPrivateKeyXML = rsa.ToXmlString(true);
          privateKey = publicPrivateKeyXML; // sets the public variable privateKey to the new private key.
  
          string publicOnlyKeyXML = rsa.ToXmlString(false);
          publicKey = publicOnlyKeyXML; // sets the public variable publicKey to the new public key.
  
          myCmd.CommandText = "UPDATE Settings SET PublicKey = @PublicKey";
          myCmd.Parameters.AddWithValue("@PublicKey", publicOnlyKeyXML);
          myConn.Open();
  
          myComm.ExecuteScalar();
      }
  }
  public static string EncryptData(string data2Encrypt, string salt)
  {
      AssignParameter();
  
      using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
      {
          SqlCommand myCmd = myConn.CreateCommand();
  
          myCmd.CommandText = "SELECT TOP 1 PublicKey FROM Settings";
  
          myConn.Open();
  
          using (SqlDataReader sdr = myCmd.ExecuteReader())
          {
              if (sdr.HasRows)
              {
                  DataTable dt = new DataTable();
                  dt.Load(sdr);
                  rsa.FromXmlString(dt.Rows[0]["PublicKey"].ToString());
              }
          }
      }
  
      //read plaintext, encrypt it to ciphertext
      byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt + salt);
      byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
      return Convert.ToBase64String(cipherbytes);
  }
  public static string DecryptData(string data2Decrypt, string privatekey, string salt)
  {
      AssignParameter();
  
      byte[] getpassword = Convert.FromBase64String(data2Decrypt);
  
      string publicPrivateKeyXML = privatekey;
      rsa.FromXmlString(publicPrivateKeyXML);
  
      //read ciphertext, decrypt it to plaintext
      byte[] plain = rsa.Decrypt(getpassword, false);
      string dataAndSalt = System.Text.Encoding.UTF8.GetString(plain);
      return dataAndSalt.Substring(0, dataAndSalt.Length - salt.Length);
  }
  </code></pre>