C# 如果在C中使用PBKDF2或RFC2898代码加密或解密数据,是否不需要存储哈希密码#

C# 如果在C中使用PBKDF2或RFC2898代码加密或解密数据,是否不需要存储哈希密码#,c#,encryption,cryptography,aes,pbkdf2,C#,Encryption,Cryptography,Aes,Pbkdf2,最后附加了实际引用的代码。 从上面的链接中我可以理解到 我得出以下结论。如果我错了,请纠正我 密码存储 pwd1 不是必需的 盐的储存** salt1 **是必要的 如果将密码散列为密钥“k1”,则将“data1”加密为“edata1”,甚至存储散列的密码=密钥 k1 ,不是必需的。我的想法背后的原因是加密数据“edata1”只能用密钥“k1”解密,并且只有用户输入正确的密码“pwd1”才能生成“k1” 结论:不需要存储密码“pwd1”。 无需存储散列密码,即“k1”。 如果我错了,请纠正我。多

最后附加了实际引用的代码。 从上面的链接中我可以理解到

我得出以下结论。如果我错了,请纠正我

  • 密码存储
  • pwd1

    不是必需的

  • 盐的储存**
  • salt1

    **是必要的

  • 如果将密码散列为密钥“k1”,则将“data1”加密为“edata1”,甚至存储散列的密码=密钥
  • k1

    ,不是必需的。我的想法背后的原因是加密数据“edata1”只能用密钥“k1”解密,并且只有用户输入正确的密码“pwd1”才能生成“k1

    结论:不需要存储密码“pwd1”。 无需存储散列密码,即“k1”。 如果我错了,请纠正我。多谢各位

    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 = "Usage: RFC2898 <password>\nYou must specify the password for encryption.\n";
        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 = "Some test data";
                //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("Error: The two values are not equal.");
                    }
                    else
                    {
                        Console.WriteLine("The two values are equal.");
                        Console.WriteLine("k1 iterations: {0}", k1.IterationCount);
                        Console.WriteLine("k2 iterations: {0}", k2.IterationCount);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error: {0}", e);
                }
            }
        }
    }
    
    使用系统;
    使用System.IO;
    使用系统文本;
    使用System.Security.Cryptography;
    公共类RFC2898测试
    {
    //生成密码为pwd1和salt salt1的密钥k1。
    //生成密码为pwd1和salt salt1的密钥k2。
    //使用对称加密使用密钥k1加密数据1,创建edata1。
    //使用对称解密使用密钥k2解密edata1,创建数据2。
    //数据2应该等于数据1。
    private const string usageText=“用法:RFC2898\n必须指定加密密码。\n”;
    公共静态void Main(字符串[]passwordargs)
    {
    //如果未指定文件名,请写入用法文本。
    if(passwordargs.Length==0)
    {
    控制台写入线(usageText);
    }
    其他的
    {
    字符串pwd1=passwordargs[0];
    //创建一个字节数组来保存随机值。
    字节[]salt1=新字节[8];
    使用(RNGCryptoServiceProvider rngCsp=new)
    RNGCryptoServiceProvider())
    {
    //用随机值填充数组。
    rngCsp.GetBytes(salt1);
    }
    //数据1可以是字符串或文件内容。
    string data1=“一些测试数据”;
    //默认迭代计数为1000,因此这两个方法使用相同的迭代计数。
    int=1000;
    尝试
    {
    Rfc2898DeriveBytes k1=新的Rfc2898DeriveBytes(pwd1,salt1,
    我的迭代);
    Rfc2898DeriveBytes k2=新的Rfc2898DeriveBytes(pwd1,salt1);
    //加密数据。
    Aes encAlg=Aes.Create();
    encAlg.Key=k1.GetBytes(16);
    MemoryStream encryptionStream=新的MemoryStream();
    CryptoStream encrypt=新加密流(encryptionStream,
    encAlg.CreateEncryptor(),CryptoStreamMode.Write);
    byte[]utfD1=新系统.Text.UTF8Encoding(false).GetBytes(
    数据1);
    加密.Write(utfD1,0,utfD1.Length);
    encrypt.FlushFinalBlock();
    encrypt.Close();
    字节[]edata1=encryptionStream.ToArray();
    k1.Reset();
    //尝试解密,从而显示它可能是往返的。
    Aes贴花=Aes.Create();
    贴花键=k2.GetBytes(16);
    贴花IV=包装IV;
    MemoryStream DecryptionStreamBack=新建MemoryStream();
    CryptoStream decrypt=新加密流(
    DecryptionStreamBack,贴花.CreateDecryptor(),CryptoStreamMode.Write);
    解密.写入(edata1,0,edata1.Length);
    decrypt.Flush();
    decrypt.Close();
    k2.Reset();
    string data2=新的UTF8Encoding(false).GetString(
    decryptionstreamback.ToArray());
    如果(!data1.Equals(data2))
    {
    WriteLine(“错误:两个值不相等。”);
    }
    其他的
    {
    WriteLine(“两个值相等”);
    WriteLine(“k1迭代:{0}”,k1.IterationCount);
    WriteLine(“k2迭代:{0}”,k2.IterationCount);
    }
    }
    捕获(例外e)
    {
    WriteLine(“错误:{0}”,e);
    }
    }
    }
    }
    
    通常您使用密码派生函数(如PBKDF2)获取密钥(此处为“k1”)进行加密和解密,因此对于解密,用户再次输入密码,并通过PBKDF2再次接收(相同)密钥进行解密。将钥匙(“k1”)存放在任何地方都是不安全的。只需记住一件事——您需要存储(随机)生成的salt和重建同一密钥的迭代次数。如果它运行时没有错误,那么它将演示
    新的Rfc2898DeriveBytes(pwd1,salt1,1000)
    新的Rfc2898DeriveBytes(pwd1,salt1)是相等的。这意味着不指定迭代计数将导致迭代计数为1000。这本可以做得更简单,比如把这个默认行为放到文档中-@ArtjomB它被“隐藏”在文档示例代码中的注释中:
    //默认迭代计数为1000,因此这两个方法使用相同的迭代计数。