【发布时间】:2016-12-22 16:34:14
【问题描述】:
我正在使用.net port of libsodium。哈希生成函数有两种形式,一种接受字节数组,一种接受字符串:
public static byte[] ArgonHashBinary(string password, string salt, long opsLimit, int memLimit, long outputLength = ARGON_SALTBYTES)
public static byte[] ArgonHashBinary(byte[] password, byte[] salt, long opsLimit, int memLimit, long outputLength = ARGON_SALTBYTES)
我遇到的问题是,当输入值相同时,两种形式都会产生相同的哈希值。
var saltAsBytes = PasswordHash.ArgonGenerateSalt();
var saltAsString = Encoding.UTF8.GetString(saltAsBytes);
var tmp = Encoding.UTF8.GetBytes(saltAsString);
var hash1 = PasswordHash.ArgonHashBinary(password, saltAsString, 6, 134217728, 16);
var hash2 = PasswordHash.ArgonHashBinary( Encoding.UTF8.GetBytes(password), saltAsBytes, 6, 134217728, 16);
任何带有“PasswordHash”的东西。是 libsodium 而不是我的代码。
从上面的代码中,当我将它从字符串转换回字节数组时,字节数组。字节数组数组总是不同的长度。 ArgonGenerateSalt() 产生一个长度为 16 的字节数组。当我将它从高于其通常 ~30 的字符串转换回来时(由于产生的盐不同,每次都不同)。
我为什么要转换为 UTF8?因为这就是他们在内部做的事情: https://github.com/adamcaudill/libsodium-net/blob/master/libsodium-net/PasswordHash.cs
public static byte[] ArgonHashBinary(string password, string salt, StrengthArgon limit = StrengthArgon.Interactive, long outputLength = ARGON_SALTBYTES)
{
return ArgonHashBinary(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), limit, outputLength);
}
当我将盐转换为 UTF8 字符串时,散列函数将失败,因为他们正在检查字节数组的长度以确保其 16 个字节。如果我将它转换为 ASCII 字符串,它可以工作,但会产生不同的哈希(这是预期的)。
澄清这段代码中的散列部分不是问题。弄清楚为什么tmp 与saltAsBytes 不同是关键。
【问题讨论】:
-
您是否单步执行过
PasswordHash中的代码,看看哪里有什么不同? -
@JimMischel 哪个部分?上面最重要的部分是当我生成盐然后将其转换为字符串然后再返回到字节数组时。大部分代码当然是我自己的。图书馆唯一要做的就是产生随机盐。 'tmp' 变量最关心的与'saltAsBytes' 不同。所以我认为这与散列片无关。一旦我弄清楚为什么会发生这种情况,散列部分可能会起作用。
-
您确定字节数组只包含有效的 UTF-8 代码吗?当数组包含无效代码点时,我不确定 GetBytes() 是如何工作的。
-
@Theo:钱在哪里? :-) `var bytes = new byte[] { 255, 255, 255 }; var buf = Encoding.Unicode.GetString(bytes); var newbytes = Encoding.Unicode.GetBytes(buf); var n = String.Join(", ", newbytes); ` 返回 255、255、253、255
-
@Theo 在我的回答中查看测试用例,然后把钱给一个无家可归的人。
标签: c# hash encoding character-encoding