字节数组的十六进制表示

Posted

技术标签:

【中文标题】字节数组的十六进制表示【英文标题】:HEX representation of byte array 【发布时间】:2012-04-16 22:02:14 【问题描述】:

我觉得这个问题很愚蠢,但由于我不知道答案,所以我还是继续。

我正在尝试一些身份验证代码并想知道为什么我从 Rfc2898DeriveBytes 获得的字节数组需要转换为 HEX 并再次转换回字节数组才能正确初始化我的 HMACSHA1 对象。我觉得我是做一些愚蠢的事情,或者只是错过了一些明显的事情。

我的客户端代码是一个基于crypto-js的javascript函数;

var key256bit = Crypto.PBKDF2(passwordEntered, saltBytes, 32,  iterations: 1000 ); 
var hmacBytes = Crypto.HMAC(Crypto.SHA1, url, key256bit,  asBytes: true );
var base64Hash = Crypto.util.bytesToBase64(hmacBytes);

我的服务器端代码如下;

    Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password,
                                              encoding.GetBytes(salt), 1000);
    byte[] key = rfc2898.GetBytes(32);

    // Don't think I should need to do this. 
    // However, it wont work if I initialise HMACSHA1 
    // with the rfc2898.GetBytes(32)
    string test = ByteArrayToString(key); 

    HMACSHA1 hmacSha1 = new HMACSHA1(encoding.GetBytes(test));
    
    byte[] computedHash = hmacSha1.ComputeHash(encoding.GetBytes(requestUri));
    string computedHashString = Convert.ToBase64String(computedHash);

我从网上获取的 ByteArrayToString 方法是;

private static string ByteArrayToString(byte[] ba)

    StringBuilder hex = new StringBuilder(ba.Length * 2);
    foreach (byte b in ba)
        hex.AppendFormat("0:x2", b);
    return hex.ToString();

所以我可以看到我从对rfc2898.GetBytes(32) 的调用中获得了 32 个字节。我使用 ByteArrayToString 方法将其转换为 HEX,以确认它与我在 Javascript 变量 key256bit 中看到的匹配。现在我的测试变量是一个长度为 64 的字符串,当我使用 encoding.GetBytes(test) 将它传递给 HMACSHA1 的构造函数时,它是一个长度为 64 的字节数组。

crypto-js 上的文档有点欠缺,但我认为调用 Crypto.PBKDF2 的参数为 32,它正在创建一个 32 字节长(或 256 位)的密钥。

非常感谢任何澄清。

【问题讨论】:

请在发布代码 sn-ps 时指定您使用的语言。您在客户端使用 JavaScript 并在服务器上使用 Java 并不是很明显。我的意思是,据我所知,您可能正在使用 Dalvik 或 C#。 @OldPro:绝对是 C#,而不是 Java。查看“字符串”的大小写、方法名称等 是的。绝对是 C#。我没有添加关于语言的标签,因为我的问题已经包含 4 个!另外,我有点怀疑我的问题的根本原因是我对代码中正在进行的转换缺乏了解。我会在接下来的几天里做一些调查并报告。 @Jon,我根本不懂 C#。在我粗略的阅读中没有发现细微的差异,这是我的观点。 Moose 先生,我并不是说您需要在标签中添加语言,但正如您所说“我的客户端代码是基于 crypto-js 的 javascript 函数”,如果您说“我的服务器”我会很感激侧面代码是 C# 如下”。这就是我所要求的。抱歉没有说得更清楚。 【参考方案1】:

我怀疑这是问题的根源,在PBKDF2.js:

return options && options.asBytes ? derivedKeyBytes :
       options && options.asString ? Binary.bytesToString(derivedKeyBytes) :
       util.bytesToHex(derivedKeyBytes);

因为您没有提供asBytesasString 的选项,所以它会将密钥转换为十六进制表示 - 就像您的 C# 代码一样。因此,目前您正在使用 512 位密钥,正是因为您正在从“原始密钥”的每个字节生成 2 个字节的“已使用密钥”。

我怀疑如果您在 Javascript 中指定 asBytes 选项,它会在没有 C# 代码中额外的十六进制部分的情况下正常工作。

再说一次,我以前从未见过 PBKDF2,所以我可能离基地很远......

【讨论】:

这对我来说是正确的。 Java 代码中的怪异弥补了 JavaScript 代码中的错误。很好的收获。 @Jon。谢谢你的建议。我会在接下来的几天里看看并报告。我怀疑你是对的,只是看看HMAC.js 的代码,如果它作为字符串传入,它会将密钥转换为字节。我应该从一开始就仔细观察。

以上是关于字节数组的十六进制表示的主要内容,如果未能解决你的问题,请参考以下文章

C# 在表示字符串的大字节数组中寻找子数组

将字符串转换为十六进制字节数组[重复]

将字节数组转换为十六进制字符串

C# 将字符转换为字节(十六进制表示)

为啥十六进制的 5D 表示为 bytearray(b']')?

十六进制颜色怎么表示一个颜色范围