JCA簡介
Java平臺強(qiáng)調(diào)安全性,包括語言安全性、密碼學(xué)、公鑰基礎(chǔ)設(shè)施、身份驗(yàn)證、安全通信和訪問控制。
JCA是java平臺的重要部分,它包含了“provider”架構(gòu)和一系列數(shù)字簽名、消息摘要、證書和證書認(rèn)證、加密(對稱/非對稱 流式/分組 加密),秘鑰生成和管理、安全隨機(jī)數(shù)生成API。這些API是的開發(fā)者可以十分簡單的把安全集成到應(yīng)用代碼中。JCA架構(gòu)設(shè)計(jì)上遵循如下準(zhǔn)則:
- 實(shí)現(xiàn)獨(dú)立: 應(yīng)用程序不必自己實(shí)現(xiàn)安全算法,但是它們可以從java平臺獲取安全服務(wù)。安全服務(wù)是在providers (參考Cryptographic Service Providers)中以可插拔的方式實(shí)現(xiàn)的。應(yīng)用程序可能依賴多個(gè)獨(dú)立的providers 來實(shí)現(xiàn)安全功能。
- 實(shí)現(xiàn)互操作性: provider是跨應(yīng)用程序互操作的。具體來說,應(yīng)用程序不綁定到特定的provider,provider也不綁定到特定的應(yīng)用程序。
- 算法可擴(kuò)展性 Java平臺包括許多內(nèi)置的providers,它們實(shí)現(xiàn)了一組基本的安全服務(wù),這些服務(wù)在今天被廣泛使用。然而,有些應(yīng)用程序可能依賴于尚未實(shí)現(xiàn)的新標(biāo)準(zhǔn)或?qū)S蟹?wù)。java平臺支持安裝定制的provider來擴(kuò)展內(nèi)置的providers。
JCA設(shè)計(jì)原則
JCA是圍繞以下原則設(shè)計(jì)的
- 實(shí)現(xiàn)獨(dú)立性和互操作性
- 算法獨(dú)立性和可擴(kuò)展性
實(shí)現(xiàn)獨(dú)立性和算法獨(dú)立性是互補(bǔ)的;您可以使用加密服務(wù),比如數(shù)字簽名和消息摘要,而不用擔(dān)心實(shí)現(xiàn)細(xì)節(jié),甚至不用擔(dān)心構(gòu)成這些概念基礎(chǔ)的算法。雖然不可能完全獨(dú)立于算法,但是JCA提供了標(biāo)準(zhǔn)化的、特定于算法的api。當(dāng)不需要實(shí)現(xiàn)獨(dú)立性時(shí),JCA允許開發(fā)人員指定特定的實(shí)現(xiàn)。
算法獨(dú)立性是通過定義加密“引擎”(服務(wù))類型和定義提供這些加密引擎功能的類來實(shí)現(xiàn)的。這些類稱為引擎類,比如MessageDigest, Signature, KeyFactory, KeyPairGenerator, and Cipher
實(shí)現(xiàn)獨(dú)立性是通過使用基于“provider”的體系結(jié)構(gòu)來實(shí)現(xiàn)的。實(shí)現(xiàn)獨(dú)立性是通過使用基于“提供者”的體系結(jié)構(gòu)來實(shí)現(xiàn)的。加密服務(wù)提供者(CSP)與“provider”是兩個(gè)等價(jià)的術(shù)語,(請參閱加Cryptographic Service Providers
)指實(shí)現(xiàn)一個(gè)或多個(gè)加密服務(wù)的包或一系列包,如數(shù)字簽名算法、消息摘要算法和密鑰轉(zhuǎn)換服務(wù)。程序可以簡單地請求實(shí)現(xiàn)特定服務(wù)(如DSA簽名算法)的特定類型的對象(如簽名對象),并從安裝的providers實(shí)現(xiàn)中選擇一個(gè)。
實(shí)現(xiàn)互操作性意味著各種實(shí)現(xiàn)可以相互協(xié)作、使用彼此的密鑰或驗(yàn)證彼此的簽名。例如,對于相同的算法,一個(gè)provider生成的密鑰可以被另一個(gè)provider使用,一個(gè)provider生成的簽名可以被另一個(gè)provider驗(yàn)證。
算法的可擴(kuò)展性意味著可以很容易地添加適合支持引擎類的新算法。
Provider架構(gòu)
Providers包含一個(gè)包(或一組包),它為公開的加密算法提供具體的實(shí)現(xiàn)。
CSP
java.security.Provider是所有Provider的基類。每個(gè)CSP都包含該類的一個(gè)實(shí)例,該實(shí)例包含provider的名稱,并列出它實(shí)現(xiàn)的所有安全服務(wù)/算法。當(dāng)需要特定算法的實(shí)例時(shí),JCA框架會查詢provider的數(shù)據(jù)庫,如果找到了合適的匹配,就會創(chuàng)建實(shí)例。
Provider包含一個(gè)包(或一組包),它為公開的加密算法提供具體的實(shí)現(xiàn)。JDK在安裝時(shí)會自帶一個(gè)或多個(gè)provider,可以靜態(tài)或動態(tài)添加其他provider??蛻魴C(jī)可以配置其運(yùn)行時(shí)環(huán)境來指定provider優(yōu)先序,當(dāng)沒有指定特定的provider時(shí), provider按照優(yōu)先序返回第一個(gè)搜索到的provider。
要使用JCA,應(yīng)用程序只需請求特定類型的對象(如MessageDigest)和特定的算法或服務(wù)(如“SHA-256”算法),并從安裝的provider之一獲得實(shí)現(xiàn)。例如,以下語句從已安裝的provider請求SHA-256消息摘要:
md = MessageDigest.getInstance("SHA-256");
或者,程序可以指定provider。每個(gè)provider都有一個(gè)用于引用它的名稱。例如,以下語句從名為ProviderC的provider請求SHA-256消息摘要:
md = MessageDigest.getInstance("SHA-256", "ProviderC");
下面的圖說明了請求SHA-256消息摘要實(shí)現(xiàn)。它們顯示了三個(gè)不同的provider,它們實(shí)現(xiàn)了各種消息摘要算法(SHA-256、SHA-384和SHA-512)。provider優(yōu)先序從左到右遞減。在圖2-1中,應(yīng)用程序不指定provider名稱請求SHA-256算法實(shí)現(xiàn),按照優(yōu)先順序搜索provider會返回ProviderB。在圖2-2中,應(yīng)用程序從特定的提供者ProviderC請求SHA-256算法實(shí)現(xiàn)。這一次會返回ProviderC的實(shí)例,即使具有更高優(yōu)先級順序的提供者ProviderB也提供MD5實(shí)現(xiàn)。
圖2-1沒有指定提供程序的請求SHA-256消息摘要實(shí)現(xiàn)

