轉自:https://www.jianshu.com/p/a8194c237363
JCA是平台的一個主要部分,包含一個“Provider”體系結構和一組用於數字簽名,消息摘要(哈希),證書和證書驗證,加密(對稱/非對稱塊/流密碼),密鑰生成 管理和安全隨機數生成等等。
JCA包含兩個軟件組件:
- 定義和支持Provider為其提供實現的加密服務的框架。 這個框架包含了諸如java.security,javax.crypto,javax.crypto.spec和javax.crypto.interfaces等軟件包。
- Sun,SunRsaSign,SunJCE等實際包含了實際的加密實現的提供商。
JDK的其他安全庫
JDK中提供的其他密碼通信庫使用JCA提供程序體系結構,但在別處進行了介紹。
- Java安全套接字擴展(JSSE)提供對安全套接字層(SSL)和傳輸層安全性(TLS)實現的訪問。
- Java通用安全服務(JGSS)(通過Kerberos)API以及簡單身份驗證和安全層(SASL)也可用於在通信應用程序之間安全地交換消息。
術語
- JCE(Java Cryptography Extension),在早期JDK版本中,由於受美國的密碼出口條例約束,Java中涉及加解密功能的API被限制出口,所以Java中安全組件被分成了兩部分: 不含加密功能的JCA(Java Cryptography Architecture )和含加密功能的JCE(Java Cryptography Extension)。現在JCE已經捆綁在JDK中,所以,這里JCE是JCA的一部分。
設計原則
- 實現獨立性和互操作性
- 算法獨立性和可擴展性
JCA提供標准化的、算法特定的API來實現上面兩個原則。
- 通過各種引擎類來實現不同的功能,實現算法獨立性(例如MessageDigest,Signature,KeyFactory,KeyPairGenerator和Cipher類)
- 使用Provider(提供者)的體系結構來達到“實現獨立性”,程序可以指定使用特定服務提供者的算法實現。
- 實現互操作性意味着各種實現可以相互協作,使用彼此的密鑰,或者驗證彼此的簽名。 這就意味着,對於相同的算法,由一個提供者生成的密鑰可以被另一個提供者使用,並且由一個提供者生成的簽名可以被另一個提供者驗證。
核心包
JCA相關安全API軟件包:
provider 提供者
provider提供者,這里的全稱是 Cryptographic Service Provider (CSP),是指實現一個或多個密碼服務(如數字簽名算法,消息摘要算法和密鑰轉換服務)的包或一組包。 每個JDK安裝都默認安裝並配置了一個或多個provider包。用戶可以靜態或動態添加其他provider。
JDK中的加密庫出於歷史原因,由幾個不同的提供者實現:
- Sun
- SunJSSE
- SunJCE
- SunRsaSign
java.security.Provider是所有安全提供程序的基類。
有兩者指定Provider的方式:
- 根據默認的優先順序自動獲取提供者

- 指定特定的Provider

Provider實現原理
JCA使用引擎類作為路由來實現Provider的關聯,實現算法獨立性。
- 引擎類:每個引擎類,都有一個對應的抽象SPI類,它定義了每個加密服務提供者算法必須實現的方法。
- SPI(服務提供者接口):每個SPI類的名稱與相應的引擎類相同,接着是Spi。 例如,Signature引擎類提供對數字簽名算法的功能的訪問。 實際的提供者實現是在SignatureSpi的子類中提供的。 應用程序調用引擎類的API方法,在實際的實現中又調用SPI方法。
下面的案例,展示了引擎類的使用,獲取Provider對象實例的過程:
例如
import javax.crypto.*;
Cipher c = Cipher.getInstance("AES");
c.init(ENCRYPT_MODE, key);
- 這里的應用程序需要一個“AES”算法的javax.crypto.Cipher實例,並不關心使用哪個提供者。
- 應用程序調用Cipher引擎類的getInstance()工廠方法,然后請求JCA框架查找支持“AES”的第一個提供程序實例。
- 該框架會咨詢每個已安裝的提供者,並獲取提供者類的提供者實例。框架搜索每個提供者,最終在CSP3中找到合適的條目。
- 這個數據庫入口指向擴展CipherSpi的實現類com.foo.AESCipher,因此適用於Cipher引擎類。創建一個com.foo.AESCipher的實例,並將其封裝在一個新創建的javax.crypto.Cipher實例中,該實例返回給應用程序。
- 當應用程序現在對Cipher實例執行init()操作時,Cipher引擎類將請求路由到com.foo.AESCipher類中相應的engineInit()支持方法中。

