您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java.Security框架中的簽名、加密、摘要及證書分別有什么作用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java.Security框架中的簽名、加密、摘要及證書分別有什么作用”吧!
前言
和前端進行數據交互時或者和第三方商家對接時,需要對隱私數據進行加密。單向加密,對稱加密,非對稱加密,其對應的算法也各式各樣。java提供了統一的框架來規范(java.security)安全加密這類API。下面將一一介紹
加密算法概念及分類
秘鑰生成
摘要算法工具-MessageDigest
簽名算法工具-Signature
常用加密工具類-Cipher
Certificate-證書的保存
KeyStore-密鑰證書的實體類
https證書加載
1 加密算法概念及分類
常用的加密算法類型有三種,如下:
單向加密:也就是不可逆的加密,例如MD5,SHA,HMAC
對稱加密:也就是加密方和解密方利用同一個秘鑰對數據進行加密和解密,例如DES,PBE等等
非對稱加密:非對稱加密分為公鑰和秘鑰,二者是非對稱的,例如用私鑰加密的內容需要使用公鑰來解密,使用公鑰加密的內容需要用私鑰來解密,DSA,RSA
2 秘鑰生成
對稱加密密鑰的生成
KeyGenerator用于生成對稱秘鑰(可逆加密),或者一個密碼性秘鑰
支持算法:AES、ARCFOUR、DES、DESede、HmacMD5、HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512、RC2
public static final KeyGenerator getInstance(String algorithm, String provider) public static final KeyGenerator getInstance(String algorithm) public final void init(int keysize) public final void init(int keysize, SecureRandom random) public final void init(SecureRandom random) public final void init(AlgorithmParameterSpec params, SecureRandom random) public final SecretKey generateKey()
示例
public static void main(String[] args) throws Exception { SecretKey secretKey = generatorDesKey(); System.out.println(secretKey); } public static SecretKey generatorDesKey() throws NoSuchAlgorithmException { KeyGenerator keyGen = KeyGenerator.getInstance("DES"); SecureRandom random = new SecureRandom(); random.nextBytes(new byte[128]); keyGen.init(56,random); SecretKey key = keyGen.generateKey(); return key; } ------------輸出結果------------------ com.sun.crypto.provider.DESKey@185c3
非對稱加密秘鑰的生成
KeyPairGenerator用于生成非對稱加密算法的密鑰對KeyPair,KeyPair會包括一個公鑰和私鑰
支持算法:DiffieHellman、DSA、RSA、RSASSA-PSS、EC
//KeyPairGenerator.java public static KeyPairGenerator getInstance(String algorithm) public static KeyPairGenerator getInstance(String algorithm, String provider) public void initialize(int keysize, SecureRandom random) public void initialize(AlgorithmParameterSpec params, SecureRandom random) public final KeyPair genKeyPair() //KeyPair.java public PublicKey getPublic() public PrivateKey getPrivate()
示例
public static void main(String[] args) throws Exception { KeyPair keyPair = generatorRsaKey(); System.out.println(keyPair); } public static KeyPair generatorRsaKey() throws Exception { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); SecureRandom random = new SecureRandom(); random.nextBytes(new byte[516]); keyGen.initialize(516,random); KeyPair keyPair = keyGen.genKeyPair(); System.out.println(keyPair.getPrivate()); System.out.println(keyPair.getPublic()); return keyPair; }
輸出結果
SunRsaSign RSA private CRT key, 516 bits params: null modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673 private exponent: 84346569319697572575234252102165188253262882511583852380907929457860452934243188047935652497010382336410866699832067872276413297543254894848799721123249067 Sun RSA public key, 516 bits params: null modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673 public exponent: 3 java.security.KeyPair@5010be6
密鑰Key和密鑰規格KeySpec的相互轉化
If the key is stored on a hardware device, its specification may contain information that helps identify the key on the device
KeySpec是一個接口,用來組成加密密鑰的密鑰內容的(透明)規范。如果密鑰存儲在硬件設備上,則其規范可以包含有助于標識該設備上的密鑰的信息
?KeySpec具有規范性,所以一般會根據外部參數生成KeySpec,再根據KeySpec生成對應的Key(個人理解,如有高見,請說出你的見解)。SecretKeyFactory、KeyFactory的作用就是轉換Key與KeySpec
SecretKeyFactory:用于對稱加密的密鑰和密鑰規格之間的轉換,配合KeyGenerator使用
支持算法:AES、ARCFOUR、DES、DESede、PBEWithMD5AndDES、PBEWithHmacSHA256AndAES_128、PBKDF2WithHmacSHA256
public static final SecretKeyFactory getInstance(String algorithm) public static final SecretKeyFactory getInstance(String algorithm, String provider) public final SecretKey translateKey(SecretKey key) public final SecretKey generateSecret(KeySpec keySpec) public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)
示例
public static void main(String[] args) throws Exception { SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); byte[] DESKey = "helloWWW".getBytes(StandardCharsets.UTF_8);// 設置密鑰 DESKeySpec keySpec = new DESKeySpec(DESKey);// 設置密鑰參數 SecretKey key = keyFactory.generateSecret(keySpec);// 得到密鑰對象 System.out.println(key); } ------------輸出結果------------------ com.sun.crypto.provider.DESKey@18e49
KeyFactory:用于非對稱加密的密鑰和密鑰規格之間的轉換,配合KeyPairGenerator使用
支持算法:DiffieHellman、DSA、RSA、RSASSA-PSS、EC
//KeyFactory.java public static KeyFactory getInstance(String algorithm) public static KeyFactory getInstance(String algorithm, String provider) public final PublicKey generatePublic(KeySpec keySpec) public final PrivateKey generatePrivate(KeySpec keySpec) public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
示例
public static void main(String[] args) throws Exception { //生成RSA秘鑰對;generatorRsaKey是上面示例提供的函數 KeyPair keyPair = generatorRsaKey(); System.out.println(keyPair); //PublicKey轉KeySpec;KeySpec再轉PublicKey X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyPair.getPublic().getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey pubKey = keyFactory.generatePublic(pubKeySpec); System.out.println(pubKey); //PrivateKey轉KeySpec;KeySpec再轉PrivateKey PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded()); PrivateKey priKey = keyFactory.generatePrivate(priKeySpec); System.out.println(priKey); }
輸出結果
java.security.KeyPair@78e03bb5 Sun RSA public key, 1024 bits params: null modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821 public exponent: 65537 SunRsaSign RSA private CRT key, 1024 bits params: null modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821 private exponent: 67868152791098303572124282937222322055125020915630253288684471666171190487123683962152169691286583419399765605089805755591451063493647416931630849589322449230367252892862038338916192807582203337302166911147185956153147905653905702289234855039234840869874793012808454810161546053566242403672442319692325665473
3 摘要算法-MessageDigest和javax.crypto.Mac(HMAC)
單向加密是不可逆的,MD5、SHA、MAC都是屬于單向加密算法的一種,也稱之為摘要算法
MD5、SHA它們會根據明文用哈希算法計算一個固定長度的摘要(哈希值),然后把明文和摘要發送給接收者,接收者根據同樣的算法計算出摘要,對比兩個摘要是否一樣即可驗證明文的正確性,它的應用場景是:防止篡改和校驗數據
MD5、SHA等算法是開源的,容易被試探出來。有沒有更安全的摘要算法呢?HMAC-帶密鑰(密碼)的hash函數,用一個密鑰和一個明文消息作為輸入,生成一個消息摘要。密鑰一般使用KeyGenerator創建,相當于一個密碼值,其被試探出的概率小
MessageDigest支持的算法:MD2、MD5、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256
javax.crypto.Mac支持的算法:HmacMD5、HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512、PBEWithHmacSHA1
MD5的示例
MessageDigest digest = MessageDigest.getInstance("MD5"); System.out.println(new String(digest.digest("hello world!".getBytes()))); System.out.println(new String(digest.digest("hello world!".getBytes()))); ------------輸出結果------------------ 0???G??w 0???G??w
MAC的示例
public static void main(String[] args) throws Exception { // 初始化HmacMD5摘要算法的密鑰產生器 KeyGenerator generator = KeyGenerator.getInstance("HmacMD5"); // 產生密鑰 SecretKey secretKey = generator.generateKey(); //SecretKeySpec繼承于SecretKey和KeySpec,因此可直接用SecretKeySpec初始化Mac //SecretKey secretKey = new SecretKeySpec("password".getBytes(), "HmacMD5"); Mac mac = Mac.getInstance("HmacMD5"); mac.init(secretKey); //計算摘要 String data = "hello world"; byte[] result1 = mac.doFinal(data.getBytes()); byte[] result2 = mac.doFinal(data.getBytes()); System.out.println(new String(result1).equals(new String(result2))); } ------------輸出結果------------------ true
4 簽名算法工具-Signature
簽名算法其實也是加密算法,它加密后的數據具有唯一標識性,就像一個人的簽名能代表一個人身份。簽名一般是指用非對稱加密算法的私鑰來加密明文的過程,生成的密文可以被持有公鑰的人識別解密,只要你的公鑰是準確對應無誤的,就能保證你解密的數據是來自持有私鑰的一方
如何保證公鑰是正確無誤,沒被篡改的?1:一對一給你,2:獲取公鑰后通過權威機構認證,相關過程可以看下之前寫的一篇文章網絡篇:朋友面試之https認證加密過程[1]
支持算法:NONEwithRSA、MD2withRSA、MD5withRSA、SHA512/224withRSA、SHA512/256withRSA、RSASSA-PSS、NONEwithDSA、SHA512withDSA、NONEwithECDSA、SHA512withECDSA、MD5withRSAandMGF1(太多了,選擇列舉幾個)
Signature.API示例,配合KeyPairGenerator使用
public static void main(String[] args) throws Exception { KeyPair keyPair = generatorRsaKey(); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(keyPair.getPrivate()); //加解密數據 byte[] data = "hello world".getBytes(); //數據簽名 signature.update(data); byte[] digest = signature.sign(); //數據解密加驗證 signature.initVerify(keyPair.getPublic()); signature.update(data); System.out.println("驗證結果:"+signature.verify(digest)); } ------------輸出結果------------------ 驗證結果:true
5 常用加密工具類-Cipher
用于加密/解密數據。支持各種類型的算法:對稱加密(例如AES),非對稱加密(例如RSA)
支持算法:AES、AESWrap、ARCFOUR、Blowfish、DES、DESede、DESedeWrap、ECIES、RSA(太多了,選擇列舉幾個)
示例
public static void main(String[] args) throws Exception { KeyPair keyPair = generatorRsaKey(); Cipher cipher = Cipher.getInstance("RSA"); // 編碼前設定編碼方式及密鑰 cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate()); //加解密數據 byte[] data = "hello world".getBytes(); //數據簽名 byte[] enData = cipher.doFinal(data); //數據解密 cipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic()); byte[] newData = cipher.doFinal(enData); System.out.println("驗證結果:"+new String(newData)); } ------------輸出結果------------------ 驗證結果:hello world
6 Certificate-證書存儲
CertificateFactory:用于創建公鑰證書(Certificate)和證書吊銷列表(CRL)
Certificate及其子類X509Certificate
CertPath和CertPathBuilder:用于構建證書鏈(也稱為證書路徑)
CertPathValidator:用于驗證證書鏈
CRL:證書吊銷列表
CertStore:用于存儲檢索證書和CRL
CertificateFactory和Certificate的示例
示例
//certificateStream是證書的輸入流 public static PublicKey getPublicKeyByCer(InputStream certificateStream) throws Exception{ CertificateFactory certificateFactory = CertificateFactory.getInstance("X509"); Certificate certificate = certificateFactory.generateCertificate(certificateStream); return certificate.getPublicKey(); }
7 KeyStore-密鑰證書的實體類
KeyStore用于存儲私鑰和證書(公鑰在證書Certificate里面)
公鑰:是一個詳細的實體的數字關聯,并有意讓所有想同這個實體發生信任關系的其他實體知道.公共鑰匙用來檢驗簽名;
私鑰:是一些數字,私有和公共鑰匙存在所有用公共鑰匙加密的系統的鑰匙對中.公共鑰匙用來加密數據,私有鑰匙用來計算簽名.公鑰加密的消息只能用私鑰解密,私鑰簽名的消息只能用公鑰檢驗簽名。
示例
public static void main(String[] args) throws Exception { InputStream certificateStream = null; //根據Certificate生成KeyStore CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(null); keyStore.setCertificateEntry("certificate", certificateFactory.generateCertificate(certificateStream)); //加載jks文件,并生成KeyStore KeyStore trustKeyStore = KeyStore.getInstance("jks"); FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks"); trustKeyStore.load(trustKeyStoreFile, "password".toCharArray()); }
8 java.https加載證書的API
KeyManagerFactory、TrustManagerFactory => KeyManager、TrustManager => SSLContext => SSLEngine、SSLSocketFactory、SSLSocket
一般的證書加載過程
用Certificate、KeyStore生成創建KeyManagerFactory和TrustManagerFactory
KeyManagerFactory和TrustManagerFactory用來創建KeyManager和TrustManager
而KeyManager和TrustManager用來初始化SSLContext
然后使用SSLContext,創建實際實現SSL/TLS協議的對象(SSLSocketFactory、SSLSocket或者SSLEngine)
SSLSocket和SSLEngine可以直接在通信對象中使用
KeyManager和TrustManager作用:
KeyManager負責向對等端顯示使用的憑證(使用的密碼標準、加密算法、證書、公鑰、簽名等)
TrustManager負責驗證從對等端收到的憑證,驗證憑證有多種方式:其中之一是創建CertPath對象,并讓JDK的內置公鑰基礎結構(PKI)框架處理驗證。在內部,CertPath實現可能會創建一個Signature對象,并使用它來驗證證書鏈中的每個簽名
示例:生成SSLContext,并使用SSLContext初始化apache-httpClient
public static String postWithSSL(String url, String jsonBody) throws Exception { SSLContext sslContext = getSslContext(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); RequestConfig config = RequestConfig.custom() .setConnectTimeout(3000) .setSocketTimeout(3000) .build(); CloseableHttpClient client = HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .setDefaultRequestConfig(config).build(); HttpPost httpPost = new HttpPost(url); //httpPost.setHeaders(headers); httpPost.setHeader("Content-Type", "application/json; charset=utf-8"); httpPost.setHeader("Accept", "application/json"); httpPost.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8)); HttpResponse response = client.execute(httpPost); HttpEntity responseEntity = response.getEntity(); String result = EntityUtils.toString(responseEntity, "UTF-8"); return result; } //雙向加密 SSLContext private static SSLContext getSslContext() throws Exception { //自身私鑰 KeyStore identityKeyStore = KeyStore.getInstance("jks"); FileInputStream identityKeyStoreFile = new FileInputStream("/root/myServer.jks"); identityKeyStore.load(identityKeyStoreFile, "password1".toCharArray()); //服務端信任證書 KeyStore trustKeyStore = KeyStore.getInstance("jks"); FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks"); trustKeyStore.load(trustKeyStoreFile, "password".toCharArray()); //構建SSLContexts return SSLContexts.custom() .loadKeyMaterial(identityKeyStore, "password1".toCharArray()) // load identity keystore .loadTrustMaterial(trustKeyStore, null) // load trust keystore .build(); } //雙向加密 SSLContext 方式二 private static SSLContext getSslContext2() throws Exception{ //自身私鑰 KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyStore keystore = KeyStore.getInstance("jks"); keystore.load(new FileInputStream(new File("/root/myServer.jks")), "password".toCharArray()); keyFactory.init(keystore, "password".toCharArray()); KeyManager[] keyManagers = keyFactory.getKeyManagers(); //服務端信任證書 TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509"); KeyStore tsStore = KeyStore.getInstance("jks"); tsStore.load(new FileInputStream(new File("/root/trustKeyStore.jks")), "password".toCharArray()); trustFactory.init(tsStore); TrustManager[] trustManagers = trustFactory.getTrustManagers(); //初始化SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, trustManagers, null); return sslContext; }
感謝各位的閱讀,以上就是“Java.Security框架中的簽名、加密、摘要及證書分別有什么作用”的內容了,經過本文的學習后,相信大家對Java.Security框架中的簽名、加密、摘要及證書分別有什么作用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。