改进的强命名

强名称签名是用于标识程序集的 .NET Framework 中的标识机制。 它是一个公钥数字签名,通常用于验证从发起方(签名者)传递到接收方(验证程序)的数据的完整性。 此签名用作程序集的唯一身份标识,并确保对程序集的引用没有歧义。 程序集作为生成过程的一部分进行签名,然后在加载时进行验证。

强名称签名有助于防止恶意方篡改程序集,然后使用原始签名者的密钥重新对程序集进行签名。 但是,强名称密钥不包含有关发布者的任何可靠信息,也不包含证书层次结构。 强名称签名不保证签署程序集的人员的可信度,也不保证该人是否是密钥的合法所有者;它仅指示密钥的所有者对程序集进行签名。 因此,不建议使用强名称签名作为信任第三方代码的安全验证程序。 Microsoft验证码是验证代码的建议方法。

传统的强名称的限制

.NET Framework 4.5 之前的版本中使用的强命名技术存在以下缺点:

  • 密钥不断受到攻击,改进的技术和硬件可以更轻松地从公钥推断私钥。 若要防范攻击,需要更大的密钥。 .NET Framework 4.5 之前的 .NET Framework 版本提供使用任何大小密钥(默认大小为 1024 位)进行签名的功能,但使用新密钥对程序集进行签名会中断引用程序集旧标识的所有二进制文件。 因此,如果要保持兼容性,则很难升级签名密钥的大小。

  • 强名称签名仅支持 SHA-1 算法。 最近发现 SHA-1 对于安全哈希应用程序来说不足。 因此,需要更强的算法(SHA-256 或更高版本)。 SHA-1 可能会失去与 FIPS 兼容的地位,这将为那些选择仅使用符合 FIPS 的软件和算法的人带来了问题。

改进的强名称的优点

增强强名称的主要优点是与预先存在的强名称兼容,以及声明一个标识等效于另一个标识的功能:

  • 具有预先签名程序集的开发人员可以将标识迁移到 SHA-2 算法,同时保持与引用旧标识的程序集的兼容性。

  • 创建新程序集且不关心预先存在的强名称签名的开发人员可以使用更安全的 SHA-2 算法,并像往常一样对程序集进行签名。

使用改进的强名称

强名称密钥由签名密钥和标识密钥组成。 程序集使用签名密钥进行签名,并由标识密钥标识。 在 .NET Framework 4.5 之前,这两个键是相同的。 从 .NET Framework 4.5 开始,标识密钥与早期 .NET Framework 版本中保持不变,但签名密钥使用更强的哈希算法进行增强。 此外,使用标识密钥对签名密钥进行签名以创建副署。

AssemblySignatureKeyAttribute 属性使程序集元数据能够将预先存在的公钥用于程序集标识,从而允许旧程序集引用继续工作。 该 AssemblySignatureKeyAttribute 属性使用附属签名来确保新签名密钥的所有者也是旧标识密钥的所有者。

使用 SHA-2 进行签名,无需密钥迁移

从命令提示符运行以下命令以对程序集进行签名,而无需迁移强名称签名:

  1. 生成新的标识密钥(如有必要)。

    sn -k IdentityKey.snk  
    
  2. 提取标识公钥,并指定使用此密钥进行签名时应使用 SHA-2 算法。

    sn -p IdentityKey.snk IdentityPubKey.snk sha256  
    
  3. 使用身份公钥文件对程序集进行延迟签名。

    csc MyAssembly.cs /keyfile:IdentityPubKey.snk /delaySign+  
    
  4. 使用完整标识密钥对对程序集进行重新签名。

    sn -Ra MyAssembly.exe IdentityKey.snk  
    

使用 SHA-2 进行签名,并迁移密钥

从命令提示符运行以下命令,使用迁移的强名称签名对程序集进行签名。

  1. 生成标识和签名密钥对(如有必要)。

    sn -k IdentityKey.snk  
    sn -k SignatureKey.snk  
    
  2. 提取签名公钥,并指定使用此密钥进行签名时应使用 SHA-2 算法。

    sn -p SignatureKey.snk SignaturePubKey.snk sha256  
    
  3. 提取标识公钥,该公钥确定用于生成副署的哈希算法。

    sn -p IdentityKey.snk IdentityPubKey.snk  
    
  4. 生成AssemblySignatureKeyAttribute属性的参数,并将该属性附加到程序集上。

    sn -a IdentityPubKey.snk IdentityKey.snk SignaturePubKey.snk  
    

    这会生成如下所示的输出。

    Information for key migration attribute.
    (System.Reflection.AssemblySignatureKeyAttribute):
    publicKey=
    002400000c80000094000000060200000024000052534131000400000100010005a3a81ac0a519
    d96244a9c589fc147c7d403e40ccf184fc290bdd06c7339389a76b738e255a2bce1d56c3e7e936
    e4fc87d45adc82ca94c716b50a65d39d373eea033919a613e4341c66863cb2dc622bcb541762b4
    3893434d219d1c43f07e9c83fada2aed400b9f6e44ff05e3ecde6c2827830b8f43f7ac8e3270a3
    4d153cdd
    
    counterSignature=
    e3cf7c211678c4d1a7b8fb20276c894ab74c29f0b5a34de4d61e63d4a997222f78cdcbfe4c91eb
    e1ddf9f3505a32edcb2a76f34df0450c4f61e376b70fa3cdeb7374b1b8e2078b121e2ee6e8c6a8
    ed661cc35621b4af53ac29c9e41738f199a81240e8fd478c887d1a30729d34e954a97cddce66e3
    ae5fec2c682e57b7442738
    

    然后,可以将此输出转换为 AssemblySignatureKeyAttribute。

    [assembly:System.Reflection.AssemblySignatureKeyAttribute(
    "002400000c80000094000000060200000024000052534131000400000100010005a3a81ac0a519d96244a9c589fc147c7d403e40ccf184fc290bdd06c7339389a76b738e255a2bce1d56c3e7e936e4fc87d45adc82ca94c716b50a65d39d373eea033919a613e4341c66863cb2dc622bcb541762b43893434d219d1c43f07e9c83fada2aed400b9f6e44ff05e3ecde6c2827830b8f43f7ac8e3270a34d153cdd",
    "e3cf7c211678c4d1a7b8fb20276c894ab74c29f0b5a34de4d61e63d4a997222f78cdcbfe4c91ebe1ddf9f3505a32edcb2a76f34df0450c4f61e376b70fa3cdeb7374b1b8e2078b121e2ee6e8c6a8ed661cc35621b4af53ac29c9e41738f199a81240e8fd478c887d1a30729d34e954a97cddce66e3ae5fec2c682e57b7442738"
    )]
    
  5. 使用标识公钥延迟对程序集签名。

    csc MyAssembly.cs /keyfile:IdentityPubKey.snk /delaySign+  
    
  6. 使用签名密钥对对程序集进行完整签名。

    sn -Ra MyAssembly.exe SignatureKey.snk  
    

另请参阅