You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何按ECMA-335计算.NET PublicKeyToken需取SHA-1哈希最后8字节?

.NET PublicKeyToken生成:为何取SHA-1哈希最后8字节而非前8字节?

我需要通过编程从给定公钥生成.NET的PublicKeyToken。根据ECMA-335标准第6.3节,PublicKeyToken应取发起者公钥SHA-1哈希的低8字节。我据此编写了取哈希前8字节的方法,但测试没得到预期值091b960f069954ca(和对应私钥签名程序集的实际值一致)。改成取哈希最后8字节后才得到正确结果,但我有疑问:x86、x86_64、ARM等架构都是小端序,按道理原方法才对,为什么必须取最后8字节?

测试用公钥

var publicKey = new byte[160] { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 121, 191, 60, 215, 5, 6, 37, 199, 18, 215, 166, 85, 224, 129, 164, 160, 163, 111, 82, 127, 149, 231, 69, 204, 27, 58, 137, 42, 212, 7, 88, 195, 89, 221, 169, 1, 63, 103, 25, 169, 186, 47, 113, 156, 15, 213, 27, 16, 14, 203, 95, 12, 246, 198, 239, 188, 175, 91, 226, 216, 216, 147, 227, 75, 134, 190, 129, 56, 169, 242, 29, 205, 12, 211, 166, 142, 138, 120, 79, 239, 229, 155, 216, 159, 248, 41, 41, 232, 96, 92, 239, 194, 14, 36, 178, 82, 8, 180, 163, 80, 4, 108, 131, 222, 91, 249, 231, 164, 116, 37, 84, 128, 15, 53, 40, 50, 124, 233, 40, 112, 69, 239, 74, 8, 34, 34, 183, 228 };

原方法(未得到正确结果)

public static string GetPublicKeyToken(byte[] publicKey)
{
  using (var sha1 = SHA1.Create())
  {
    var publicKeyHash = sha1.ComputeHash(publicKey);
    var publicKeyToken = new StringBuilder(16);

    for (int i = 0; i < 8; i++)
    {
       publicKeyToken.Append(publicKeyHash[i].ToString("x2"));
    }

    return publicKeyToken.ToString();
  }
}

修改后正确方法

public static string GetPublicKeyTokenMod(byte[] publicKey)
{
  using (var sha1 = SHA1.Create())
  {
    var publicKeyHash = sha1.ComputeHash(publicKey);
    var publicKeyToken = new StringBuilder(16);

    for (int i = publicKeyHash.Length - 1; i >= publicKeyHash.Length - 8; i--)
    {
       publicKeyToken.Append(publicKeyHash[i].ToString("x2"));
    }

    return publicKeyToken.ToString();
  }
}

问题原因解析

ECMA-335里说的“低8字节”是指数值意义上的低64位,而非字节数组的前8个元素。SHA-1哈希的字节数组是按大端序存储的——也就是数组的第一个字节是哈希值的最高位字节,最后一个字节是最低位字节。

举个简单例子:假设哈希值对应的64位整数是0x1122334455667788,大端序存储的字节数组是[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],其中数值的低8字节(整个64位)对应的就是数组的最后8个字节。而CPU的小端序是把最低位字节放在数组开头,但SHA-1的输出并不遵循CPU字节序,它有固定的大端存储规则。

所以当我们需要取数值上的低8字节时,要从SHA-1哈希数组的末尾往前取8个字节,并且按从后往前的顺序拼接成字符串——因为字符串形式的PublicKeyToken是把低字节对应的十六进制放在前面,这正好对应小端序的展示方式,但本质是因为哈希本身是大端存储,取低数值位需要拿数组末尾的字节,再反转顺序来匹配Token的字符串格式。


内容的提问来源于stack exchange,提问作者ackh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:01:16