- 理解引擎類,SPI(服務提供接口類)、SPI實現類
如上案例,Cipher是一個引擎類,提供加解密的服務。
而實際定義加解密功能的類是CipherSpi。
提供者CSP3的com.foo.AESCipher類是一個SPI實現類,實現了CipherSpi接口。
引擎類
引擎類為特定類型的密碼服務提供接口,而不依賴於特定的密碼算法或提供者。 引擎需要提供:
- 密碼操作(加密,數字簽名,消息摘要等),
- 發生器或密碼材料的轉換器(密鑰和算法參數),或
- 對象(密鑰庫或證書)封裝了密碼數據,可以在更高的抽象層使用。
以下引擎類是可用的:
- SecureRandom:用於生成隨機或偽隨機數字。
- MessageDigest:用於計算指定數據的消息摘要(散列)。
- Signature:使用密鑰初始化,這些簽名用於簽署數據並驗證數字簽
- Cipher:用密鑰初始化,用於加密/解密數據。存在各種類型的算法:對稱批量加密(例如AES),非對稱加密(例如RSA)和基於密碼的加密(例如PBE)。
- Message Authentication Codes(MAC):與MessageDigests一樣,它們也會生成散列值,但是首先使用密鑰初始化以保護消息的完整性。
KeyFactory:用於將Key類型的現有不透明密鑰轉換為密鑰規范(底層密鑰材料的透明表示),反之亦然。
SecretKeyFactory:用於將SecretKey類型的現有不透明加密密鑰轉換為密鑰規范(底層密鑰材料的透明表示),反之亦然。 SecretKeyFactorys是專門的KeyFactorys,只能創建密鑰(對稱)。
KeyPairGenerator:用於生成一對適用於指定算法的公鑰和私鑰。
KeyGenerator:用於生成與指定算法一起使用的新密鑰。
KeyAgreement:由兩方或多方使用,商定和建立一個特定的密鑰,用於特定的密碼操作。
AlgorithmParameters:用於存儲特定算法的參數,包括參數編碼和解碼。
AlgorithmParameterGenerator:用於生成適合於指定算法的一組AlgorithmParameters。
KeyStore:用於創建和管理密鑰庫。密鑰庫是密鑰的數據庫。密鑰庫中的私鑰具有與其關聯的證書鏈,用於驗證相應的公鑰。密鑰庫還包含來自可信實體的證書。
CertificateFactory:用於創建公鑰證書和證書吊銷列表(CRL)。
CertPathBuilder:用於構建證書鏈(也稱為證書路徑)。
CertPathValidator:用於驗證證書鏈。
CertStore:用於從存儲庫中檢索證書和CRL。
注意:生成器可以創建具有全新內容的對象,而工廠只能從現有材料(例如編碼)中創建對象。
1. Provider類
- 指定Provider類
在調用引擎類的getInstance方法來請求和實例化實現實例時,指定想要實現的所需算法的名稱以及可選的Provider(或提供者類)的名稱。 - 安裝Providers
有兩種方式安裝Provider:在classpath的任何位置放置一個包含Provider類的zip或JAR文件;如果將提供程序置於標准擴展目錄中,則該提供程序將被視為已安裝的擴展程序 - 注冊Provider
靜態注冊:在配置文件JAVA_HOME\lib\security\java.security中注冊security.provider.n=masterClassName
動態注冊:調用Security類中的addProvider或insertProviderAt方法。 - Provider類方法
public String getName()
public double getVersion()
public String getInfo()
2. Security類
Security類管理已安裝的提供程序和安全性屬性。 它只包含靜態方法,永遠不會實例化。
提供了一系列API查詢Provider、增加Provider、刪除Provider
Provider[] arr = Security.getProviders();
3. SecureRandom隨機生成器類
SecureRandom類是提供隨機數生成器(RNG)功能的引擎類。 它不同於java.lang.Random類,因為它產生密碼強的隨機數。 如果生成器中的隨機性不足,則會使保護機制變得更加容易。 在密碼學中使用隨機數字,例如生成加密密鑰,算法參數等等。
4. MessageDigest摘要類
MessageDigest類是一個引擎類,用於提供密碼安全的消息摘要(如SHA-256或SHA-512)的功能。 加密安全的消息摘要采用任意大小的輸入(一個字節數組),並生成一個固定大小的輸出,稱為摘要或散列。

5. Signature 簽名類
Signature類是一個引擎類,旨在提供加密數字簽名算法(如DSA或RSAwithMD5)的功能。 密碼安全簽名算法采用任意大小的輸入和私鑰,並生成一個相對較短(通常是固定大小)的字節串,稱為簽名,具有以下屬性:
- 只有私鑰/公鑰對的所有者才能創建簽名。 任何擁有公鑰的人都可以在計算上不可能恢復私鑰
- 鑒於與用於生成簽名的私鑰相對應的公鑰,應該有可能驗證輸入的真實性和完整性。
-
簽名和公鑰沒有透露有關私鑰的任何信息。
圖片.png
6. Cipher 加密解密類
Cipher類提供用於加密和解密的加密密碼的功能。 加密是取數據(稱為明文)和密鑰的過程,並且產生對不知道密鑰的第三方毫無意義的數據(密文)。 解密是相反的過程:取密文和密鑰並產生明文。

7. SealedObject 密封對象類
8. Mac 消息認證碼類
HMAC是基於密碼散列函數的MAC。 HMAC可以與任何密碼散列函數(例如SHA-256)結合秘密共享密鑰一起使用。

9. Key 密鑰接口
秘鑰有兩種表示形式:key(不透明)和keyspecs(透明)。
- 不透明的密鑰接口無法直接訪問密鑰材料字段,只有定義的三種方法:getAlgorithm,getFormat和getEncoded。
- 透明的密鑰,可以以通過相應規范類中定義的某個get方法單獨訪問每個關鍵字值。 例如,DSAPrivateKeySpec定義了getX,getP,getQ和getG方法來訪問私鑰x以及用於計算密鑰的DSA算法參數:素數p,次數q和基數g。 如果密鑰存儲在硬件設備上,其規格可能包含有助於識別設備密鑰的信息。
9.1 Key 不透明秘鑰接口
秘鑰可以通過以下方式獲得:
- KeyGenerator (生成對稱秘鑰)
- KeyPairGenerator(生成非對稱秘鑰)
- Certificate證書
- KeyStore密碼庫
- 轉換KeySpecs(使用KeyFactory)
java.security.Key接口是所有不透明密鑰的頂層接口。
以下是在java.security.interfaces和javax.crypto.interfaces包中擴展Key接口的接口列表:
SecretKey用於對稱秘鑰
PublicKey和PrivateKey接口分別用於非對稱秘鑰的公鑰和私鑰。
KeyPair類是密鑰對(公鑰和私鑰)的簡單持有者。
9.2 KeySpecs 透明秘鑰接口
也叫密鑰規范(密鑰材料)接口
java.security.spec包中的密鑰規范接口和類。
DESKeySpec是一種DES密鑰規范。
X509EncodedKeySpec是一種公鑰編碼規范,它表示公鑰的DER編碼,根據X.509標准中規定的格式。
PKCS8EncodedKeySpec是一種私鑰編碼規范,以PKCS8標准中指定的格式對私鑰進行DER編碼。
KeySpecs實現的子類如下:
10 生成器和工廠類的區別:

10.1 生成器 **Generator
生成器用於生成一個全新的對象(秘鑰)。比如KeyGenerator生成SecretKey,KeyPairGenerator生成KeyPair。
生成器一般有兩種方法來生成密鑰對
- 以獨立於算法的方式
void initialize(int keysize, SecureRandom random)
void initialize(int keysize)
- 以特定於算法的方式
void initialize(AlgorithmParameterSpec params, SecureRandom random)
void initialize(AlgorithmParameterSpec params)
KeyPairGenerator類,用於生成公鑰和私鑰對的引擎類。

KeyGenerator類, 用於為對稱算法生成密鑰。

10.2 工廠類 **Factory
工廠類用於將數據從一個現有的對象類型轉換為另一個。一個密鑰工廠可以用來在兼容的密鑰規范之間進行轉換。
比如SecretKeyFactory和KeyFactory,可以轉換keySpecs為key。比如CertificateFactory,從字節輸入流(FileInputStream)轉換成證書(Certificate)對象。
秘鑰工廠是雙向的,密鑰工廠用於將密鑰(java.security.Key類型的不透明密鑰)轉換為密鑰規范(以合適的格式對基礎密鑰材料進行透明表示),反之亦然。
比如KeyFactory類和SecretKeyFactory類:


11 KeyAgreement 秘鑰協商類
Diffie-Hellman算法是一種密鑰協議,是兩方或多方可以建立相同密碼密鑰而不必交換任何秘密信息的協議。

