我正在努力将所有数据库从MS SQL服务器迁移到Postgres。在这个过程中,我正在编写Postgres中的等效代码,以产生在MS SQL中获得的相同散列文本。
以下是我在MS SQL中的代码:
DECLARE @HashedText nvarchar(50)
DECLARE @InputText nvarchar(50) = 'password'
DECLARE @HashedBytes varbinary(20) -- maximum size of SHA1 output
SELECT @HashedBytes = HASHBYTES('SHA1', @InputText)
SET @HashedText = CONVERT(nvarchar(50), @HashedBytes, 2)
SELECT @HashedText
这产生了值E8F97FBA9104D1EA5047948E6DFB67FACD9F5B73
以下是用Postgres编写的等效代码:
DO
$$
DECLARE v_InputText VARCHAR = 'password';
DECLARE v_HashedText VARCHAR;
DECLARE v_HashedBytes BYTEA;
BEGIN
SELECT
ENCODE(DIGEST(v_InputText, 'SHA1'), 'hex')
INTO
v_HashedBytes;
v_HashedText := CAST(v_HashedBytes AS VARCHAR);
RAISE INFO 'Hashed Text: %', v_HashedText;
END;
$$;
这产生了值5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
。
花了一些时间后,我才明白在MS SQL中用'VARCHAR'替换数据类型'NVARCHAR'会产生与Postgres相同的结果。
现在的问题是在MS SQL中我们已经有密码哈希并存储在数据库中,如上所示。我无法将MS SQL中的散列文本转换为Postgres,也无法在Postgres中生成相同的散列文本,因为Postgres不支持UTF-16 unicode。
所以,我只是想知道是否有可能遵循解决方案?
让我们依次看看你的建议:
- 将MS SQL中生成的十六进制值转换为等效于使用VARCHAR数据类型生成的十六进制值(在Postgres中为相同值)
这归结为将用户的密码从UTF-16转换为UTF-8(或其他编码)并重新散列它。要做到这一点,你需要知道用户的密码,从理论上讲,你不需要 - 这就是首先对它进行哈希处理的重点。
在实践中,您使用的是未加盐的SHA1哈希值,其中存在大型预先计算的表格,并且使用GPU优化算法可以实现蛮力。因此,“灰帽子”选项将破解所有用户的密码,并重新哈希。
如果你这样做,使用salt和更好的哈希函数重新哈希它们以及将它们转换为UTF-8可能是明智的。
- 在Postgres中将UTF8文本转换为UTF16文本(甚至通过任何类型的扩展)并生成十六进制值,这些值等同于在MS SQL中生成的值
从理论上讲,这更简单,只需要一个例程来进行字符串转换。但是,正如您所发现的,Postgres中没有内置支持。
对于任何完全由ASCII字符组成的字符串,转换很简单:在字符串的每个字节之前插入一个NULL字节(hex 00
)。但这会破坏使用不在此范围内的字符的任何密码。
另一种方法是将生成哈希的责任移出数据库: