數字簽名與數字證書技術簡介 .

數字簽名、數字證書等技術,是現代信息安全的核心技術,可謂使用面十分廣泛。其基本理論本身並不複雜,本文希望通過深入淺出的介紹,能夠讓大家有一些基本瞭解。

 

對稱加密、非對稱加密

讓我們通過一個例子開始:我們的主角分別是Alice和Bob。現在假設Alice要給Bob發送一份文件,文件內容非常機密。Alice不希望文件在發送的過程中被人截取而泄密。

這個時候,自然想到的方法就是對文件進行加密。當然除了加密外,我們還需要讓Bob能夠解密。就像Alice對文件上了鎖,爲了讓Bob能夠解開,則Bob必須有鑰匙來對文件解鎖。在信息安全或密碼學中,我們將這種鑰匙稱爲密鑰。密鑰一般分爲兩種,對稱密鑰非對稱密鑰

 

對稱密鑰很容易理解,如同Alice用一把鑰匙將文件上鎖,而Bob使用相同的鑰匙就可以將文件解鎖,即加密使用的密鑰與解密使用的密鑰是相同的。目前的對稱密鑰算法有DES3DESAES等,而密鑰則一般是一串固定長度的字符。

如下,BobAlice事先已經約定,將使用DES算法,並且已經約定好使用的密鑰。於是Alice使用這份密鑰對文件進行了加密,併發送給BobBob使用相同的密鑰對文件解密即可:


 

 

 


 

對稱密鑰算法的安全性還是非常有保障的。拿DES算法舉例,到目前爲止,除了用窮舉搜索法對DES算法進行攻擊外,還沒有發現更有效的辦法。而56位長的密鑰的窮舉空間爲256,這意味着如果一臺計算機的速度是每一秒鐘檢測一百萬個密鑰,則它搜索完全部密鑰就需要將近2285年的時間。而3DES(3次DES操作)、AES算法安全性則更高。由此可見,使用對稱密鑰對文件進行了加密,基本上不用太擔心文件可能泄密。

 

目前大部分的開發語言都有對應的數字加密模塊,例如JAVA的JCE模塊就可以調用簡單的實現加解密。以下是一份JAVA代碼例子:


 

 

  1. package com.test.chiper;  
  2.   
  3. import javax.crypto.Cipher;  
  4. import javax.crypto.spec.SecretKeySpec;  
  5.   
  6. import sun.misc.BASE64Decoder;  
  7. import sun.misc.BASE64Encoder;  
  8.   
  9. public class TestChiper {  
  10.     private static final BASE64Encoder base64En = new sun.misc.BASE64Encoder();  
  11.     private static final BASE64Decoder base64De = new sun.misc.BASE64Decoder();  
  12.     private static String AESKey="1234567890123456";  
  13.       
  14.     public static String encrypt(String mText) throws Exception {  
  15.         SecretKeySpec secrekeysp = new SecretKeySpec(  
  16.                 AESKey.getBytes(),"AES");  
  17.         java.security.Key key = (java.security.Key) secrekeysp;  
  18.         Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");  
  19.         cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key);  
  20.         byte[] b = cipher.doFinal(mText.getBytes());  
  21.         return base64En.encode(b);  
  22.     }  
  23.     public static String decrypt(String mText) throws Exception {  
  24.         SecretKeySpec secrekeysp = new SecretKeySpec(  
  25.                 AESKey.getBytes(),"AES");  
  26.         java.security.Key key = (java.security.Key) secrekeysp;  
  27.         Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");  
  28.         cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key);  
  29.         byte[] b = cipher.doFinal(base64De.decodeBuffer(mText));  
  30.         return new String(b);  
  31.     }  
  32.   }  
