生成强名称程序集
通過嵌入公鑰并使用私鑰簽名,可以生成強(qiáng)名稱(strong name)的程序集。強(qiáng)名稱程序集由4部分進(jìn)行標(biāo)識:名稱、版本、區(qū)域性和公鑰。與之相對的,我們可以把沒有嵌入公鑰和使用私鑰簽名的程序集稱之為弱名稱(weak name)程序集(這個(gè)術(shù)語是Jffery Richter創(chuàng)造的)。強(qiáng)名稱程序集與弱名稱程序集相比,有以下特點(diǎn):
??? * 強(qiáng)名稱程序集可以保證唯一性。公/私密鑰對是由發(fā)行者自行生成的,是唯一的,保證了程序集的標(biāo)識不會重復(fù)。
??? * 強(qiáng)名稱程序集可以防篡改。強(qiáng)類型程序集使用私鑰對自己進(jìn)行了簽名,這樣在被加載時(shí)可以檢查程序集是否被修改。
??? * 強(qiáng)名稱程序集可以實(shí)施版本策略。對于弱名稱程序集,引用它的程序不會關(guān)心它的版本,而對于強(qiáng)類型的程序集來說,引用它的程序會被綁定到特定版本的程序集上,如果使用新版本的強(qiáng)名稱程序集替換舊版本,會導(dǎo)致程序無法運(yùn)行。(當(dāng)然還可以使用配置文件對強(qiáng)名稱程序集進(jìn)行重定向)。
??? * 強(qiáng)名稱程序集可以部署到GAC中。GAC指全局程序集緩存,這是一個(gè)公共目錄,放在此處的程序集可以被本機(jī)任意一個(gè)程序所引用。弱名稱程序集無法部署到此處。不同版本的相同程序集還可以同時(shí)存在于GAC中。
??? * 強(qiáng)名稱程序集只能引用強(qiáng)名稱程序集。弱名稱程序集可以引用強(qiáng)名稱程序集,也可以引用弱名稱程序集,但強(qiáng)名稱程序集只能引用強(qiáng)名稱程序集。
??? * 強(qiáng)名稱程序集支持并行執(zhí)行。并行(side-by-side)執(zhí)行是指程序同時(shí)引用了多個(gè)版本的同名程序集,這樣在運(yùn)行時(shí),會有多個(gè)版本的同名程序集被加載和同時(shí)執(zhí)行。通常不建議使用。
下面來研究一下如何生成強(qiáng)名稱的程序集。首先,使用SN.exe創(chuàng)建一個(gè)密鑰文件:
sn.exe -k MyKey.snk
生成的文件包含了公鑰和私鑰的內(nèi)容。我們可以查看公鑰的內(nèi)容,私鑰是不允許查看的,所以要先將公鑰提取出來。仍然是使用SN.exe:
sn -p MyKey.snk MyPublicKey.snk
sn -tp MyPublicKey.snk
前一個(gè)命令將密鑰文件中的公鑰提取出來,放到 MyPublicKey.snk 文件中;后一個(gè)命令用于顯示該文件中的公鑰和公鑰標(biāo)記(Public key token),顯示的內(nèi)容可能如下(每個(gè)人生成的都不同):
Microsoft (R) .NET Framework Strong Name Utility? Version 3.5.21022.8
Copyright (c) Microsoft Corporation.? All rights reserved.
Public key is
0024000004800000940000000602000000240000525341310004000001000100757c8b7854ffcb
4763250746c094e45db0c715214415fb01bd178f3374224c1292dbbc9dddfb6af7de1766888464
1a39fbea9d0bee001c093b228400aa39c0db5724fc11c221bd2c7442a30ef26c076b1bb0f559ce
7955572b4174125494a593c199d968019323483e72d5bdb93d96af14ccfeb0c5d4af6ea191d226
e6812db5
Public key token is 337642649f453c2c
公鑰標(biāo)記是公鑰的64位散列值,用于簡化對公鑰的引用。
第二步是創(chuàng)建強(qiáng)名稱程序集。我們可以在源文件中使用AssemblyKeyFileAttribute,但在編譯時(shí)會產(chǎn)生警告,建議使用命令行選項(xiàng)來代替此特性。所以此處使用csc.exe:
csc /t:library /keyfile:MyKey.snk MyType.cs
運(yùn)行后得到 MyType.dll ,我們可以顯示其中包含的公鑰標(biāo)記,看是否和上面的相同:
sn -Tp MyType.dll
顯示內(nèi)容如下:
Microsoft (R) .NET Framework Strong Name Utility? Version 3.5.21022.8
Copyright (c) Microsoft Corporation.? All rights reserved.
Public key is
0024000004800000940000000602000000240000525341310004000001000100757c8b7854ffcb
4763250746c094e45db0c715214415fb01bd178f3374224c1292dbbc9dddfb6af7de1766888464
1a39fbea9d0bee001c093b228400aa39c0db5724fc11c221bd2c7442a30ef26c076b1bb0f559ce
7955572b4174125494a593c199d968019323483e72d5bdb93d96af14ccfeb0c5d4af6ea191d226
e6812db5
Public key token is 337642649f453c2c
由此可見,公鑰的內(nèi)容確實(shí)嵌入到了程序集當(dāng)中。除此之外,程序集的全部內(nèi)容經(jīng)過散列編碼后,還使用密鑰進(jìn)行了簽名,也嵌入到了程序集中。
這樣我們就得到了一個(gè)強(qiáng)名稱程序集。如果有程序引用了該程序集,會記錄由以下內(nèi)容標(biāo)識的程序集:
MyType, Version=1.0.3087.28686, Culture=neutral, PublicKeyToken=337642649f453c2c
這些內(nèi)容唯一的標(biāo)識了一個(gè)強(qiáng)名稱程序集,由于公鑰太長,這里只引用了公鑰標(biāo)記。當(dāng)程序運(yùn)行時(shí),CLR 會根據(jù)這些內(nèi)容去搜尋程序集,只有完全匹配的程序集才會被加載,即便是版本的細(xì)微差別都不會忽略。如果沒有找到,或者找到的程序集不匹配,都會產(chǎn)生異常。
Strong Name(強(qiáng)名稱)主要作用是用來程序集的統(tǒng)統(tǒng)一命名,通過文件名稱、版本號(AssemblyVersion)、數(shù)字密鑰的公鑰記號(Public Key Token)、程序集的區(qū)域性設(shè)置(Culture)4部分信息來區(qū)分程序集。公鑰記號還有一個(gè)重要用途,就是用來驗(yàn)證大型組織(也不一定是大型組織,只要你知道他的公鑰記號就好)開發(fā)的.NET程序集。這樣可以讓程序集無法被偽造,安全性得到了提高。
????? 首先,來談一下版本號(文件名稱就放過了:P),在程序集的Attribute中一共有三種版本號,分別是AssemblyFileVersion、AssemblyInformationalVersion、AssemblyVersion:
??????? (1)、AssemblyFileVersion:為編譯器生成的文件加入版本號;
??????? (2)、AssemblyInformationalVersion:加入產(chǎn)品版本號;
??????? (3)、AssemblyVersion:這才是用于定義強(qiáng)名稱的版本號;這個(gè)版本號由四部分組成分別用"."隔開例如3.0.6701.9其中3為主版本號在最前面,后面一個(gè)0為副版本號,再后面6701為編譯生成號,最后面的9為修訂號。在設(shè)定Assembly的AssemblyVersion屬性時(shí),可是使用"*"來聲明有編譯器生成編譯生成好和修訂號,例如2.3.*,則編譯生成號為 2000年1月1日起到編譯日期止累計(jì)的天數(shù),而修訂號則是當(dāng)天累計(jì)的秒數(shù)(實(shí)際為秒數(shù)/2,因?yàn)?4×60×60 = 86400>65536),用這種日期機(jī)制來生成版本號,有助于生成持續(xù)增加且永不重復(fù)版本號;
????? 現(xiàn)在來繼續(xù)看一下數(shù)字密鑰的公鑰記號,他也對應(yīng)著Assembly的一個(gè)屬性,名字叫做AssemblyKeyFiles,他將接受一個(gè)由sn.exe(Visual Studio2005可以在"vs安裝目錄\SDK\v2.0\Bin"下找到)工具生成的.snk(strong name key強(qiáng)名稱密鑰)文件(例如:sn -k MyKey.snk)作為參數(shù),.snk文件包含一個(gè)公鑰/密鑰對(可以用sn -tp Mykey.snk來查看.snk文件,但是不知道為什么有時(shí)候沒法查看總是提示:未能將密鑰轉(zhuǎn)換為標(biāo)記 --程序集" <null> "的公鑰無效),在這里,使用公鑰/密鑰對,進(jìn)行加密主要目的是通過簽名防止程序集的偽造,簽名的具體過程是:
??? (1)、在編譯后簽名前對程序集的所有非主模塊計(jì)算出其散列值,并保存在主模塊清單中的FileDef中;
??? (2)、通過一定的方式對存在于主模塊清單FileDef中的散列值和主模塊一起計(jì)算出其對應(yīng)的散列值,并將散列算法的引用保存在主模塊清單中的AssemblyDef中;
??? (3)、對上面算出的主模塊的散列值通過密鑰(私鑰)進(jìn)行加密,并將加密后的值作為數(shù)字簽名保存在主模塊的CLR文件頭中,并將公鑰保存在主模塊清單的AssemblyDef中。
??? 這樣就通過這種公鑰/密鑰對可以互相加密解密的特性,可以保證如果通過公鑰解密的數(shù)字簽名和當(dāng)前主模塊計(jì)算出散列值相同則為真正的程序集,否則則為偽造。
??? 這里如果在程序集的開發(fā)過程中,有大量的人介入,每個(gè)負(fù)責(zé)編譯強(qiáng)名稱程序集的人都需要訪問包含公鑰/密鑰對文件,這樣就很難保證密鑰不會被泄露出去,為了盡量防止這種情況的發(fā)生,便誕生了一種叫做延遲簽名(delayed signature)的機(jī)制,這種機(jī)制的運(yùn)作方式是:
??? (1)、首先通過sn -p命令產(chǎn)生一個(gè)只包含公鑰信息的.snk文件,例如:sn -p MyKey.snk MyPubKey.snk,
后面的這個(gè)MyPubKey.snk便是一個(gè)只包含公鑰信息的.snk文件;
??? (2)、然后呢通過用true來初始化AssemblyDelaySignAttribute來激活delayed signature,這樣開發(fā)人員直接使用MyPubKey.snk來代替MyKey.snk來進(jìn)行開發(fā),編譯器不會對主模塊進(jìn)行簽名,但是會保留出主模塊中用來簽名的空間,并且還會將MyPubKey.snk中的公鑰信息插入到主模塊清單中的AssemblyDef中,并且計(jì)算各非主模塊的散列值插入到主模塊清單的FileDef中。
??? (3)、最后當(dāng)開發(fā)完畢準(zhǔn)備打包部署時(shí),只要使用sn.exe工具的-R(注意大寫)選項(xiàng)就可以完成簽名,例如:sn.exe -R Assname.exe MyKey.snk。
??? 可以通過sn -T(注意大寫)來查看程序集的公鑰記號(Public Key Token)。如果程序集的公鑰記號是b03f5f7f11d50a3a那么他就石油微軟公司提供的,如果過是b77a5c561934e089那么就是有ECMA組織提供的,除非他們的密鑰被破解,或者改變,否者這是永久成立的。
??? 一旦程序集進(jìn)行了數(shù)字簽名,它就具有了請名稱。
????? 最后,我們來簡單的了解一下程序集的區(qū)域性設(shè)置,區(qū)域設(shè)置(Culture)是為了程序能夠讓不同的國家、不同語言的用戶來使用而產(chǎn)生的一種機(jī)制,他需要為程序支持的每一種區(qū)域設(shè)置提供一組應(yīng)用程序呈現(xiàn)給用戶的內(nèi)容(字符串、圖片、動(dòng)畫、聲音、日期和數(shù)字格式等),著被稱為應(yīng)用程序的全球化(globalization)或國際化(internationalization)或本地化(localization)。
????? 區(qū)域設(shè)置是國家和語言的組合體,比如“en-US”就是表示英語(美國)“fr-CA”表示法語(加拿大),區(qū)域設(shè)置通過CultureInfoAttribute來實(shí)現(xiàn)。
????? 區(qū)域設(shè)置作為程序集強(qiáng)名成的一部分,但是任何包含代碼的程序集必須采用區(qū)域無關(guān)的設(shè)置即提供給CultureInfoAttribute的字符串為空,如果過要用區(qū)域設(shè)置作為資源的索引就要?jiǎng)?chuàng)建一種僅包含資源的程序集--衛(wèi)星程序集(satellite assembly)。
??? 關(guān)于區(qū)域設(shè)置
關(guān)于強(qiáng)名稱
強(qiáng)名稱是標(biāo)識一個(gè)配件的方法(當(dāng)然也可用于標(biāo)識一個(gè).Net 應(yīng)用程序, 應(yīng)用程序配件單或部署配件單)。它具有充分限定(full qualified)的特性, 可以全局唯一標(biāo)識一個(gè)配件。它由以下幾個(gè)部分組成:
??????????????? +
????????????????? 簡單的用于描述配件的名稱, 如mscorlib;
??????????????? +
????????????????? 版本號;
??????????????? +
????????????????? 文化信息, 包含關(guān)于配件的語言環(huán)境信息, 缺省為不確定(neutral);
??????????????? +
????????????????? 公有密鑰 (Public Key);
??????????????? +
????????????????? 數(shù)字簽名 (Digital Signature);
公有密鑰和數(shù)字簽名用于保證配件內(nèi)容不會被第三方輕易篡改。關(guān)于它們的詳細(xì)信息請參考第3節(jié)。
強(qiáng)名稱的作用
和以往非托管(Native/Unmanaged)的組件,如COM,普通的DLL,及弱名稱配件僅僅使用簡單的名稱標(biāo)識自身相比,使用強(qiáng)名稱的配件具有如下的好處:
?
1)可以精確地標(biāo)識一個(gè)配件
使用強(qiáng)名稱能夠精確區(qū)分不同的配件,強(qiáng)名稱中的版本信用于識別同一個(gè)配件不同的版本,從而避免版本沖突問題,比如DLL地獄(DLL Hell)。
2)防止配件內(nèi)容被篡改
強(qiáng)名稱對配件的內(nèi)容采用了相應(yīng)的簽名機(jī)制,配合相應(yīng)的驗(yàn)證機(jī)制,雖然不能完全避免但可防止配件內(nèi)容被第三方輕易篡改。
# 其實(shí)與傳統(tǒng)的直接被編譯成機(jī)器碼的程序不同,.Net 配件是以托管代碼形式保存在PE格式的文件中的,也就是以微軟中間語言代碼(MSIL)形式存在。因此只要對MSIL比較熟悉,第三方就可以很容易地對.Net配件進(jìn)行篡改,所以為配件使用強(qiáng)名稱是保護(hù)配件內(nèi)容安全的方法之一。
強(qiáng)簽名的實(shí)現(xiàn)
強(qiáng)簽名
配件強(qiáng)簽名的過程如下圖所示:
?
?
?
?
角色、對象:
??????????????? +
????????????????? .Net Developer: .Net配件開發(fā)者;
??????????????? +
????????????????? Strong name Tool(Sn.exe)/Assembly Linker(Al.exe): 配件強(qiáng)簽名工具
??????????????? +
????????????????? Strong-naming Assembly:強(qiáng)名稱配件
??????????????? +
????????????????? Cryptography:密碼系統(tǒng)
??????????????? + Consumer of Strong-named Assembly:強(qiáng)名稱配件使用者
過程:
1)(1-2)配件開發(fā)者使用相應(yīng)的工具如Sn.exe產(chǎn)生用于非對稱加解密的密鑰對,其包含了一個(gè)公有密鑰和一個(gè)私有密鑰。Sn.exe將創(chuàng)建并把密鑰對保存到指定的文件中;
2)(3)配件開發(fā)者以保存密鑰對的文件作為參數(shù)向配件連接器Al.exe請求對配件進(jìn)行強(qiáng)簽名,下面是一個(gè)例子:
al /out:Anor.dll Anor.module /keyfile:1.snk
?
# 除了使用配件連接器之外,我們也可以通過以下方式請求編譯器對配件進(jìn)行強(qiáng)簽名:
??????????????????????????? *
????????????????????????????? 使用編譯器選項(xiàng) 如、/keyfie (C#),/KEYFILE(C++);
??????????????????????????? * 在配件源代碼中使用配件屬性指定密鑰對文件。如在C#源代碼中可以這樣指定:
????????????????? [assembly:AssemblyKeyFile("1.snk")]
3)(4-7)強(qiáng)簽名工具(Al.exe,或相應(yīng).Net語言編譯器)獲取配件內(nèi)容,并請求密碼系統(tǒng)對其進(jìn)行散列,密碼系統(tǒng)對配件內(nèi)容進(jìn)行散列后返回其哈希值;
4)(8-9)強(qiáng)簽名工具從密鑰對文件中摘取私有密鑰(Private Key),向密碼系統(tǒng)申請使用私有密鑰對配件內(nèi)容進(jìn)行非對稱加密,密碼系統(tǒng)隨后返回加密后的結(jié)果,也就是所謂的數(shù)字簽名(Digital Signature);
5)(10-11)簽名工具從密鑰對文件中摘取出公有密鑰(Public Key),連同將獲得的配件的數(shù)字簽名一起存儲在配件的裝配單中(Assembly Manifest);
6)(12-17)強(qiáng)名稱配件使用者引用強(qiáng)名稱配件后,在編譯時(shí),編譯器將從強(qiáng)名稱配件中獲取該強(qiáng)名稱配件的公有密鑰(Public Key),然后請求密碼系統(tǒng)對公有密鑰進(jìn)行散列,隨后把密碼系統(tǒng)返回的哈希值保存在強(qiáng)名稱配件使用者的裝配件中。
#對公有密鑰散列后的哈希值稱之為公有密鑰令牌(Public Key Token)。強(qiáng)名稱配件使用者之所以保存公有密鑰令牌而不是公有密鑰本身是為了節(jié)省自己的存儲空間,因?yàn)榱钆票让荑€本身所需的存儲空間少得多。
延遲簽名(Delay Signing)
從3.1可以看出對配件進(jìn)行簽名同時(shí)需要公有密鑰和私有密鑰。在大型項(xiàng)目中,往往存在大量的分別有不同開發(fā)人員開發(fā)的需要強(qiáng)簽名的配件,這些開發(fā)人員都需要使用私有密鑰。許多人對私有密鑰的使用可能會影響私有密鑰的安全,私有密鑰應(yīng)該掌握在少數(shù)授權(quán)人手中。另外由于開發(fā)過程中配件需要反復(fù)的進(jìn)行編譯、測試、修改,每次都進(jìn)行強(qiáng)簽名是沒有必要的。其實(shí)配件只要在最后發(fā)布前強(qiáng)簽名就可以了。
為此可以使用.Net延遲簽名機(jī)制。配件在開發(fā)過程中,開發(fā)人員只需使用公有密鑰(可以使用Sn.exe從密鑰對中摘取出來)對配件進(jìn)行延遲簽名,這時(shí)3.1的步驟2就有些變化了。強(qiáng)簽名工具不會獲取配件的數(shù)字簽名,而僅把公有密鑰保存在配件的裝配單中,同時(shí)為將來產(chǎn)生的數(shù)字簽名保留存儲空間。
當(dāng)配件開發(fā)完成,在發(fā)布前,再使用Sn.exe等強(qiáng)簽名工具配合私有密鑰對配件強(qiáng)簽名。
這就是所謂的延遲簽名。
強(qiáng)簽名配件驗(yàn)證
經(jīng)過第3節(jié)的強(qiáng)簽名之后,配件中包含了公有密鑰和數(shù)字簽名,這些信息將成為強(qiáng)簽名驗(yàn)證機(jī)制(如.Net CLR驗(yàn)證)識別配件和驗(yàn)證配件內(nèi)容是否被修改的依據(jù)。利用這些信息,同時(shí)結(jié)合強(qiáng)名稱配件使用者所擁有的公共密鑰令牌,.Net CLR可以驗(yàn)證所引用的配件內(nèi)容是否被篡改。其過程如下圖所示:
?
?
?
?
?
?
?
角色、對象:
??????????????? +
????????????????? Consumer of Strong-named Assembly:強(qiáng)名稱配件使用者
??????????????? +
????????????????? Common Language Runtime(CLR):.Net公共語言運(yùn)行時(shí)
??????????????? +
????????????????? Strong-named Assembly:強(qiáng)名稱配件
??????????????? + Cryptography:密碼系統(tǒng)
??????? 過程:
1)(1)強(qiáng)名稱配件使用者引用強(qiáng)名稱配件,向CLR提供配件的強(qiáng)名稱信息,其中包括它所持有的強(qiáng)名稱配件的公有密鑰令牌。CLR根據(jù)提供的信息加載相應(yīng)強(qiáng)名稱配件,加載之前需要對配件進(jìn)行驗(yàn)證;
2)(2-6)驗(yàn)證公共令牌。CLR從強(qiáng)名稱配件中獲取公有密鑰并使用密碼系統(tǒng)對其進(jìn)行散列,然后把散列后的值同強(qiáng)名稱配件使用者提供的公有密鑰令牌相比較,判斷是否相同,如果不同說明至少有一方的公共密鑰相關(guān)數(shù)據(jù)被修改了,驗(yàn)證失敗;
3)(7-15)CLR獲取強(qiáng)名稱配件的內(nèi)容,然后使用密碼系統(tǒng)對配件內(nèi)容進(jìn)行散列,獲得配件散列后的哈希值。同時(shí)CLR請求密碼系統(tǒng)使用存放在強(qiáng)名稱配件的裝配件中的公共密鑰對同樣保存在其中的數(shù)字簽名進(jìn)行解密得到一個(gè)哈希值。最后比較上述兩個(gè)哈希值,如果相同說明強(qiáng)名稱配件完好無損,未被篡改,驗(yàn)證通過,否則驗(yàn)證失敗;
#上述過程中,CLR使用的散列算法應(yīng)該和強(qiáng)名稱工具對強(qiáng)名稱配件公共密鑰散列時(shí)使用的算法一致。實(shí)際上,CLR可以從強(qiáng)名稱配件使用者的裝配件中獲知后者使用的散列算法。
?
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zgh2002007/archive/2009/03/19/4005323.aspx
轉(zhuǎn)載于:https://www.cnblogs.com/jhxk/articles/1612436.html
總結(jié)
- 上一篇: iframe 父窗口和子窗口相互的调用方
- 下一篇: 查看跟踪文件的地址