生成共享密鑰有如下幾步:
- 創建KeyAgreement對象
KeyAgreement.getInstance()
- 初始化KeyAgreement
public void init(Key key);
public void init(Key key, SecureRandom random);
public void init(Key key, AlgorithmParameterSpec params);
public void init(Key key, AlgorithmParameterSpec params, SecureRandom random);
- 執行密鑰協商階段
public Key doPhase(Key key, boolean lastPhase);
- 生成共享密鑰
public byte[] generateSecret();
public int generateSecret(byte[] sharedSecret, int offset);
public SecretKey generateSecret(String algorithm);
12. 密碼庫KeyStore
“密鑰庫”是一種可用於管理密鑰和證書的存儲庫,一個密碼庫包含多個私鑰和證書。
- KeyStore文件:用戶密鑰庫默認存儲在用戶主目錄中名為.keystore的文件中。
- 密碼庫工具:keytool和jarsigner的命令行工具,以及一個名為policytool的基於GUI的工具。
- 密鑰庫實現類型:
默認的keystore實現類型是“jks”,
推薦的keystore實現是“pkcs12”,
可以在java.security文件中的修改默認實現類型:
keystore.type=jks
KeyStore類

密鑰庫中有兩種不同類型的條目:Key Entry(密鑰條目)和Trusted Certificate Entry(可信任的證書條目)
KeyStore對象可以從文件中load()或store()到文件。並提供了一系列方法來操作key條目和Certificate條目。
13. AlgorithmParameters和AlgorithmParameterSpecs
AlgorithmParameters:不透明的加密參數接口
AlgorithmParameterSpecs:透明的加密參數接口
AlgorithmParameters或AlgorithmParameterSpecs用於配置算法的初始化參數
AlgorithmParameterGenerator生成器,是一個引擎類,用於生成一組適用於特定算法的全新參數,提供了生成AlgorithmParameters和AlgorithmParameterSpecs的方法。
14. CertificateFactory類
CertificateFactory類是定義證書工廠功能的引擎類,用於從其編碼(文件流)生成證書和證書吊銷列表(CRL)對象。
15. JCA如何在SSL / TLS實現中使用
- 編寫Provider類的具體實現,並在Security類的提供者列表中注冊
- 使用KeyManager(密鑰庫)和TrustManagerSSLContext(信任度)初始化SSLContext
- 使用上下文SSLContext,創建實際實現SSL / TLS協議的對象(SSLSocket和SSLEngine)。
- SSLSocket和SSLEngine將直接在通信對象中使用。
KeyManager和TrustManager作用:
- JSSE KeyManager負責向對等端顯示使用的憑證(使用的密碼標准、加密算法、證書、公鑰、簽名等)
- JSSE TrustManager負責驗證從對等端收到的憑證,驗證憑證有多種方式:其中之一是創建CertPath對象,並讓JDK的內置公鑰基礎結構(PKI)框架處理驗證。 在內部,CertPath實現可能會創建一個Signature對象,並使用它來驗證證書鏈中的每個簽名。
SSL/TLS握手過程:
客戶端首先發送一個ClientHello消息給服務器。 服務器選擇要使用的密碼組,然后將其發回到ServerHello消息中,並根據套件選擇開始創建JCA對象。 我們將在下面的例子中使用服務器唯一身份驗證。

在第一個示例中,服務器嘗試使用基於RSA的密碼組,例如TLS_RSA_WITH_AES_128_CBC_SHA。 查詢服務器的KeyManager,並返回相應的RSA條目。 服務器的憑證(即:證書/公鑰)將在服務器的證書消息中發送。 客戶端的TrustManager驗證服務器的證書,如果接受,客戶端使用SecureRandom對象生成一些隨機字節。 然后使用已使用在服務器證書中找到的PublicKey初始化的加密非對稱RSA密碼對象對其進行加密。 此加密數據在客戶端密鑰交換消息中發送。 服務器將使用其相應的PrivateKey在解密模式下使用類似的密碼恢復字節。 這些字節然后用於建立實際的加密密鑰。
一旦建立了真實的加密密鑰,秘密密鑰就被用來初始化一個對稱的密碼對象,並且這個密碼被用來保護所有傳輸中的數據。 為了幫助確定數據是否已被修改,創建MessageDigest並接收發往網絡的數據的副本。 當數據包完成時,摘要(哈希)被附加到數據,並且整個數據包被密碼加密。 如果使用諸如AES的分組密碼,則必須填充數據以形成完整的塊。 在另一端,這些步驟簡單地顛倒過來。
作者:jection
鏈接:https://www.jianshu.com/p/a8194c237363
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。