Strong Name(强名称)主要作用是用来程序集的统统一命名,通过文件名称、版本号(AssemblyVersion)、数字密钥的公钥记号(Public Key Token)、程序集的区域性设置(Culture)4部分信息来区分程序集。公钥记号还有一个重要用途,就是用来验证大型组织(也不一定是大型组织,只要你知道他的公钥记号就好)开发的.NET程序集。这样可以让程序集无法被伪造,安全性得到了提高。
首先,来谈一下版本号(文件名称就放过了:P),在程序集的Attribute中一共有三种版本号,分别是AssemblyFileVersion、AssemblyInformationalVersion、AssemblyVersion:
(1)、AssemblyFileVersion:为编译器生成的文件加入版本号;
(2)、AssemblyInformationalVersion:加入产品版本号;
(3)、AssemblyVersion:这才是用于定义强名称的版本号;这个版本号由四部分组成分别用"."隔开例如3.0.6701.9其中3为主版本号在最前面,后面一个0为副版本号,再后面6701为编译生成号,最后面的9为修订号。在设定Assembly的AssemblyVersion属性时,可是使用"*"来声明有编译器生成编译生成好和修订号,例如2.3.*,则编译生成号为2000年1月1日起到编译日期止累计的天数,而修订号则是当天累计的秒数(实际为秒数/2,因为24×60×60 = 86400>65536),用这种日期机制来生成版本号,有助于生成持续增加且永不重复版本号;
现在来继续看一下数字密钥的公钥记号,他也对应着Assembly的一个属性,名字叫做AssemblyKeyFiles,他将接受一个由sn.exe(Visual Studio2005可以在"vs安装目录\SDK\v2.0\Bin"下找到)工具生成的.snk(strong name key强名称密钥)文件(例如:sn -k MyKey.snk)作为参数,.snk文件包含一个公钥/密钥对(可以用sn -tp Mykey.snk来查看.snk文件,但是不知道为什么有时候没法查看总是提示:未能将密钥转换为标记 --程序集" <null> "的公钥无效),在这里,使用公钥/密钥对,进行加密主要目的是通过签名防止程序集的伪造,签名的具体过程是:
(1)、在编译后签名前对程序集的所有非主模块计算出其散列值,并保存在主模块清单中的FileDef中;
(2)、通过一定的方式对存在于主模块清单FileDef中的散列值和主模块一起计算出其对应的散列值,并将散列算法的引用保存在主模块清单中的AssemblyDef中;
(3)、对上面算出的主模块的散列值通过密钥(私钥)进行加密,并将加密后的值作为数字签名保存在主模块的CLR文件头中,并将公钥保存在主模块清单的AssemblyDef中。
这样就通过这种公钥/密钥对可以互相加密解密的特性,可以保证如果通过公钥解密的数字签名和当前主模块计算出散列值相同则为真正的程序集,否则则为伪造。
这里如果在程序集的开发过程中,有大量的人介入,每个负责编译强名称程序集的人都需要访问包含公钥/密钥对文件,这样就很难保证密钥不会被泄露出去,为了尽量防止这种情况的发生,便诞生了一种叫做延迟签名(delayed signature)的机制,这种机制的运作方式是:
(1)、首先通过sn -p命令产生一个只包含公钥信息的.snk文件,例如:sn -p MyKey.snk MyPubKey.snk,
后面的这个MyPubKey.snk便是一个只包含公钥信息的.snk文件;
(2)、然后呢通过用true来初始化AssemblyDelaySignAttribute来激活delayed signature,这样开发人员直接使用MyPubKey.snk来代替MyKey.snk来进行开发,编译器不会对主模块进行签名,但是会保留出主模块中用来签名的空间,并且还会将MyPubKey.snk中的公钥信息插入到主模块清单中的AssemblyDef中,并且计算各非主模块的散列值插入到主模块清单的FileDef中。
(3)、最后当开发完毕准备打包部署时,只要使用sn.exe工具的-R(注意大写)选项就可以完成签名,例如:sn.exe -R Assname.exe MyKey.snk。
可以通过sn -T(注意大写)来查看程序集的公钥记号(Public Key Token)。如果程序集的公钥记号是b03f5f7f11d50a3a那么他就石油微软公司提供的,如果过是b77a5c561934e089那么就是有ECMA组织提供的,除非他们的密钥被破解,或者改变,否者这是永久成立的。
一旦程序集进行了数字签名,它就具有了请名称。
最后,我们来简单的了解一下程序集的区域性设置, 区域设置(Culture)是为了程序能够让不同的国家、不同语言的用户来使用而产生的一种机制,他需要为程序支持的每一种区域设置提供一组应用程序呈现给用户的内容(字符串、图片、动画、声音、日期和数字格式等),着被称为应用程序的全球化(globalization)或国际化(internationalization)或本地化(localization)。
区域设置是国家和语言的组合体,比如“en-US”就是表示英语(美国)“fr-CA”表示法语(加拿大),区域设置通过CultureInfoAttribute来实现。
区域设置作为程序集强名成的一部分,但是任何包含代码的程序集必须采用区域无关的设置即提供给CultureInfoAttribute的字符串为空,如果过要用区域设置作为资源的索引就要创建一种仅包含资源的程序集--卫星程序集(satellite assembly)。
关于区域设置,我将在后面专门拿出一个实例来结合说明。在此就不再详述。