package com.test.chiper;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class TestChiper {
	private static final BASE64Encoder base64En = new sun.misc.BASE64Encoder();
	private static final BASE64Decoder base64De = new sun.misc.BASE64Decoder();
	private static String AESKey="1234567890123456";
	
	public static String encrypt(String mText) throws Exception {
		SecretKeySpec secrekeysp = new SecretKeySpec(
				AESKey.getBytes(),"AES");
		java.security.Key key = (java.security.Key) secrekeysp;
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key);
		byte[] b = cipher.doFinal(mText.getBytes());
		return base64En.encode(b);
	}
	public static String decrypt(String mText) throws Exception {
		SecretKeySpec secrekeysp = new SecretKeySpec(
				AESKey.getBytes(),"AES");
		java.security.Key key = (java.security.Key) secrekeysp;
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key);
		byte[] b = cipher.doFinal(base64De.decodeBuffer(mText));
		return new String(b);
	}
  }


 

 

前文提到的對稱密鑰算法,已經基本滿足了Alice對於文件機密性的要求。然而還是存在兩個問題:

1、AliceBob彼此之間必須約定將使用的密鑰,而這個約定的過程本身就可能存在泄密的風險;

2、如果除了Alice以外,還有JessicaEvaMary100位女士也需要向Bob發送文件。那麼,Bob可能需要有100次約定密鑰的過程。

由此可見,無論是安全性還是可用性上,對稱密鑰都是存在問題的。而兩個問題則是必須解決的。

 

