PBKDF2 不在 C# 中返回明文和散列期望值

PBKDF2 is not returning plaintext and hashed expected value in C#

我正在尝试在 C# 中使用 PBKDF2 创建密码,然后我正在尝试检索该密码。

var masterPwd = "masterPassword";
var service = "www.google.com";
byte[] salt = CreateSalt(16);
var encodedPwd = CreateMasterPassword(masterPwd, salt);
var decoded = CreateMasterPassword(encodedPwd, salt);

定义了以下函数:

        public static byte[] CreateSalt(int size)
        {
            var salt = new byte[size];
            using (var random = new RNGCryptoServiceProvider())
            {
                random.GetNonZeroBytes(salt);
            }

            return salt;
        }

        public static string CreateMasterPassword(string password, byte[] salt)
        {

            string PassHash = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA256,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));
            return PassHash;
        }

这样的话,decoded不应该和masterPwd一样吗?

我认为您对 PBKDF2 的作用有些误解。它不是一个你可以恢复明文数据的加密函数(让我们把蛮力放在一边,因为它不是 'intended use')。相反,它是一种 "slow" 哈希机制,通常被描述为 "one way".

PBKDF2是密钥推导函数,但也用于存储密码。这是 PBKDF2 用于密码存储时的典型流程。

  1. 用户创建了一个带有密码的网站帐户。该站点生成一个随机盐,然后将 PBKD2 应用于带有盐的密码,并存储结果和盐。盐以纯文本形式存储。
  2. 当用户需要再次登录时,站点要求输入用户名和密码。它查找该用户的盐,然后将 PBKDF2 重新应用到用户输入的密码。
  3. 它将存储的哈希值与用户输入的哈希值进行比较。如果哈希值相等,则网站知道他们输入的密码正确。

这种方法意味着网站不会以它可能知道的方式存储密码。这允许网站否认知道密码。

如果那是你想要做的,那么你应该如何使用它。

如果您确实需要一种方法来拥有 "two way" 算法,那么这就是从散列到加密。在这个地方将使用对称算法,解决密钥和 IV 管理的所有麻烦问题。您很可能想看一下构建在对称密码(如 libsodium)之上的高度抽象。

libsodium 是一个很好的抽象,建立在原语之上,可以消除猜测如何使用它们的工作。如果提供简单的API,如"encrypt this thing with this password",它能正确地从密码中导出加密密钥,对加密进行某种形式的认证,并受到信息安全专家的好评。