代码改变世界

【读书笔记】.NET本质论第二章-Components(Part Two,public key)

2009-04-19 13:45  横刀天笑  阅读(1806)  评论(2编辑  收藏  举报

接上篇,在上一篇中提到了AssemblyName有一部分是public key token。这里有个public key,实际上public key和private key是成对的。顾名思义,public key就是公钥,private key就是私钥。公钥是公开的,私钥是非公开的,而且密级要很高。

CLR用数字签名的方式防止程序集发布后被篡改,而且还可以唯一的确定发布人。这个签名的方法是使用公钥私钥文件,然后对程序集所有模块取一个哈希生成一个数字签名然后放在程序集的元数据中。

当前CLR版本使用RSA 公钥/私钥和Secure Hash Algorithm(SHA)产生数字签名

在SDK中有一个strong name tool,SN.exe,使用这个工具可以生成公钥私钥对:

sn -k publicprivate.snk

这样publicprivate.snk这个文件里就包含公钥和私钥(私钥436个字节,公钥由128个字节和一个32字节的头部组成)

但是私钥这个东西密级很高(大公司应该制定严密的使用私钥的申请制度),我们编写程序的时候要经常部署测试,总不能每次都申请使用一次私钥签名一次吧。微软也想到了这点,就允许我们光使用公钥签名,公钥是公开的,所以这个不涉及密级的问题。SN.exe可以从公钥私钥文件中取出公钥生成一个新文件:

sn –p publicprivate.snk public.snk

这样public.snk里就只包含公钥了,你可以把这个文件放心的发布给所有的开发人员使用这个来签名,但是千万记住,这个只能在测试的时候使用,发布的时候如果使用这个那什么防篡改啊啥的都没用了。为什么呢?

在我们要使用公钥文件签名的时候我们给程序集使用这样的特性:

using System.Reflection;
[assembly:AssemblyKeyFile("public.snk")]
[assembly:AssemblyDelaySign(false)]

注意这里的AssemblyDelaySign,意思是延迟签名,等到真正发布的时候我们再使用私钥签名。

如果使用这种方式签名啊,生成的程序集签名那个地方就会留空,程序集元数据里只有公钥。

好了,现在程序要发布了,我们是不是把公钥私钥文件拿来,然后用vs把程序再编译一遍呢?当然不是,有的时候程序代码非常大,重新编译一次可不是很容易的。

SN.exe还有一个命令行开关可以给程序集重新签名,就是把刚才那个留空的地方填上真正的签名:

sn –R mylib.dll publicprivate.snk

注意,这里使用的是publicprivate.snk,就是包含私钥的那个文件。

这里说完了,那为啥又要有一个public key token呢?

你想啊,public key有128个字节,那么长,我们使用程序集名引用程序集时难道都把这个带上?而且说过,程序集的元数据里记录了该程序集所引用程序集的所有信息,那要全部记录上该多大啊。如是就搞出个public key token这么个东西,这个东西只有8个字节,SN.exe也有个开关从公钥里生成public key token:

sn –t public.snk

这样我们引用程序集就可以使用这样的字符串了:

System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35

那么这个public key token是怎么得来的呢?算法步骤如下:

1、使用SHA1算法从public key得到它的哈希值

2、取出这个哈希值最后的8个字节

3、然后把这8个字节倒排一下