圖2-2使用ProviderC請求SHA-256消息摘要

JDK中的加密實(shí)現(xiàn)是通過幾個(gè)不同的provider(Sun、SunJSSE、SunJCE、SunRsaSign)分發(fā)的,這主要是由于歷史原因,但在較小程度上是由于它們提供的功能類型和算法。其他Java運(yùn)行時(shí)環(huán)境可能不一定包含這些provider,因此應(yīng)用程序不應(yīng)該請求特定于provider的實(shí)現(xiàn),除非知道某個(gè)特定provider是可用的。
JCA提供了一組api,允許用戶查詢安裝了哪些provider以及它們支持哪些服務(wù)。
這種體系結(jié)構(gòu)還使最終用戶可以很容易地添加其他provider。許多第三方provider實(shí)現(xiàn)已經(jīng)可用。有關(guān)provider如何編寫、安裝和注冊的詳細(xì)信息,請參閱Provider 類
provider是如何實(shí)現(xiàn)的
算法獨(dú)立性是通過定義一個(gè)通用的高級應(yīng)用程序編程接口(API)來實(shí)現(xiàn)的,所有應(yīng)用程序都使用這個(gè)API來訪問服務(wù)類型。實(shí)現(xiàn)獨(dú)立性是通過讓所有的provider實(shí)現(xiàn)遵守定義好的接口。比如引擎類,應(yīng)用程序調(diào)用通過engine類路由并傳遞到底層的支持實(shí)現(xiàn)。實(shí)現(xiàn)處理請求并返回正確的結(jié)果。
每個(gè)引擎類中的應(yīng)用程序API方法通過實(shí)現(xiàn)相應(yīng)服務(wù)provider接口(SPI)的類路由到provider的實(shí)現(xiàn)。也就是說,對于每個(gè)引擎類,都有一個(gè)相應(yīng)的抽象SPI類,它定義了每個(gè)加密服務(wù)provider的算法必須實(shí)現(xiàn)的方法。每個(gè)SPI類的名稱與相應(yīng)引擎類的名稱相同,后面跟著SPI。比如, Signature 簽名引擎提供了數(shù)字簽名的功能, 實(shí)際provider 需要實(shí)現(xiàn)的SPI為SignatureSpi,應(yīng)用程序調(diào)用engine類的API方法,后者在實(shí)際實(shí)現(xiàn)中調(diào)用SPI方法。
每個(gè)SPI類都是抽象的。要為特定算法提供特定類型服務(wù)的實(shí)現(xiàn),Provider必須子類化相應(yīng)的SPI類,并為所有抽象方法提供實(shí)現(xiàn)。
對于API中的每個(gè)引擎類,通過調(diào)用引擎類中的getInstance()工廠方法來請求和實(shí)例化實(shí)現(xiàn)實(shí)例。引擎類使用上面描述的框架provider選擇機(jī)制來獲得實(shí)際的支持實(shí)現(xiàn)(SPI),然后創(chuàng)建實(shí)際的引擎對象。engine類的每個(gè)實(shí)例都封裝了相應(yīng)SPI類的實(shí)例(作為私有字段),即SPI對象。API對象的所有API方法都聲明為final,它們的實(shí)現(xiàn)調(diào)用封裝的SPI對象的相應(yīng)SPI方法。
為了更清楚地說明這一點(diǎn),請看示例2-1和圖2-3:
示例2-1 獲取Engine類實(shí)例的示例代碼
import javax.crypto.*;
Cipher c = Cipher.getInstance("AES");
c.init(ENCRYPT_MODE, key);
圖2-3 應(yīng)用程序檢索“AES”密碼實(shí)例