1976年,美國斯坦福大學的研究生Diffie和教授Hellman發表一個基於非對稱密鑰加密的想法,這個想法開創了密碼學的變革。他們的想法其實非常簡單,將密鑰分爲公鑰(publicKey私鑰(privateKey兩種。公鑰加密的內容,使用私鑰可以解開;而私鑰加密的內容,公鑰可以解開。然而,單獨的知道公鑰或私鑰,卻沒有辦法推出另一份密鑰。

 

繼續我們的例子:仍然是Alice需要與Bob發送一份絕密文件。在此之前,Bob生成了一對密鑰:公鑰和私鑰。Bob將公鑰發佈在了一個公共的密鑰庫中,而私鑰則不對外公開,僅Bob本人持有。如下圖所示,Alice從公鑰庫中取出Bob的公鑰,對文件進行加密,再發送給Bob。而Bob通過自己持有的私鑰,即可將文件解密:

 


 

通過非對稱密鑰,Bob只是將公鑰公佈,並沒有和Alice約定密鑰。僅僅知道公鑰是沒有辦法推出私鑰的,因此不用擔心私鑰泄密的問題。另一反面,如果有jessica也想向Bob發送文件,僅需要從公鑰庫中取到Bob的公鑰即可,也不需要更多的密鑰。

 

非對稱密鑰算法很有效的解決了安全性和可用性的問題,非對稱密鑰算法又稱作“公開密鑰加密算法”,我們常說的PKIPublic Key Infrastructure)則是建立在此技術之上的安全基礎體系。目前使用最爲廣泛的非對稱密鑰爲RSA算法,該算法是由三位算法發明者的姓氏開頭字母命名而來。

由於非對稱加密算法的複雜度更高,因此非對稱加密的速度遠沒有對稱加密算法快,甚至可能比對稱加密慢上1000倍。

 

信息摘要、數字簽名

基於上文的非對稱密鑰算法,我們可以繼續我們的場景:

假設有一天,Alice收到了一份署名爲Bob的文件。Alice希望能夠確認這份文件一定是來自Bob;另外Alice希望能夠確信,這份文件在傳輸過程中並沒有被它人篡改。那麼基於非對稱密鑰算法我們應該怎麼做?

確認文件一定來自於Bob,其實就是Bob無法否認自己發送過這份文件。信息安全中稱作不可抵賴性;另一方面,確信文件並沒有中途被篡改,則稱作不可篡改性

在非對稱密鑰算法中提到,公鑰加密的內容使用私鑰可以解密。同樣的,基於私鑰加密的內容使用公鑰也可以解密,兩者一一對應。因此我們可以很容易想到。如果Bob利用自己手裏的私鑰對文件進行加密後,傳輸給AliceAlice再通過公鑰庫中Bob的公鑰進行解密,則可以證明文件一定是由Bob發出(由於只有Bob持有私鑰)。另外,因爲傳輸的是密文,如果能夠使用公鑰解密,同時也證明了文件並沒有中途被篡改。這樣的做法其實已經同時滿足了不可抵賴性和不可篡改性。

然而,由於傳輸的文件可能很大,爲了證明文件的不可抵賴性和不可篡改性,需要對整個文件進行加密,由於非對稱算法效率較低,這樣做的代價太大。因此常規的做法是用到信息摘要數字簽名的方式。

所謂信息摘要,其實就是某種HASH算法。將信息明文轉化爲固定長度的字符,它具有如下特點:

無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的

 

用相同的摘要算法對相同的消息求兩次摘要,其結果必然相同;

 

一般地,只要輸入的消息不同,對其進行摘要以後產生的摘要消息也幾乎不可能相同;

 

消息摘要函數是單向函數,即只能進行正向的信息摘要,而無法從摘要中恢復出任何的消息

 

好的摘要算法,沒有人能從中找到碰撞,雖然碰撞是肯定存在的。即對於給定的一個摘要,不可能找到一條信息使其摘要正好是給定的。或者說,無法找到兩條消息,是它們的摘要相同。

 

一般的,我們將信息的摘要也稱作信息的指紋。如同指紋的含義,相同的信息一定會得相同的指紋,而僅通過指紋又無法還原出原始信息。目前主要的摘要算法有MD5SHA1

 

當有了信息摘要技術以後,基於BobAlice發送文件的場景,我們可以進行如下的操作:

 


 

第一步:

① Bob將原始的信息進行一次信息摘要算法,得到原始信息的摘要值;

 

② Bob使用自己的私鑰,對該摘要值進行加密。得到信息摘要的密文;

 

③ Bob將原始文件和摘要值的密文一起發送給Alice

 

④ 一般的,我們將原始文件和摘要密文稱作Bob對原始文件的簽名結果。

 


 

第二步:

① 當Alice接收到Bob傳輸的信息(原始文件,信息摘要密文)後,使用Bob的公鑰將摘要密文解密,得到信息摘要明文;

 

② 使用信息摘要算法,取原文的摘要信息,獲取原始文件摘要信息;

 

③ Alice比較解密後的摘要信息和取得的摘要信息。如果相同,則可以證明文件一定由Bob發送,並且中途並沒有經過任何篡改。一般將這個過程稱作驗籤。

 

所謂數字簽名,就是對原始文件的“指紋”進行了私鑰加密。這樣,即可保證文件的特徵(摘要值)一定經過了私鑰的加密。同時由於信息摘要的長度普遍不長(MD5128位,SHA1主要爲256位),也並沒有帶來太大的開銷。

如同對稱密鑰算法,在大部分開發語言中,基於非對稱算法的數字簽名,數字加密算法。也都進行了一定的封裝。如下鏈接就比較詳細的描述了基於JCE如何實現數字簽名、加密、驗證等:

http://blog.csdn.net/centralperk/article/details/8538697

 

 

數字證書

 

基於非對稱密鑰算法,Bob生成了一對公私鑰。Bob將公鑰發佈在公開的密鑰庫中。而Alice在向Bob發送加密文件或者驗證Bob簽名的文件時,均要從公鑰庫取到Bob的公鑰。我們已經知道,一般來說公鑰就是一段固定長度的字符串,並沒有特定的含義。

爲了讓Alice能夠方便的辨別公鑰,我們可以考慮對給公鑰附加一些信息,例如該公鑰使用的算法,該公鑰的所有者(主題),該公鑰的有效期等一系列屬性。這樣的數據結構我們稱作PKCS10數據包

 

公鑰的主題我們採用唯一標示符(或稱DN-distinguished name),以儘量唯一的標示公鑰所有者。以下是基於抽象語法表示法所定義的PKCS10數據結構:

  1. CertificationRequestInfo ::= SEQUENCE {    
  2.         version          INTEGER { v1(0) } (v1,...),   
  3.         subject          Name,    
  4.         subjectPKInfo  SubjectPublicKeyInfo{{ PKInfoAlgorithms }},    
  5.         attributes       [0] Attributes{{ CRIAttributes }}    
  6.         }    
  7.     SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE {    
  8.         algorithm     AlgorithmIdentifier {{IOSet}},   
  9.         subjectPublicKey  BIT STRING    
  10.         }    
  11.   
  12.     PKInfoAlgorithms ALGORITHM ::= {     
  13.         ...  -- add any locally defined algorithms here -- }    
  14.       
  15.     Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}     
  16.       
  17.     CRIAttributes  ATTRIBUTE  ::= {    
  18.         ... -- add any locally defined attributes here -- }    
  19.   
  20.     Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {    
  21.         type    ATTRIBUTE.&id({IOSet}),    
  22.         values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})   
  23.     }   
