生成强名称程序集
通過嵌入公鑰并使用私鑰簽名,可以生成強名稱(strong name)的程序集。強名稱程序集由4部分進行標識:名稱、版本、區域性和公鑰。與之相對的,我們可以把沒有嵌入公鑰和使用私鑰簽名的程序集稱之為弱名稱(weak name)程序集(這個術語是Jffery Richter創造的)。強名稱程序集與弱名稱程序集相比,有以下特點:
??? * 強名稱程序集可以保證唯一性。公/私密鑰對是由發行者自行生成的,是唯一的,保證了程序集的標識不會重復。
??? * 強名稱程序集可以防篡改。強類型程序集使用私鑰對自己進行了簽名,這樣在被加載時可以檢查程序集是否被修改。
??? * 強名稱程序集可以實施版本策略。對于弱名稱程序集,引用它的程序不會關心它的版本,而對于強類型的程序集來說,引用它的程序會被綁定到特定版本的程序集上,如果使用新版本的強名稱程序集替換舊版本,會導致程序無法運行。(當然還可以使用配置文件對強名稱程序集進行重定向)。
??? * 強名稱程序集可以部署到GAC中。GAC指全局程序集緩存,這是一個公共目錄,放在此處的程序集可以被本機任意一個程序所引用。弱名稱程序集無法部署到此處。不同版本的相同程序集還可以同時存在于GAC中。
??? * 強名稱程序集只能引用強名稱程序集。弱名稱程序集可以引用強名稱程序集,也可以引用弱名稱程序集,但強名稱程序集只能引用強名稱程序集。
??? * 強名稱程序集支持并行執行。并行(side-by-side)執行是指程序同時引用了多個版本的同名程序集,這樣在運行時,會有多個版本的同名程序集被加載和同時執行。通常不建議使用。
下面來研究一下如何生成強名稱的程序集。首先,使用SN.exe創建一個密鑰文件:
sn.exe -k MyKey.snk
生成的文件包含了公鑰和私鑰的內容。我們可以查看公鑰的內容,私鑰是不允許查看的,所以要先將公鑰提取出來。仍然是使用SN.exe:
sn -p MyKey.snk MyPublicKey.snk
sn -tp MyPublicKey.snk
前一個命令將密鑰文件中的公鑰提取出來,放到 MyPublicKey.snk 文件中;后一個命令用于顯示該文件中的公鑰和公鑰標記(Public key token),顯示的內容可能如下(每個人生成的都不同):
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
公鑰標記是公鑰的64位散列值,用于簡化對公鑰的引用。
第二步是創建強名稱程序集。我們可以在源文件中使用AssemblyKeyFileAttribute,但在編譯時會產生警告,建議使用命令行選項來代替此特性。所以此處使用csc.exe:
csc /t:library /keyfile:MyKey.snk MyType.cs
運行后得到 MyType.dll ,我們可以顯示其中包含的公鑰標記,看是否和上面的相同:
sn -Tp MyType.dll
顯示內容如下:
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
由此可見,公鑰的內容確實嵌入到了程序集當中。除此之外,程序集的全部內容經過散列編碼后,還使用密鑰進行了簽名,也嵌入到了程序集中。
這樣我們就得到了一個強名稱程序集。如果有程序引用了該程序集,會記錄由以下內容標識的程序集:
MyType, Version=1.0.3087.28686, Culture=neutral, PublicKeyToken=337642649f453c2c
這些內容唯一的標識了一個強名稱程序集,由于公鑰太長,這里只引用了公鑰標記。當程序運行時,CLR 會根據這些內容去搜尋程序集,只有完全匹配的程序集才會被加載,即便是版本的細微差別都不會忽略。如果沒有找到,或者找到的程序集不匹配,都會產生異常。
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)。
??? 關于區域設置
關于強名稱
強名稱是標識一個配件的方法(當然也可用于標識一個.Net 應用程序, 應用程序配件單或部署配件單)。它具有充分限定(full qualified)的特性, 可以全局唯一標識一個配件。它由以下幾個部分組成:
??????????????? +
????????????????? 簡單的用于描述配件的名稱, 如mscorlib;
??????????????? +
????????????????? 版本號;
??????????????? +
????????????????? 文化信息, 包含關于配件的語言環境信息, 缺省為不確定(neutral);
??????????????? +
????????????????? 公有密鑰 (Public Key);
??????????????? +
????????????????? 數字簽名 (Digital Signature);
公有密鑰和數字簽名用于保證配件內容不會被第三方輕易篡改。關于它們的詳細信息請參考第3節。
強名稱的作用
和以往非托管(Native/Unmanaged)的組件,如COM,普通的DLL,及弱名稱配件僅僅使用簡單的名稱標識自身相比,使用強名稱的配件具有如下的好處:
?
1)可以精確地標識一個配件
使用強名稱能夠精確區分不同的配件,強名稱中的版本信用于識別同一個配件不同的版本,從而避免版本沖突問題,比如DLL地獄(DLL Hell)。
2)防止配件內容被篡改
強名稱對配件的內容采用了相應的簽名機制,配合相應的驗證機制,雖然不能完全避免但可防止配件內容被第三方輕易篡改。
# 其實與傳統的直接被編譯成機器碼的程序不同,.Net 配件是以托管代碼形式保存在PE格式的文件中的,也就是以微軟中間語言代碼(MSIL)形式存在。因此只要對MSIL比較熟悉,第三方就可以很容易地對.Net配件進行篡改,所以為配件使用強名稱是保護配件內容安全的方法之一。
強簽名的實現
強簽名
配件強簽名的過程如下圖所示:
?
?
?
?
角色、對象:
??????????????? +
????????????????? .Net Developer: .Net配件開發者;
??????????????? +
????????????????? Strong name Tool(Sn.exe)/Assembly Linker(Al.exe): 配件強簽名工具
??????????????? +
????????????????? Strong-naming Assembly:強名稱配件
??????????????? +
????????????????? Cryptography:密碼系統
??????????????? + Consumer of Strong-named Assembly:強名稱配件使用者
過程:
1)(1-2)配件開發者使用相應的工具如Sn.exe產生用于非對稱加解密的密鑰對,其包含了一個公有密鑰和一個私有密鑰。Sn.exe將創建并把密鑰對保存到指定的文件中;
2)(3)配件開發者以保存密鑰對的文件作為參數向配件連接器Al.exe請求對配件進行強簽名,下面是一個例子:
al /out:Anor.dll Anor.module /keyfile:1.snk
?
# 除了使用配件連接器之外,我們也可以通過以下方式請求編譯器對配件進行強簽名:
??????????????????????????? *
????????????????????????????? 使用編譯器選項 如、/keyfie (C#),/KEYFILE(C++);
??????????????????????????? * 在配件源代碼中使用配件屬性指定密鑰對文件。如在C#源代碼中可以這樣指定:
????????????????? [assembly:AssemblyKeyFile("1.snk")]
3)(4-7)強簽名工具(Al.exe,或相應.Net語言編譯器)獲取配件內容,并請求密碼系統對其進行散列,密碼系統對配件內容進行散列后返回其哈希值;
4)(8-9)強簽名工具從密鑰對文件中摘取私有密鑰(Private Key),向密碼系統申請使用私有密鑰對配件內容進行非對稱加密,密碼系統隨后返回加密后的結果,也就是所謂的數字簽名(Digital Signature);
5)(10-11)簽名工具從密鑰對文件中摘取出公有密鑰(Public Key),連同將獲得的配件的數字簽名一起存儲在配件的裝配單中(Assembly Manifest);
6)(12-17)強名稱配件使用者引用強名稱配件后,在編譯時,編譯器將從強名稱配件中獲取該強名稱配件的公有密鑰(Public Key),然后請求密碼系統對公有密鑰進行散列,隨后把密碼系統返回的哈希值保存在強名稱配件使用者的裝配件中。
#對公有密鑰散列后的哈希值稱之為公有密鑰令牌(Public Key Token)。強名稱配件使用者之所以保存公有密鑰令牌而不是公有密鑰本身是為了節省自己的存儲空間,因為令牌比密鑰本身所需的存儲空間少得多。
延遲簽名(Delay Signing)
從3.1可以看出對配件進行簽名同時需要公有密鑰和私有密鑰。在大型項目中,往往存在大量的分別有不同開發人員開發的需要強簽名的配件,這些開發人員都需要使用私有密鑰。許多人對私有密鑰的使用可能會影響私有密鑰的安全,私有密鑰應該掌握在少數授權人手中。另外由于開發過程中配件需要反復的進行編譯、測試、修改,每次都進行強簽名是沒有必要的。其實配件只要在最后發布前強簽名就可以了。
為此可以使用.Net延遲簽名機制。配件在開發過程中,開發人員只需使用公有密鑰(可以使用Sn.exe從密鑰對中摘取出來)對配件進行延遲簽名,這時3.1的步驟2就有些變化了。強簽名工具不會獲取配件的數字簽名,而僅把公有密鑰保存在配件的裝配單中,同時為將來產生的數字簽名保留存儲空間。
當配件開發完成,在發布前,再使用Sn.exe等強簽名工具配合私有密鑰對配件強簽名。
這就是所謂的延遲簽名。
強簽名配件驗證
經過第3節的強簽名之后,配件中包含了公有密鑰和數字簽名,這些信息將成為強簽名驗證機制(如.Net CLR驗證)識別配件和驗證配件內容是否被修改的依據。利用這些信息,同時結合強名稱配件使用者所擁有的公共密鑰令牌,.Net CLR可以驗證所引用的配件內容是否被篡改。其過程如下圖所示:
?
?
?
?
?
?
?
角色、對象:
??????????????? +
????????????????? Consumer of Strong-named Assembly:強名稱配件使用者
??????????????? +
????????????????? Common Language Runtime(CLR):.Net公共語言運行時
??????????????? +
????????????????? Strong-named Assembly:強名稱配件
??????????????? + Cryptography:密碼系統
??????? 過程:
1)(1)強名稱配件使用者引用強名稱配件,向CLR提供配件的強名稱信息,其中包括它所持有的強名稱配件的公有密鑰令牌。CLR根據提供的信息加載相應強名稱配件,加載之前需要對配件進行驗證;
2)(2-6)驗證公共令牌。CLR從強名稱配件中獲取公有密鑰并使用密碼系統對其進行散列,然后把散列后的值同強名稱配件使用者提供的公有密鑰令牌相比較,判斷是否相同,如果不同說明至少有一方的公共密鑰相關數據被修改了,驗證失敗;
3)(7-15)CLR獲取強名稱配件的內容,然后使用密碼系統對配件內容進行散列,獲得配件散列后的哈希值。同時CLR請求密碼系統使用存放在強名稱配件的裝配件中的公共密鑰對同樣保存在其中的數字簽名進行解密得到一個哈希值。最后比較上述兩個哈希值,如果相同說明強名稱配件完好無損,未被篡改,驗證通過,否則驗證失敗;
#上述過程中,CLR使用的散列算法應該和強名稱工具對強名稱配件公共密鑰散列時使用的算法一致。實際上,CLR可以從強名稱配件使用者的裝配件中獲知后者使用的散列算法。
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zgh2002007/archive/2009/03/19/4005323.aspx
轉載于:https://www.cnblogs.com/jhxk/articles/1612436.html
總結
- 上一篇: iframe 父窗口和子窗口相互的调用方
- 下一篇: 查看跟踪文件的地址