如圖所示應(yīng)用需要一個(gè)javax.crypto.Cipher.AES的實(shí)例而不關(guān)心使用哪一個(gè)provider。應(yīng)用程序調(diào)用Cipher engine類的getInstance()工廠方法,該方法要求JCA框架找到第一個(gè)支持AES的provider實(shí)例??蚣茏稍兠總€(gè)已安裝的provider,并獲得provider類的provider實(shí)例。(回想一下,Provider類是可用算法的數(shù)據(jù)庫。)框架搜索每個(gè)provider,最后在CSP3中找到合適的條目。這個(gè)數(shù)據(jù)庫入口指向擴(kuò)展了CipherSpi的com.foo.AESCipher實(shí)現(xiàn)類,因此適用于Cipher engine。com.foo.AESCipher實(shí)例創(chuàng)建并封裝在新創(chuàng)建的javax.crypto.Cipher實(shí)例中.當(dāng)應(yīng)用程序現(xiàn)在對Cipher實(shí)例執(zhí)行init()操作時(shí),Cipher engine類將請求路由到com.foo.AESCipher中的相應(yīng)engineInit()方法。
Java Security Standard Algorithm Names列出為Java安全環(huán)境定義的標(biāo)準(zhǔn)名稱。其他第三方provider可能會定義自己的這些服務(wù)的實(shí)現(xiàn),甚至是附加服務(wù)。
Keystores(密鑰存儲庫)
所謂keystore是一個(gè)可以用來管理密鑰和證書的數(shù)據(jù)庫。對于需要數(shù)據(jù)進(jìn)行身份驗(yàn)證、加密或簽名的應(yīng)用程序,可以使用密鑰存儲庫
應(yīng)用程序可以使用java.security包中的 KeyStore 的實(shí)現(xiàn)類來訪問一個(gè)秘鑰存儲庫。在JDK 9中,默認(rèn)和推薦的密鑰存儲類型(格式)是“pkcs12”,它基于RSA pkcs12個(gè)人信息交換語法標(biāo)準(zhǔn)。在此之前,默認(rèn)的密鑰存儲類型是“jks”,這是一種專有格式。還可以使用其他密鑰存儲格式,例如“jceks”(另一種專用密鑰存儲格式)和“pkcs11”(基于RSA pkcs11標(biāo)準(zhǔn)),支持訪問加密令牌,如硬件安全模塊和智能卡。
應(yīng)用程序可以從不同的提供者中選擇不同的密鑰存儲實(shí)現(xiàn)。
引擎類和算法
engine類為特定類型的加密服務(wù)提供接口,獨(dú)立于特定的加密算法或provider
引擎提供以下之一:
- 加密操作(加密、數(shù)字簽名、消息摘要等)
- 密碼材料的生成器或轉(zhuǎn)換器(密鑰和算法參數(shù))
- 封裝加密數(shù)據(jù)并可用于更高抽象層的對象(密鑰存儲或證書)
引擎類:
- SecureRandom:用于生成隨機(jī)數(shù)或偽隨機(jī)數(shù)。
- MessageDigest:用于計(jì)算指定數(shù)據(jù)的消息摘要(散列)。
- Signature: 使用密鑰初始化, 用于數(shù)據(jù)簽名和驗(yàn)證數(shù)字簽名
- Cipher: 使用密鑰初始化,用于加解密數(shù)據(jù)。有各種類型的算法: 對稱加密 (e.g. AES), 非對稱加密(e.g. RSA), 和基于密碼的加密(e.g. PBE).
- Message Authentication Codes (MAC): 與MessageDigests一樣,它們也生成哈希值,但首先使用密鑰進(jìn)行初始化,以保護(hù)消息的完整性。
- KeyFactory: 用于將現(xiàn)有的不透明類型密鑰轉(zhuǎn)換為密鑰規(guī)范(底層密鑰材料的透明表示),反之亦然
- SecretKeyFactory:用于將現(xiàn)有的、不透明的、類型為SecretKey的加密密鑰轉(zhuǎn)換為密鑰規(guī)范(底層密鑰材料的透明表示),反之亦然。
- Secretkeyfactory是專門的keyfactory,僅創(chuàng)建私鑰(對稱)。
- KeyPairGenerator: 用于生成適合與指定算法一起使用的公鑰和私鑰對。
- KeyGenerator: 用于生成用于指定算法的私鑰。
- KeyAgreement: 由兩個(gè)或多個(gè)方共同商定并建立一個(gè)特定的密鑰以用于特定的加密操作
- AlgorithmParameters: 用于存儲特定算法的參數(shù),包括參數(shù)編碼和解碼。
- AlgorithmParameterGenerator :用于生成一組適合于指定算法的算法參數(shù)。
- KeyStore: 用于創(chuàng)建和管理密鑰存儲庫。密鑰存儲庫是密鑰的數(shù)據(jù)庫。密鑰存儲庫中的私鑰具有與它們相關(guān)聯(lián)的證書鏈,從而對相應(yīng)的公鑰進(jìn)行身份驗(yàn)證。密鑰存儲庫還包含來自受信任實(shí)體的證書。
CertificateFactory: 用于創(chuàng)建公鑰證書和證書撤銷列表(crls)
CertPathBuilder:用于構(gòu)建證書鏈(也稱為證書路徑)。
CertPathValidator: 用于驗(yàn)證證書鏈。
CertStore:用于從存儲庫中檢索證書和crl
核心類和接口
以下是JCA中提供的核心類和接口。
-
Provider和Security -
SecureRandom,MessageDigest,Signature,Cipher,Mac,KeyFactory,SecretKeyFactory,KeyPairGenerator,KeyGenerator,KeyAgreement,AlgorithmParameter,AlgorithmParameterGenerator,KeyStore,CertificateFactory, 和引擎 -
Key接口,KeyPair -
AlgorithmParameterSpec接口,AlgorithmParameters, -
AlgorithmParameterGenerator, 和在java.security.spec與javax.crypto.spec包中的算法參數(shù)和特定接口類 -
KeySpec接口,EncodedKeySpec,PKCS8EncodedKeySpec, 和X509EncodedKeySpec. -
SecretKeyFactory,KeyFactory,KeyPairGenerator,KeyGenerator,KeyAgreement, 和KeyStore.
本指南將首先介紹最有用的高級類(Provider, Security, SecureRandom, MessageDigest, Signature, Cipher, and Mac),然后深入研究各種支持類?,F(xiàn)在,只需簡單地說鍵(public, private, and secret)是由各種JCA類生成和表示的,高級類將其用作操作的一部分就足夠了。
本節(jié)展示了每個(gè)類和接口中的主要方法,這些類(MessageDigest, Signature, KeyPairGenerator, SecureRandom, KeyFactory, 和key specification classes) 中的一些示例在相應(yīng)的代碼示例部分中提供
有關(guān)安全API包的完整參考文檔可以在包摘要中找到:
java.securityjavax.cryptojava.security.certjava.security.specjavax.crypto.specjava.security.interfacesjavax.crypto.interfaces