CertificationRequestInfo ::= SEQUENCE {  
		version          INTEGER { v1(0) } (v1,...), 
		subject          Name,  
		subjectPKInfo  SubjectPublicKeyInfo{{ PKInfoAlgorithms }},  
		attributes       [0] Attributes{{ CRIAttributes }}  
		}  
	SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE {  
		algorithm     AlgorithmIdentifier {{IOSet}}, 
		subjectPublicKey  BIT STRING  
		}  

	PKInfoAlgorithms ALGORITHM ::= {   
		...  -- add any locally defined algorithms here -- }  
	
	Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}   
	
	CRIAttributes  ATTRIBUTE  ::= {  
		... -- add any locally defined attributes here -- }  

	Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {  
		type    ATTRIBUTE.&id({IOSet}),  
		values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) 
	} 

我們已經有了PKCS10數據包,除了公鑰信息外,還有公鑰的持有者,公鑰的版本號等信息。然而這樣的數據結構其實並沒有任何權威性。例如有一天一個叫做Richard的人想冒充Bob,也生成一對公私鑰,並且使用了相同的公鑰主題封裝爲P10數據結構。Alice其實並沒有辦法分辨哪個是真實Bob的公鑰。

爲了解決這個問題,就需要一個權威的第三方機構,對P10結構的數據進行認證。就如同對P10文件蓋上一個權威的章,防止仿照。這樣的權威機構,我們稱作CA(Certificate Authority)數字證書認證中心。而CA如何爲P10數據蓋章呢?非常簡單,就是我們前文已經提到的數字簽名技術:


 

① 如上圖所示,CA機構其實也持有一張私鑰。一般來說,CA會對這份私鑰進行特別的保護,嚴禁泄漏和盜用。

② Bob將自己的公鑰附加上一系列信息後,形成了P10數據包(請求包),併發送給CA

③ CA機構通過其他一些手段,例如查看Bob的身份信息等方式,認可了Bob的身份。於是使用自己的私鑰對P10請求進行簽名。(也可能會先對數據進行一些簡單修改,如修改有效期或主題等)

④ 這樣的簽名結果,我們就稱作數字證書。

 

