首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Server 2008 CLR对密码进行散列

使用Server 2008 CLR对密码进行散列
EN

Stack Overflow用户
提问于 2013-10-30 20:54:06
回答 1查看 3K关注 0票数 3

我试图使用SHA-512算法在Server 2008中实现哈希和加密密码的解决方案。此解决方案基于Michael的“专家SQL Server 2008加密”一书。根据他的例子,我能够在visual 2010中构建这个项目(.NET 3.5在C#中),并部署到Server 2008 (如下面的代码所示)。

代码语言:javascript
复制
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Cryptography;

namespace Apress.Samples
{
    public partial class CustomEncryption
    {
    [Microsoft.SqlServer.Server.SqlFunction
    (
      IsDeterministic = true,
      DataAccess = DataAccessKind.None
    )]
    public static SqlBytes SaltedHash
    (
      SqlString Algorithm,
      [SqlFacet(MaxSize = -1)] SqlBytes PlainText,
      SqlBytes Salt
    )
    {
        // Return NULL if any of the parameters is NULL
        if (Algorithm.IsNull || PlainText.IsNull || Salt.IsNull)
            return SqlBytes.Null;

        // Determine which algorithm to use
        bool HashDefined = true;
        HashAlgorithm Hash = null;
        switch (Algorithm.Value.ToUpper())
        {
            case "SHA256":
                Hash = new SHA256Managed();
                break;

            case "SHA384":
                Hash = new SHA384Managed();
                break;

            case "SHA512":
                Hash = new SHA512Managed();
                break;

            default:
                HashDefined = false;
                break;
        }
        if (!HashDefined)
            throw new Exception
              ("Unsupported hash algorithm - use SHA256, SHA384 or SHA512");

        // Combine the plaintext with the salt
        byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length];
        for (long i = 0; i < Salt.Length; i++)
            PlainTextWithSalt[i] = Salt[i];
        for (long i = Salt.Length; i < PlainText.Length; i++)
            PlainTextWithSalt[i] = PlainText.Value[i - Salt.Length];

        // Generate the hash and return the result
        byte[] HashBytes = Hash.ComputeHash(PlainTextWithSalt);
        return new SqlBytes(HashBytes);
    }
}
}

当我使用下面的代码从SQL执行测试时,将按照每个算法的预期生成哈希。

代码语言:javascript
复制
DECLARE @plaintext varchar(15);
SET @plaintext = 'ABCDEFGHIJ';

DECLARE @salt varbinary(16);
SET @salt = Crypt_Gen_Random(16);

DECLARE @sha256 varbinary(32)
DECLARE @sha384 varbinary(48)
DECLARE @sha512 varbinary(64)

SELECT @sha256 = dbo.SaltedHash('SHA256', CAST(@plaintext AS varbinary(max)), @salt);
SELECT @sha384 = dbo.SaltedHash('SHA384', CAST(@plaintext AS varbinary(max)), @salt);
SELECT @sha512 = dbo.SaltedHash('SHA512', CAST(@plaintext AS varbinary(max)), @salt);

SELECT 'SHA-256' AS algorithm, @sha256 AS hash
UNION ALL
SELECT 'SHA-384', @sha384
UNION ALL
SELECT 'SHA-512', @sha512;

我想使用它来验证登录,在这里我假设我需要检索存储给用户记录的salt值,并将它传递给SaltedHash函数,在那里它将返回哈希值。从那里开始,我将比较函数返回的散列值和存储在用户记录中的散列值。

我遇到的问题是,当我测试传递一个硬编码的盐值('0x0E5ECC235FF6BD7337FFDDE5799D4EEA')以及明文('ABCDEFGHIJ')以模拟哈希值时(例如,用于比较散列密码)。如果我用相同的硬编码盐值提供明文值('1234567890'),它将返回完全相同的散列值。实际上,任何10个字符的明文值都会返回相同的散列值。

代码语言:javascript
复制
DECLARE @plaintext varchar(15);
SET @plaintext = 'ABCDE12345';

DECLARE @salt varbinary(16);
SET @salt = 0x0E5ECC235FF6BD7337FFDDE5799D4EEA; // Hardcoded salt value!

SELECT @salt

DECLARE @sha256 varbinary(32)
DECLARE @sha384 varbinary(48)
DECLARE @sha512 varbinary(64)

SELECT @sha256 = dbo.SaltedHash('SHA256', CAST(@plaintext AS varbinary(max)), @salt);
SELECT @sha384 = dbo.SaltedHash('SHA384', CAST(@plaintext AS varbinary(max)), @salt);
SELECT @sha512 = dbo.SaltedHash('SHA512', CAST(@plaintext AS varbinary(max)), @salt);

SELECT 'SHA-256' AS algorithm, @sha256 AS hash
UNION ALL
SELECT 'SHA-384', @sha384
UNION ALL
SELECT 'SHA-512', @sha512;

我假设问题在于“将明文与salt相结合”代码,但不确定。

对于如何解决这个问题,有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-30 21:51:28

是的,您对数组副本犯了错误,您从未将PlainText的最后一个PlainText字节复制到目标数组中。这里是您的原始代码的更正版本。所有需要做的就是i需要上升到PlainText.Length + Salt.Length

代码语言:javascript
复制
// Combine the plaintext with the salt
byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length];
for (long i = 0; i < Salt.Length; i++)
    PlainTextWithSalt[i] = Salt[i];
for (long i = Salt.Length; i < PlainText.Length + Salt.Length; i++)
    PlainTextWithSalt[i] = PlainText.Value[i - Salt.Length];

然而,使用Array.Copy更容易做到这一点

代码语言:javascript
复制
byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length];
Array.Copy(Salt, PlainTextWithSalt, Salt.Length);
Array.Copy(PlainText, PlainTextWithSalt, Salt.Length, PlainText.Length);

还有一件事要注意。修改密码是很好的,但是那仅仅是一半的战斗,您也需要使哈希。通常,这是通过像bcryptPBKDF2这样的函数来完成的,这些函数为您管理salt和PBKDF2,另外它们还允许您将哈希的迭代次数设置为对密码执行的次数(您通常会选择一个大的数字,您希望这个数字尽可能大,这在您的终端系统中是可以容忍的)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19693615

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档