how to sign an assembly with a strong name & how to create a pair key怎样通过强名给程序集签名以及如何创建钥匙对?

What is assembly什么是程序集
        Assembly is a logical collection of one or more modules [modjul]. Each assembly has a four-part name that uniquely identifies it. This four-part consists of the friendly name, culture , develpoer, and version of the component. These names are sotred in the assembly manifest [程序集清单] of the assembly itself. The CLR uses the four-part assemebly name to find the correct component at load time. The CLR provides programmatic access to assenbly names via the System.reflection.AssemblyName type, which is easily accessed via the System.Reflection.Assembly.GetName method.
    程序集是一个或者多个模块的集合。每个程序集签名由一个4部分的名称来标示它。这4部分包括文件名称,文化,开发者及版本号。所有程序集信息都保存在程序集自己的程序集清单中。 在载入的时候CLR利用这个程序集名称来找到正确的组件。

    The Name property if the assembly name is not optional, that is to say compulsory. In simple scenarios, the Name property is all that the CLR needs to locate the correct component at load time. When one builds an assembly, this part of name is automatically selected by your compiler based on the target file name.
    All assembly names have a fout-part versionnumber of the form Majar.Minor.Build.Revision. if u do not set this version number explicitly, it defaults to be 0.0.0.0. 
    Assembly Names can contain a cultureinfo attribute that identifies the spoken language and country code that the component has been develped for.

Strong Name Assembly强命名程序集
        different corperation may develop the assemblies that have the same assembly name. if all this assemlbies are installed in the same directory, the lastest installed assembly will overwrite the previois one. This is the reason Why famous Dll Hell ocurrs
    Obiviously, using simpe assemly name to indentify itself is not always secure and not enough, therefore CLR requires a secure mechnism to idenfity each assembly, this is called Strong Name Assembly
        因为不同的公司可能会开发出有相同名字的程序集来,如果这些程序集都被复制到同一 个相同的目录下,最后一个安装的程序集将会代替前面的程序集。这就是著名的Windows “DLL Hell”出现的原因。    
       很明显,简单的用文件名来区分程序集是不够的,CLR需要支持某种机制来唯一的标识一个程序集。这就是所谓的强命名程序集。
       A Strong Name Assembly consists of four feactures which can idenfity the assembly itself: Name, version, culture info, and public/private key
    一个强命名程序集包含四个唯一标志程序集的特性:文件名(没有扩展名),版本号,语言文化信息(如果有的话),公有秘钥。
   
Public Keys and Assemblies公钥和程序集
    The CLR uses public key technology both to uniquely identify the developer of a component and to protect the component from being tampered[篡改] with once it is out of the original developer's hands. Each assembly can have a public key embedded in its manifest that identifies the developer. Assemblies with public keys also have a digital signature that is generated before the assembly is first shipped that provides a secure hash of the assembly manifest. This digital signature cn be verified using only the public key; however, ths signature can be generated only with the corresponding private key, which organizations must guard more closely than their source code. the current builds of the CLR use RSA public/private keys and Secure Hash Algorithm(SHA) hasing to produce the digital signature(fingerprint)
    在CLR 下可以采用公钥对程序集签名,从而能够唯一标示组件开发者,保护组件被篡改等。每一个程序集可以有一个公钥,其内嵌在其程序集清单中来标示其开发者等信息。

How to sign an assembly怎样给程序集签名
       You must have a cryptographic key pair to sign an assembly with a strong name. To sign an assembly with a strong name, you must have a public/privae key pair. This public and private cryptographic key pais is used during complilation to create a strong-named assembly, u can create a key pair using the strong name tool (sn.exe), key pairs files usually have an .snk extension
 
    command line:
    sn -k keyName 
    对程序集进行强命名签名 必须有一对加密钥。创建公钥/私钥的方法非常简单,可以直接调用.net sdk命令: Sn

How to generate public/private key pair via commad SN  如何利用SN 命令创建密钥对

SN command concepts SN 命令基础
1. create a public/private key  创建公钥/密钥命令
    sn -k keypairName.snk  //normally, the suffixed character for key pair is snk, but not mandate.
                                    //一般来说,密钥对后缀名为snk, 但是不是强行规定
    eg. sn -k MyKey.snk
2 to generate a public key  from key pairs and see the content | public key token
    从密钥对中产生公钥,并且查看公钥内容或者公钥令牌
    a. sn -p MyKey.snk MyPublicKey.snk 首先从密钥对中产生公钥
    b. sn -tp MyPublicKey.snk 然后就可以查看公钥内容和公钥令牌了
如下图所示


     c) sn -t MyPublicKey.snk 或者只查看公钥令牌


Get Back to the Topic :How wo sign ?回到主题:如何签名?
    only if we got the key pairs, it's very simple to sign with a strong name. we only need to set the System.Reflection.AssemblyKeyFileAttribute as the key pair in the assemblyinfo.cs file, as shown:
    在得到密钥对后,给程序集签名非常简单。我们只需要在assemblyinfo.cs文件中[一般是该文件]将程序集的AssemblyKeyFile设置为密钥对即可。如下所示
    using System.Reflection;
    [assembly:AssemblyKeyFile("MyKey.snk")]
 


实例讲解:
1. project without strong name signature没有利用strong name signature的工程
    首先我们创建一个dll library工程,就叫做test吧,在project中定义一个MyTest的类,主要提供一个方法Hello.
其相应的主要代码如下:
    namespace test
    {
    public MyTest
    {
        public string Hello()
        {
        return "Hello World";
        }
    }
   }
然后将该project build后我们可以得到test.dll文件
    然后,我们创建另外一个project 来调用这个dll.创建project named Console1,并且添加reference test.dll 。主要代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using test;

namespace Console1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                test.MyTest a = new MyTest();
                Console.WriteLine(a.Hello());
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message.ToString());
            }
        }
    }
}


我们可以得到输出结果:Hello World。
    但是,我们知道,利用很多反向编译工具例如ildasm.exe,可以得到assembly的结构,我们完全可以做另外一个和test.dll接口完全一样的dll,来代替原来的test.dll。
比如,我们编写一个接口完全一样的assembly, 如下
   namespace test
    {
    public MyTest
    {
        public string Hello()
        {
        return "This is a hack DLL";
        }
    }
   }

程序依然能够正常运行!这就是著名的dll hell! 因此,不管是出于恶意或者无意之举,在没有strong name的时候,我们都可以替换原来的dll,从而使得程序不可预见!!
        那么如何防止这样的事情发生呢?我们可以利用strong name.
          首先我们看一下.Net Runtime是怎么识别和导入一个DLL的。在.Net中当我们说Assembly Name的时候,不是仅仅指其文件名(比如abc.dll)。实际 上,Assembly name是由四个部分构成的:Friendly Name,Culture, Pubilc Key(Token), Version。除了Friendly Name 和 Version 是一定有的,其他两个取决于开发者有没有指定它们。比如像我这样的初学者就不会去做一个有Public Key的程序,如果没有指定的话,Culture=neutral,PublicKeyToken=null。我们知道,Assembly 导入有显示导入和隐式导入两种。显示指的是使用Assembly.Load或者Assembly.LoadFrom来动态导入一个Assembly到内存当中。隐式指的是CLR自动导入所要用到的Assembly。当CLR Loader决定导入一个Assembly的时候,它一定会导入和Reference阶段具有相同PublicKey或者PublicKeyToken的Assembly。否则导入失败。比如我们在Reference的abc Assembly的PublicKeyToken是1234123412341234,那么在运行阶段,它就会去找具有1234123412341234PublicToken的Assembly,找不到便抛出异常。当然如果Reference的Assembly不具备Publickey,.Net Runtime 就会省略这个过程,由此,我们可以看出Pulic Key或者PublicKeyToken就是我们需要的数字签名。我们将具有Public Key的程序称之为强签名程序。

一个典型的工程,其签名过程如下:
1.创建公钥/密钥对,command : sn -k test.snk
2.然后在需要强签名的assembly的AssemblyInfo.cs中,设置刚才的钥匙对,设置如下:
    [assembly:AssemblyKeyFile(@"test.snk")]
然后将project build的话, 你就会得到具有强签名的assembly.

但是,在一个大型的项目中,你不可能把钥匙对给项目中的每个开发人员。那么,如何解决这个问题呢?
1.我们可以先让项目中的人员先用public key对assembly进行sign。从钥匙对中获得public key的方法如下:
sn -p test.snk mypublickey.snk
这样就可以得到key pair对应的public key了
    当然,这时,我们可以通过sn -t mypublickey .snk察看 public key token。 或者 sn -tp mypublickey.snk来擦看public key的内容和public key token 了。
项目中的人员利用publickey签名,只需要设置如下:
[assembly:AssemblyKeyFile("mypublic.snk")]
[assembly:AssemblyDelaySign(true)]
注意:   [assembly:AssemblyDelaySign(true)]一定要注意,表明延迟签名 否则assembly 无法通过compile和build.
如果要在延迟签名的条件下,将Assembly发不到GAC,那么必须作如下处理:
sn -vr myother.dll
从而在进行公共部署的时候跳过验证过程。

2.待assembly buidl之后,再利用key pair对assemly签名, 假设我们有一个延迟签名的发布后的assembly named myother.dll。 为了对该程序集进行re-sign(重签名), 我们可以命令如下:
        Sn -R myother.dll test.snk  //test.snk是完整的key pair.
    最后把之前禁止的验证过程重新启动
        sn -vu myother.dll //unregister for verification skipping
    


posted on 2008-04-23 16:40  飞天舞者  阅读(1712)  评论(0编辑  收藏  举报

导航

For more information about me, feel free email to me winston.he@hotmail.com