我正在尝试在ASP.Net Membership系统中创建默认SHA-1密码散列的纯t-sql表示。理想情况下,我会得到的是:
UserName Password GeneratedPassword
cbehrens 34098kw4D+FKJ== 34098kw4D+FKJ==
注意:那里有伪造的base-64文本。我有base64_encode和解码函数正确往返。这是我的尝试,但不起作用:
SELECT UserName, Password, dbo.base64_encode(HASHBYTES('SHA1', dbo.base64_decode(PasswordSalt) + 'test')) As TestPassword FROM aspnet_Users U JOIN aspnet_membership M ON U.UserID = M.UserID
我尝试了很多关于主题的变化,但无济于事。我需要在纯T-Sql中执行此操作;涉及控制台应用程序或类似的东西将使工作翻倍。
因此,如果有人能提供从ASP.Net会员资料中复制该密码的语法应该是什么,我将不胜感激。
答案 0 :(得分:9)
我通过反向引导来自此处ASP.NET Identity default Password Hasher, how does it work and is it secure?的C#代码和来自此处Is there a SQL implementation of PBKDF2?
的一些出色的PBKDF2 SQL函数编写了散列存储过程。首先创建从Is there a SQL implementation of PBKDF2?
获取的这两个函数create FUNCTION [dbo].[fn_HMAC]
(
@hash_algorithm varchar(25),
@key VARCHAR(MAX),
@message VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
--HASH key if longer than 16 characters
IF(LEN(@key) >64)
SET @key = HASHBYTES(@hash_algorithm,@key)
DECLARE @i_key_pad VARCHAR(MAX), @o_key_pad VARCHAR(MAX), @position INT
SET @position = 1
SET @i_key_pad = ''
SET @o_key_pad = ''
--splice ipad & opod with key
WHILE @position <= LEN(@key)
BEGIN
SET @i_key_pad = @i_key_pad + CHAR(ASCII(SUBSTRING(@key, @position, 1)) ^ 54)
SET @o_key_pad = @o_key_pad + CHAR(ASCII(SUBSTRING(@key, @position, 1)) ^ 92)
SET @position = @position + 1
END
--pad i_key_pad & o_key_pad
SET @i_key_pad = LEFT(@i_key_pad + REPLICATE('6',64),64)
SET @o_key_pad = LEFT(@o_key_pad + REPLICATE('\',64),64)
RETURN HASHBYTES(@hash_algorithm,CONVERT(VARBINARY(MAX),@o_key_pad) + HASHBYTES(@hash_algorithm,@i_key_pad + @message))
END
GO
和
CREATE function [dbo].[fn_PBKDF2]
(
@hash_algorithm varchar(25),
@password varchar(max),
@salt varchar(max),
@rounds int,
@outputbytes int
)
returns varchar(max)
as
begin
declare @hlen int
select @hlen = len(HASHBYTES(@hash_algorithm, 'test'))
declare @l int
SET @l = (@outputbytes +@hLen -1)/@hLen
declare @r int
SET @r = @outputbytes - (@l - 1) * @hLen
declare @t varchar(max), @u varchar(max), @block1 varchar(max)
declare @output varchar(max)
SET @output = ''
declare @i int
SET @i = 1
while @i <= @l
begin
set @block1 = @salt +cast(cast(@i as varbinary(4)) as varchar(4))
set @u = dbo.fn_HMAC(@hash_algorithm,@password,@block1)
set @t = @u
declare @j int
SET @j = 1
while @j < @rounds
begin
set @u = dbo.fn_HMAC(@hash_algorithm,@password,@u)
declare @k int
SET @k = 0
DECLARE @workstring varchar(max)
SET @workstring = ''
while @k < @hLen
begin
set @workstring = @workstring + char(ascii(substring(@u,@k+1,1))^ascii(substring(@t,@k+1,1)))
set @k = @k + 1
end
set @t = @workstring
set @j = @j + 1
end
select @output = @output + case when @i = @l then left(@t,@r) else @t end
set @i = @i + 1
end
return master.dbo.fn_varbintohexstr(convert(varbinary(max), @output ))
end
GO
然后创建存储过程以生成哈希密码
CREATE PROCEDURE [dbo].[EncryptPassword2]
@passwordIn AS VARCHAR(MAX),
@passwordOut VARCHAR(max) OUTPUT
AS
-- Generate 16 byte salt
DECLARE @saltVarBin VARBINARY(max)
SET @saltVarBin = (SELECT CAST(newid() AS binary(16)))
-- Base64 encode the salt
DECLARE @saltOut VARCHAR(max)
SET @saltOut = cast('' as xml).value('xs:base64Binary(sql:variable("@saltVarBin"))', 'varchar(max)')
-- Decode salt to pass to function fn_PBKDF2
DECLARE @decodedsalt varchar(max)
SET @decodedsalt = convert(varchar(max),(SELECT CAST('' as xml).value('xs:base64Binary(sql:variable("@saltOut"))', 'varbinary(max)')))
-- Build the password binary string from 00 + salt binary string + password binary string created by 32 byte 1000 iteration ORC_PBKDF2 hashing
DECLARE @passwordVarBinStr VARCHAR(max)
-- Identity V1.0 and V2.0 Format: { 0x00, salt, subkey }
SET @passwordVarBinStr = '0x00' + REPLACE(master.dbo.fn_varbintohexstr(@saltVarBin) + (SELECT dbo.fn_PBKDF2('sha1', @passwordIn, @decodedsalt, 1000, 32)),'0x','')
-- Identity V3.0 Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey } (comment out above line and uncomment below line)
--SET @passwordVarBinStr = '0x01000000010000271000000010' + REPLACE(master.dbo.fn_varbintohexstr(@saltVarBin) + (SELECT dbo.fn_PBKDF2('SHA2_256', @passwordIn, @decodedsalt,10000, 32)),'0x','')
-- Convert the password binary string to base 64
DECLARE @passwordVarBin VARBINARY(max)
SET @passwordVarBin = (select cast('' as xml).value('xs:hexBinary( substring(sql:variable("@passwordVarBinStr"), sql:column("t.pos")) )', 'varbinary(max)') from (select case substring(@passwordVarBinStr, 1, 2) when '0x' then 3 else 0 end) as t(pos))
SET @passwordOut = cast(''as xml).value('xs:base64Binary(sql:variable("@passwordVarBin"))', 'varchar(max)')
RETURN
最后使用
执行存储过程DECLARE @NewPassword varchar(100)
DECLARE @EncryptPassword VARCHAR(max)
select @NewPassword = 'password12344'
EXECUTE EncryptPassword2 @NewPassword, @PasswordOut = @EncryptPassword OUTPUT;
PRINT @EncryptPassword
请注意,对于SQL Server的更高版本,可能需要更改存储过程,因为这是专门为2005年编写的,我相信在以后的版本中转换为base64会有所不同。
答案 1 :(得分:7)
如果您运行的是2005或更高版本,则可以创建CLR(.NET)UDF:
[SqlFunction(
IsDeterministic = true, IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None
)]
public static string EncodePassword(string pass, string salt) {
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] src = Convert.FromBase64String(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) {
return Convert.ToBase64String(sha1.ComputeHash(dst));
}
}
您需要在类中包含以下命名空间:
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
课程必须公开。
构建.dll然后运行以下(每个要调用UDF的数据库)SQL语句:
sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO
IF OBJECT_ID (N'dbo.EncodePassword', N'FS') IS NOT NULL
DROP FUNCTION dbo.EncodePassword;
IF EXISTS (SELECT name FROM sys.assemblies WHERE name='UDF')
DROP ASSEMBLY UDF
CREATE ASSEMBLY UDF FROM 'FULL_PATH_TO.dll' WITH PERMISSION_SET=SAFE
GO
CREATE FUNCTION EncodePassword(
@pass NVARCHAR(4000),
@salt NVARCHAR(4000)
)
RETURNS NVARCHAR(4000)
-- return NULL if any input parameter(s) are NULL
WITH RETURNS NULL ON NULL INPUT
AS
EXTERNAL NAME UDF.[NAMESPACE.CLASSNAME].EncodePassword
GO
显然,将'NAMESPACE.CLASSNAME'替换为您的类的名称空间(如果有)和名称。你可能想要搞乱输入参数和返回值大小。
然后使用T-SQL调用UDF:
SELECT UserName,Password
,dbo.EncodePassword('PASSWORD', PasswordSalt) As TestPassword
FROM aspnet_Users U
JOIN aspnet_membership M ON U.UserID = M.UserID
适合我:)
答案 2 :(得分:3)
您可以在SQL中创建此函数,而不是使用CLR。在这个页面上你会发现一个非常好的例子:
http://svakodnevnica.com.ba/index.php?option=com_kunena&func=view&catid=4&id=4&Itemid=5&lang=en#7
P.S。 byte [] src = Convert.FromBase64String(salt);是正确的方式...
福克斯
答案 3 :(得分:2)
注意:先备份!!
<div class="clickable">
<div class="hid">Phone Number</div>
<i class="fa fa-phone"></i>
</div>
<div class="clickable">
<div class="hid">Email Here</div>
<i class="fa fa-envelope"></i>
</div>
计算哈希值的函数:
Select * into dbo.aspnet_Membership_BACKUP from [dbo].[aspnet_Membership]
我正在将会员数据库从“清除”密码更改为更安全的哈希格式 - 请将其命名为:
/*
Create compatible hashes for the older style ASP.Net Membership
Credit for Base64 encode/decode: http://stackoverflow.com/questions/5082345/base64-encoding-in-sql-server-2005-t-sql
*/
Create Function dbo.AspNetHashCreate (@clearPass nvarchar(64), @encodedSalt nvarchar(64))
Returns nvarchar(128)
as
begin
declare @binSalt varbinary(128)
declare @binPass varbinary(128)
declare @result nvarchar(64)
Select @binPass = CONVERT(VARBINARY(128), @clearPass)
-- Passed salt is Base64 so decode to bin, then we'll combine/append it with password
Select @binSalt = CAST(N'' as XML).value('xs:base64Binary(sql:column("bin"))','VARBINARY(128)')
from (Select @encodedSalt as bin) as temp;
-- Hash the salt + pass, then convert to Base64 for the output
Select @result = CAST(N'' as XML).value('xs:base64Binary(xs:hexBinary(sql:column("bin")))', 'NVARCHAR(64)')
from (Select HASHBYTES('SHA1', @binSalt + @binPass) as bin) as temp2;
-- Debug, check sizes
--Select DATALENGTH(@binSalt), DATALENGTH(@binPass), DATALENGTH(@binSalt + @binPass)
return @result
end
即使我的数据库最初设置为“清除”密码,也会为每条记录创建salt值,但是,如果由于某种原因您没有salt值,则可以使用此值创建它们:
Update [dbo].[aspnet_Membership] set PasswordFormat = 1, Password = dbo.AspNetHashCreate(password, PasswordSalt) where PasswordFormat = 0
然后像这样使用它:
/*
Create compatible salts for the older style ASP.Net Membership (just a 16 byte random number in Base64)
Note: Can't use newId() inside function so just call it like so: dbo.AspNetSaltCreate(newId())
Credit for Base64 encode: http://stackoverflow.com/questions/5082345/base64-encoding-in-sql-server-2005-t-sql
*/
Create Function dbo.AspNetSaltCreate (@RndId uniqueidentifier)
Returns nvarchar(24)
as
begin
return
(Select CAST(N'' as XML).value('xs:base64Binary(xs:hexBinary(sql:column("bin")))', 'NVARCHAR(64)')
from (select cast(@RndId as varbinary(16)) as bin) as temp)
end
享受!
答案 4 :(得分:1)
根据this SO post,,这是他们用来编码/散列你的密码/盐的过程。
public string EncodePassword(string pass, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass); //HERE
byte[] src = Encoding.Unicode.GetBytes(salt); //and HERE
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst); //then they has the bytes not the string...
return Convert.ToBase64String(inArray);
}
我可能错了,但看起来你错过了获取密码和盐字节的步骤。您可以尝试添加它并查看它是否有效吗?