CLR笔记:3.共享程序集合强命名程序集
3.1 两种程序集,两种部署
CLR有两种程序集,弱命名程序集和强命名程序集,二者基本一样,区别:强命名程序集时用发布者的公钥/私钥对 进行了签名,唯一性的标识了程序集的发布者。弱命名程序集只能私有部署,强命名程序集可以使用全局部署,也可以私有部署。
3.2 为程序集指派强名称
一个强命名的程序集包括4部分重要属性,标志唯一:一个无扩展名的程序集,一个版本号,一个语言文化标志,一个公钥publickey。此外,还使用发布者的私钥进行签名
MyTypes,Version=1.0.8123.0,Culture=neatral,PublicKeyToken=xxxxxxxxxxxxxxxx(公钥标记)
MS使用公钥/私钥加密技术,这样,没有两家公司有相同的公钥/私钥对(除非他们共享公钥/私钥对)。
使用反射获取强命名程序集的PublicKeyToken
创建强命名程序集的步骤:
1.生成公钥/私钥对:使用SN命令,这个命令所有开关都区分大小写
SN -k MyCompany.keys
——这里MyCompany.keys是创建的文件名
2.将原有程序集升级为强命名程序集
csc /keyfile:MyCompany.keys app.cs
——这里,app.cs是包含清单表的文件,不能对不包含清单表的文件签名。C#编译器会打开MyCompany,使用私钥对程序集进行签名,并在清单中嵌入公钥。
用私钥签名一个文件:是指生成一个强命名程序集时,程序集的FileDef清单中列出了包含的所有本件,将每个文件名称添加到清单中,文件的内容都会根据私钥进行哈希处理,得到的哈希值与文件名一起存入FileDef中。这个哈希值称为RSA数字签名。
最终,生成的包含清单的PE32文件,其中会含有RSA数字签名和公钥
补充1:签名默认使用SHA-1算法,也可以使用别的算法,通过AL命令的/algid开关指定。
补充2,还可以使用SN命令,在原有基础上,得到只含公钥的文件并显示:
SN -p MyCompany.keys MyCompany.PublicKey
——这里MyCompany.PublicKey是创建的公钥文件名
SN -pt MyCompany.PublicKey
——显示公钥与公钥标记
补充4:公钥标记是公钥的最后8个字节。
AssemblyRef中存的是公钥标记,AssemblyDef存的是公钥。
3.3 GAC 全局程序集缓存
GAC一般在C:\Windows\Assembly,结构化的,有很多子目录。
使用Windows Explorer shell扩展来浏览GAC目录,这个工具是在安装Framework时附带的。
不能使用手动方法复制程序集文件到GAC,要使用GACUtil命令。
只能安装强命名程序集到GAC中,而且要有Admin/PowerUser权限。
GAC的好处是可以容纳一个程序集的多个版本。每个版本都有自己的目录。缺点是违反了简单安装的原则。
3.4 在生成的程序集中引用一个强命名程序集
第2章有讲到,对于不完整路径,csc编译时目录查找顺序:
1.工作目录(要编译的cs文件所在)
2.系统目录(csc.exe所在,同时也包括CLR DLL)
3./lib开关指定的目录
4.LIB系统变量指定的目录
安装Framework时,会安装.NET程序集两套副本,一套在编译器/CLR目录——便于生成程序集,另一套在GAC子目录——便于在运行时加载它们。编译时并不去GAC中查找。
3.5 强命名程序集能防范篡改
在安装强命名程序集到GAC时,系统对包含清单的文件内容进行哈希处理,并将这个值与PE32文件中嵌入的RSA数字签名进行比较,如果一致,就再去比较其他文件内容(也是哈希处理在比RSA签名)。一旦有一个不一致,就不能安装到GAC。
如果强命名程序集安装在GAC以外的目录,则会在加载时比较签名。
3.6 延迟签名(部分签名) delayed signing
开发阶段会使用到这个功能
允许开发人员只用公钥来生成一个程序集,而不需要私钥。
编译时,会预留一定空间来存储RSA数字签名,不对文件内容进行哈希处理。CLR会跳过对哈希值的检查。以后可以再对其进行签名。
步骤如下:
1.生成程序集:csc /keyfile: MyCompany.PublicKey /delaysign: MyAssembly.cs
2.跳过对哈希值的检查: SN.exe -Vr MyAssembly.dll
3.准备私钥,再次进行签名: SN.exe -R MyAssembly.dll MyCompany.PrivateKey
4.再次延迟签名: SN.exe -Vu MyAssembly.dll
3.7 私有部署强命名程序集
强命名程序集如果不在GAC中,每次加载都要进行验证,有性能损失。
还可以设计为局部共享强命名程序集,指定配置文件的codeBase即可。
3.8 运行库如何解析类型引用
在TypeRef中查找类型引用的纪录,发现其强签名,然后定位这个程序集的所在位置:会在以下三个地方查找:
1.同一个文件:编译时就能发现(早期绑定)
2.不同的文件,但同一个程序集:在FileRef表中
3.不同的文件,不同的程序集:这时要加载被引用的程序集,从中查找
注:AssemblyRef使用不带扩展名的文件名来引用程序集。绑定程序集时,系统通过探测xx.dll和xx.exe来定位文件。
ModuleDef,ModuleRef,FileDef使用文件名及其扩展名来引用文件。
注:在GAC中查找程序集时,除了名称,版本,语言文化和公钥,还需要CPU体系结构,而且是先根据这个体系结构查找。