title: Is there no need to store Hashed password, if I use PBKDF2 or RFC2898 code encrypt or decrypt data in C#
body: <p>Actual referenced code is appended in the end.
  From what I can understand from the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=netcore-3.1" rel="nofollow noreferrer">code for <strong>PBKDF2</strong> or <strong>RFC2898</strong> in C#</a>  as given in the above link .</p>
  <p>I have come to the following conclusion. Please correct me if I am wrong.</p>
  <ol>
  <li>Storing of Password</li>
  </ol>
  <blockquote>
  <p><strong>pwd1</strong></p>
  </blockquote>
  <p>is <strong>not</strong> <strong>necessary</strong>.</p>
  <ol start="2">
  <li>Storing of Salt     **</li>
  </ol>
  <blockquote>
  <p><strong>salt1</strong></p>
  </blockquote>
  <p>** is     <strong>necessary</strong>.</p>
  <ol start="3">
  <li>If password is hashed to form key '<strong>k1</strong>', to encrypt the '<strong>data1</strong>'  to '<strong>edata1</strong>' , even storing the hashed password = key</li>
  </ol>
  <blockquote>
  <p><strong>k1</strong></p>
  </blockquote>
  <p>, is <strong><strong>not</strong> <strong>necessary</strong></strong>. The reason behind my thinking is encrypted data ‘<strong>edata1</strong>’ can only be decrypted with key ‘<strong>k1</strong>’ and ‘<strong>k1</strong>’ can only be generated if the user enters the right password ‘<strong>pwd1</strong>’.</p>
  <p>Conclusion : Password ‘<strong>pwd1</strong>’   need not be stored.
  Neither hashed password i.e. , ‘<strong>k1</strong>’ needs to be stored.
  Please correct me if I am wrong. Thank you.</p>
  <pre><code>using System;
  using System.IO;
  using System.Text;
  using System.Security.Cryptography;
  
  public class rfc2898test
  {
      // Generate a key k1 with password pwd1 and salt salt1.
      // Generate a key k2 with password pwd1 and salt salt1.
      // Encrypt data1 with key k1 using symmetric encryption, creating edata1.
      // Decrypt edata1 with key k2 using symmetric decryption, creating data2.
      // data2 should equal data1.
  
      private const string usageText = &quot;Usage: RFC2898 &lt;password&gt;\nYou must specify the password for encryption.\n&quot;;
      public static void Main(string[] passwordargs)
      {
          //If no file name is specified, write usage text.
          if (passwordargs.Length == 0)
          {
              Console.WriteLine(usageText);
          }
          else
          {
              string pwd1 = passwordargs[0];
              // Create a byte array to hold the random value.
              byte[] salt1 = new byte[8];
              using (RNGCryptoServiceProvider rngCsp = new
  RNGCryptoServiceProvider())
              {
                  // Fill the array with a random value.
                  rngCsp.GetBytes(salt1);
              }
  
              //data1 can be a string or contents of a file.
              string data1 = &quot;Some test data&quot;;
              //The default iteration count is 1000 so the two methods use the same iteration count.
              int myIterations = 1000;
              try
              {
                  Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,
  myIterations);
                  Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
                  // Encrypt the data.
                  Aes encAlg = Aes.Create();
                  encAlg.Key = k1.GetBytes(16);
                  MemoryStream encryptionStream = new MemoryStream();
                  CryptoStream encrypt = new CryptoStream(encryptionStream,
  encAlg.CreateEncryptor(), CryptoStreamMode.Write);
                  byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(
  data1);
  
                  encrypt.Write(utfD1, 0, utfD1.Length);
                  encrypt.FlushFinalBlock();
                  encrypt.Close();
                  byte[] edata1 = encryptionStream.ToArray();
                  k1.Reset();
  
                  // Try to decrypt, thus showing it can be round-tripped.
                  Aes decAlg = Aes.Create();
                  decAlg.Key = k2.GetBytes(16);
                  decAlg.IV = encAlg.IV;
                  MemoryStream decryptionStreamBacking = new MemoryStream();
                  CryptoStream decrypt = new CryptoStream(
  decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
                  decrypt.Write(edata1, 0, edata1.Length);
                  decrypt.Flush();
                  decrypt.Close();
                  k2.Reset();
                  string data2 = new UTF8Encoding(false).GetString(
  decryptionStreamBacking.ToArray());
  
                  if (!data1.Equals(data2))
                  {
                      Console.WriteLine(&quot;Error: The two values are not equal.&quot;);
                  }
                  else
                  {
                      Console.WriteLine(&quot;The two values are equal.&quot;);
                      Console.WriteLine(&quot;k1 iterations: {0}&quot;, k1.IterationCount);
                      Console.WriteLine(&quot;k2 iterations: {0}&quot;, k2.IterationCount);
                  }
              }
              catch (Exception e)
              {
                  Console.WriteLine(&quot;Error: {0}&quot;, e);
              }
          }
      }
  }
  </code></pre>