将字节数组转换为字符串然后再返回会产生不同的结果

时间:2016-12-22 16:34:15

标签: c# hash encoding character-encoding

我正在使用.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);
    }

当我将salt转换为UTF8字符串时,散列函数将失败,因为它们正在检查字节数组的长度以确保其16字节。如果我将它转换为ASCII字符串,它可以工作但产生一个不同的哈希(这是预期的)。

澄清此代码中的散列片不是问题。弄清楚为什么tmp不同,然后saltAsBytes是关键。

2 个答案:

答案 0 :(得分:3)

我认为这里的问题是ArgonGenerateSalt方法不会返回UTF8编码的字符串,而是returns completely random bytes

您不能将随机字节解码为UTF8字符串并期望它往返。一个简单的例子,看看这个爆炸的地方是做以下事情:

var data = new byte[] { 128 };
var dataAsString = Encoding.UTF8.GetString( data );
var dataAsBytes = Encoding.UTF8.GetBytes( dataAsString );

在此之后,dataAsBytes将是3个字节(特别是239,191,189)。

答案 1 :(得分:2)

  

将字节数组转换为字符串然后再返回会产生不同的结果

二进制数据可能无法转换为字符串,然后返回字节数组 使用Encoding.[AnyEncoding].GetBytesEncoding.[AnyEncoding].GetString

而是使用Convert.ToBase64StringConvert.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