使用RijndaelManaged从ASP.NET成员资格中解密加密密码

时间:2011-12-29 14:30:23

标签: c# asp.net-membership class-library encryption

最重要的是创建一个custom FTP Authentication Provider。为此,必须从IFtpAuthenticationProvider接口继承,然后在GAC中注册该程序集。之后,需要在IIS的FTP设置中注册程序集。

为了实现这一目标,我必须使用数据库,该数据库在我们之前开发的自定义成员资格和角色提供程序中保存数据库中的用户信息。因此,这意味着我必须使用本地类库app.config文件并使用ConfigurationManager.OpenMappedExeConfiguration()读取它。我从那里读取连接字符串,我甚至可以provide it to Linq-To-Sql classes dynamically。没问题。

接下来,我尝试create a class that inherits from SqlMembershipProvider,以便我可以使用它自己的系统来解密用户的密码。但是,问题是它必须从配置中读取machineKey值。您可以为SqlMembershipProvider提供自定义配置的唯一方法是通过它的Initialize方法(我们不打算在我们的代码中使用它)。但无论如何我试过并失败了。我已经能够为其提供自定义成员资格设置,但不能提供machineKey设置。

所以,我决定激进。我说:我decryptionKey来自machineKey所以我会尝试手动解密密码。

到目前为止,我已尝试使用RijndaelManaged

    private string UnEncodePassword(string encodedPassword, string secretKey)
    {
        string password = encodedPassword;

        var keyBytes = new byte[16];
        var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
        Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));

        RijndaelManaged rm = new RijndaelManaged
        {
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            KeySize = 128,
            BlockSize = 128,
            Key = keyBytes,
            IV = keyBytes
        };

        var encryptedBytes = Convert.FromBase64String(encodedPassword);
        password = Encoding.UTF8.GetString(Decrypt(encryptedBytes, rm));

        return password;
    }

我有点意识到我在这里拍摄空白,因为我不确定使用什么样的填充,最重要的是,即使我可能没有击中正确的IV。到目前为止,我做的最好的事情是得到一些垃圾回应,如: 21l < ( \t )。

所以我需要一些指示。甚至关于如何从另一个角度处理整个问题的建议也是值得欢迎的。

修改

只是为了让事情更清楚一些。我不是想破解密码或任何东西。我有密码,我有decryptionKey等。我只是想找到一种方法来加密/解密它,以便我可以进行用户验证。
我完全清楚加密/解密密码首先不是最好的方法,但有理由这样做。

3 个答案:

答案 0 :(得分:5)

您不应该解密密码。你应该比较密码哈希值。

不应使用可逆加密存储密码。密码意味着存储为哈希(而不是MD5,它太弱了)。

关于上面的评论,您无需解密密码即可对其进行比较。您想要比较哈希值,而不是原始值。系统不应该能够获得密码的原始文本。使用内置的ASP.NET成员资格提供程序正确地将密码存储为哈希。这可能是你不能解密它们的原因,它们是无法解密的。

编辑:关于您使用passwordFormat="Encrypted"作为SQL成员资格提供程序的事实。有了这个事实,您可以使用相同的格式加密密码,使用相同的填充,cipherMode和IV(您需要从SQL数据库中查询),然后只比较加密的密码值。这可能是不必要的工作。您真的只想在代码中使用用户名/密码组合调用Membership的登录功能,并验证它是否成功。您需要确保机器钥匙和相关部件在两个系统中都匹配,否则您将无法成功。

你真的想要计划转移到散列密码,但是存储加密密码而不是散列密码几乎没有意义。它只比用纯文本存储它们稍微好一些。

答案 1 :(得分:1)

您通常不需要存储加密密码,除非您想要一种允许用户查看其当前密码的密码恢复形式。这通常是一个坏主意,它确实需要更多的工作。

按照惯例,您应该只在您的数据库中存储密码的盐渍哈希哈希是一种单向操作(因此,如果您的数据库遭到入侵,任何人都无法解密信息以找出密码。)

要检测用户的密码是否与您存储的密码相匹配,您只需要使用与用于散列数据库中的值相同的盐哈希密码。如果两个哈希匹配,则用户提供了正确的密码。

身份验证算法应如下所示:

  1. 获取哈希值(可能是您使用每个用户唯一的盐,或者是全局用盐)
  2. 生成用户密码的哈希值。
  3. 将散列密码与数据库中存储的密码进行比较以获取指定的用户名(如果使用LINQ-to-SQL,则简单的Any语句可以执行此操作)。
  4. 返回一个值以表示成功或失败。

答案 2 :(得分:1)

我同意其他人使用密码通常比加密密码更安全。

但是因为你无法选择为什么必须使用Encryption中的DecriptionMembershipProvider方法(顺便说一句,我甚至认为这不可行)。

为什么不创建自己的加密方法并在Web应用程序和类库中使用它们。