數字證書同樣遵循一個格式標準,我們稱作X509標準,我們一般提到的X509證書就是如此。以下是X509的格式:

 

  1. [Certificate ::= SEQUENCE {  
  2.     tbsCertificate TBSCertificate,  
  3.     signatureAlgorithm AlgorithmIdentifier,  
  4.     signature BIT STRING  
  5. }  
  6.   
  7. TBSCertificate ::= SEQUENCE {  
  8.     version [0] EXPLICIT Version DEFAULT v1,  
  9.     serialNumber CertificateSerialNumber,  
  10.     signature AlgorithmIdentifier,  
  11.     issuer Name,  
  12.     validity Validity,  
  13.     subject Name,  
  14.     subjectPublicKeyInfo SubjectPublicKeyInfo,  
  15.     issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,  
  16.     -- If present, version must be v2or v3  
  17.     subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,  
  18.     -- If present, version must be v2or v3  
  19.     extensions [3] EXPLICIT Extensions OPTIONAL  
  20.     -- If present, version must be v3  
  21.     }  
  22. Version ::= INTEGER {  
  23.     v1(0), v2(1), v3(2)  
  24. }  
  25.   
  26. CertificateSerialNumber ::= INTEGER  
  27.     Validity ::= SEQUENCE {  
  28.     notBefore CertificateValidityDate,  
  29.     notAfter CertificateValidityDate  
  30. }  
  31.   
  32. CertificateValidityDate ::= CHOICE {  
  33.     utcTime UTCTime,  
  34.     generalTime GeneralizedTime  
  35. }  
  36.   
  37. UniqueIdentifier ::= BIT STRING  
  38.     SubjectPublicKeyInfo ::= SEQUENCE {  
  39.     algorithm AlgorithmIdentifier,  
  40.     subjectPublicKey BIT STRING  
  41. }  
  42.   
  43. Extensions ::= SEQUENCE OF Extension  
  44. Extension ::= SEQUENCE {  
  45.     extnID OBJECT IDENTIFIER,  
  46.     critical BOOLEAN DEFAULT FALSE,  
  47.     extnValue OCTET STRING  
  48. }  
[Certificate ::= SEQUENCE {
	tbsCertificate TBSCertificate,
	signatureAlgorithm AlgorithmIdentifier,
	signature BIT STRING
}

TBSCertificate ::= SEQUENCE {
	version [0] EXPLICIT Version DEFAULT v1,
	serialNumber CertificateSerialNumber,
	signature AlgorithmIdentifier,
	issuer Name,
	validity Validity,
	subject Name,
	subjectPublicKeyInfo SubjectPublicKeyInfo,
	issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
	-- If present, version must be v2or v3
	subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
	-- If present, version must be v2or v3
	extensions [3] EXPLICIT Extensions OPTIONAL
	-- If present, version must be v3
	}
Version ::= INTEGER {
	v1(0), v2(1), v3(2)
}

CertificateSerialNumber ::= INTEGER
	Validity ::= SEQUENCE {
	notBefore CertificateValidityDate,
	notAfter CertificateValidityDate
}

CertificateValidityDate ::= CHOICE {
	utcTime UTCTime,
	generalTime GeneralizedTime
}

UniqueIdentifier ::= BIT STRING
	SubjectPublicKeyInfo ::= SEQUENCE {
	algorithm AlgorithmIdentifier,
	subjectPublicKey BIT STRING
}

Extensions ::= SEQUENCE OF Extension
Extension ::= SEQUENCE {
	extnID OBJECT IDENTIFIER,
	critical BOOLEAN DEFAULT FALSE,
	extnValue OCTET STRING
}

 

基於數字證書,我們可以再來看看Bob如何給Alice發送一份不可否認、不可篡改的文件:


 

第一步:Bob除了對文件進行簽名操作外,同時附加了自己的數字證書。一同發給Alice

 


 

第二步:Alice首先使用CA的公鑰,對證書進行驗證。如果驗證成功,提取證書中的公鑰,對Bob發來的文件進行驗籤。如果驗證成功,則證明文件的不可否認和不可篡改。

 

 

可以看到,基於數字證書後,Alice不在需要一個公鑰庫維護Bob(或其他人)的公鑰證書,只要持有CA的公鑰即可。數字證書在電子商務,電子認證等方面使用非常廣泛,就如同計算機世界的身份證,可以證明企業、個人、網站等實體的身份。同時基於數字證書,加密算法的技術也可以支持一些安全交互協議(如SSL)。下一篇文章,將爲大家介紹SSL協議的原理。

 








 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章