将字节数组转换为字符串然后再返回会产生不同的结果
我正在使用libsodium的.net端口 。 哈希生成函数有两种forms,一种接受字节数组,另一种接受字符串:
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)
我遇到的问题是两种forms在输入值相同时产生相同的散列。
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); }
当我将salt转换为UTF8字符串时,散列函数将失败,因为它们正在检查字节数组的长度以确保其16字节。 如果我将它转换为ASCII字符串,它可以工作但产生一个不同的哈希(这是预期的)。
澄清此代码中的散列片不是问题。 弄清楚为什么tmp
不同,那么saltAsBytes
是关键。
我认为这里的问题是ArgonGenerateSalt
方法不返回UTF8编码的字符串,它返回完全随机的字节 。
您不能将随机字节解码为UTF8字符串并期望它往返。 一个简单的例子来看看这个爆炸的地方是做以下事情:
var data = new byte[] { 128 }; var dataAsString = Encoding.UTF8.GetString( data ); var dataAsBytes = Encoding.UTF8.GetBytes( dataAsString );
在此之后, dataAsBytes
将是3个字节(特别是dataAsBytes
)。
将字节数组转换为字符串然后再返回会产生不同的结果
二进制数据可能无法转换为字符串,然后使用Encoding.[AnyEncoding].GetBytes
返回到字节数组Encoding.[AnyEncoding].GetBytes
和Encoding.[AnyEncoding].GetString
而是使用Convert.ToBase64String
和Convert.FromBase64String
你可以轻松测试……
var bytes = new byte[] { 255, 255, 255 }; var buf = Encoding.UTF8.GetString(bytes); var newbytes = Encoding.UTF8.GetBytes(buf);
newbytes
的长度将是9 …..
编辑:这是@Theo的测试用例
var bytes = new byte[] { 0, 216 }; //any new byte[] { X, 216 }; var buf = Encoding.Unicode.GetString(bytes); var newbytes = Encoding.Unicode.GetBytes(buf); //253,255