RSA是當(dāng)前最流行的非對稱加密方式,使用公鑰加密使用密鑰解密,如何妥善的保管密鑰就成了關(guān)鍵。
工具類
package com.yitong.utils;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import javax.crypto.Cipher;/** * RSA工具類 */public class RSAUtil { /** * @description: 隨機生成RSA密鑰對(密鑰默認(rèn)長度為1024) * @params: * @return: */ public static KeyPair getRSAKeyPair() { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); return kpg.genKeyPair(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * @description: 隨機生成RSA密鑰對 * @params: * @return: */ public static KeyPair getRSAKeyPair(int length) { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(length); return kpg.genKeyPair(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * @description: 用公鑰加密 * @params: * @return: String */ public static String encryptData(String data, PublicKey publicKey) { try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return HexUtil.encode(cipher.doFinal(data.getBytes())); } catch (Exception e) { e.printStackTrace(); } return null; } /** * @description: 用私鑰解密 * @params: * @return: String */ public static String decryptData(String encryptedData, PrivateKey privateKey) { try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(HexUtil.decode(encryptedData))); } catch (Exception e) { e.printStackTrace(); } return null; } /** * @description: 字符串還原公鑰 * @params: * @return: PublicKey */ public static PublicKey getPublicKey(String key) { try { byte[] keyBytes; keyBytes = Base64Util.decode(key); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = null; keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(keySpec); return publicKey; } catch (Exception e) { e.printStackTrace(); } return null; } /** * @description: 字符串還原公鑰Base64 * @params: * @return: String */ public static String getPublicKey(PublicKey publicKey) { return Base64Util.encode(publicKey.getEncoded()); } /** * @description: 字符串還原私鑰 * @params: * @return: PrivateKey */ public static PrivateKey getPrivateKey(String key) { try { byte[] keyBytes; keyBytes = Base64Util.decode(key); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = null; keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } catch (Exception e) { e.printStackTrace(); } return null; } /** * @description: 字符串還原私鑰Base64 * @params: * @return: String */ public static String getPrivateKey(PrivateKey privateKey) { return Base64Util.encode(privateKey.getEncoded()); }}
使用
static String plainText = "123456789123456789";// 明文 static String cipherText;// 密文 static PublicKey publicKey; static PrivateKey privateKey; private static void RSAEncrypt() { if (null == publicKey) { KeyPair aKey = RSAUtil.getRSAKeyPair(); publicKey = aKey.getPublic(); privateKey = aKey.getPrivate(); String pString = RSAUtil.getPublicKey(publicKey); String pString2 = RSAUtil.getPrivateKey(privateKey); System.out.println("公鑰:" pString "\n私鑰:" pString2); } for (int i = 0; i < 5; i ) { cipherText = RSAUtil.encryptData(plainText, publicKey); System.out.println("加密密文:" cipherText); try { System.out.println("解密明文:" RSAUtil.decryptData(cipherText, privateKey)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
這個是動態(tài)生成一對密鑰的用法,這里存在一個問題,自己生成的一對密鑰別人不知道,除了自己任何人都沒有辦法解密,我們一般都是自己加密給別人解密,這樣就得想辦法把私鑰傳給別人,但存在泄露的風(fēng)險。
這種方式是為了解決傳遞密鑰存在泄露風(fēng)險的問題,keystore擁有完整的一對密鑰,既包含公鑰也包含私鑰,證書只包含公鑰,只能利用證書進行加密。
以win系統(tǒng)為例,打開cmd,輸入:keytool -genkey -alias 你的證書別名 -keyalg 密鑰算法 -keystore 證書庫文件保存的位置和文件名 -keysize 密鑰長度 -validity 證書有效期天數(shù)
示例:keytool -genkey -alias mykey -keyalg RSA -keystore D:/mk.keystore -keysize 1024 -validity 36500
然后按照提示輸入密鑰庫的相關(guān)信息:
輸入密鑰庫口令:再次輸入新口令:您的名字與姓氏是什么? [Unknown]: zhang您的組織單位名稱是什么? [Unknown]: pc您的組織名稱是什么? [Unknown]: pc您所在的城市或區(qū)域名稱是什么? [Unknown]: shanghai您所在的省/市/自治區(qū)名稱是什么? [Unknown]: shanghai該單位的雙字母國家/地區(qū)代碼是什么? [Unknown]: 86CN=zhang, OU=yitong, O=pc, L=shanghai, ST=shanghai, C=86是否正確? [否]: 是輸入 <mykey> 的密鑰口令 (如果和密鑰庫口令相同, 按回車):再次輸入新口令:Warning:JKS 密鑰庫使用專用格式。建議使用 "keytool -importkeystore -srckeystore D:/mk.keystore -destkeystore D:/mk.keystore -deststoretype pkcs12" 遷移到行業(yè)標(biāo)準(zhǔn)格式 PKCS12。
這樣就在D盤根目錄下生成一個密鑰庫,這個密鑰庫相當(dāng)重要一定要妥善保管,接下來就需要生成證書了:
keytool -export -alias mykey -keystore D:/mk.keystore -file D:/mk.cer
這樣就能再D盤根目錄下看到證書文件了,我們可以根據(jù)需要在原有的密鑰庫添加新的密鑰。
直接上代碼:
static String plainText = "123456789123456789";// 明文 static String cipherText;// 密文 static PublicKey publicKey; static PrivateKey privateKey; static String certificatePath = "D:/mk.cer"; static String keystorePath = "D:/mk.keystore"; private static void CerEncrypt() throws Exception { // 加密 CertificateFactory cff = CertificateFactory.getInstance("X.509"); InputStream in = new FileInputStream(certificatePath); Certificate cf = cff.generateCertificate(in); PublicKey pString = cf.getPublicKey(); // 得到證書文件攜帶的公鑰 System.out.println("公鑰:" Base64Util.encode(pString.getEncoded())); cipherText = RSAUtil.encryptData(plainText, pString); System.out.println("加密密文:" cipherText); // 解密 FileInputStream inputStream = new FileInputStream(keystorePath); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(inputStream, "000000".toCharArray()); inputStream.close(); String alias = "mykey"; String pswd = "000000"; Certificate cert = ks.getCertificate(alias); PublicKey publicKey = cert.getPublicKey(); PrivateKey privateKey = (PrivateKey) ks.getKey(alias, pswd.toCharArray()); System.out.println("私鑰:" RSAUtil.getPrivateKey(privateKey) "\n公鑰:" RSAUtil.getPublicKey(publicKey)); System.out.println(RSAUtil.decryptData(cipherText, privateKey)); }
當(dāng)我們的報文需要RSA加密的時候就可以將證書放在客戶端,keystore放在服務(wù)端,這樣客戶端發(fā)送的報文就能自行加密,在服務(wù)端利用keystone文件獲取私鑰進行解密。
來源:https://www.icode9.com/content-4-276251.html