(點選上方公眾號,可快速關註)
來源:王潔 ,
imaidata.github.io/blog/2017/08/08/java結合keytool實現非對稱加密和解密/
那一篇講簽名,這一篇將加密解密。在Java安全體系中,簽名屬於JAAS模組,加解密屬於JCE模組。
keytool的使用
keytool是JDK自帶的一個金鑰庫管理工具。這裡只用到了keytool的部分功能,包括生成金鑰對,匯出公鑰等。keytool生成的公鑰/私鑰對存放到一個到了一個檔案中,這個檔案有密碼保護,通稱為keystore。
生成金鑰對
$ keytool -genkey -alias signLegal -keystore examplestanstore2 -validity 1800 -keyalg RSA
生成別名為signLegal的金鑰對,存放在金鑰庫examplestanstore2中,證書的有效期是1800天(預設是90天)。
輸入一系列的引數。輸入的引數遵循了LDAP的風格和標準。可以想象,生成的金鑰對可以看成LDAP的一個條目。
命令執行成功後會在當前目錄下建立一個叫examplestanstore2的檔案。相對另一篇博文,增加了一個keyalg引數。因為keytool預設演演算法是DSA,而DSA只能用於簽名。RSA既能用於簽名,也能用於加密。而本文是研究加密問題,只能用RSA演演算法。
檢視金鑰對
$ keytool -list -keystore examplestanstore2 -v
列出了examplestanstore2金鑰庫的中所有金鑰對。-v引數表示詳細資訊,詳細資訊中有證書的失效時間。
匯出公鑰證書
$ keytool -export -keystore examplestanstore2 -alias signLegal -file StanSmith.crt -rfc
匯出的公鑰存放在當前目錄的StanSmith.crt檔案中。講“簽名”的那篇博文沒有加-rfc引數,匯出是個二進位制檔案(CER格式)。加上-rfc後,匯出的是文字檔案(PEM)格式。在下麵的測試中,如果使用CER格式,會報錯 ` No installed provider supports this key: sun.security.provider.DSAPublicKeyImpl`。
Java加密和解密
在Java程式中,首先從金鑰庫取出私鑰和公鑰,然後對測試字串進行加密。二進位制的密文轉換成字串輸出到螢幕,然後解密成明文再輸出到螢幕。
GenSig2.java
import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
import sun.security.provider.*;
public class RSAEntry {
public static void main(String[] args) {
try {
//1.從金鑰庫中取私鑰
KeyStore ks = KeyStore.getInstance(“JKS”);
FileInputStream ksfis = new FileInputStream(“examplestanstore2”);
BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
// open keystore and get private key
// alias is ‘signLeal’, kpasswd/spasswd is ‘vagrant’
ks.load(ksbufin, “vagrant”.toCharArray());
PrivateKey prikey = (PrivateKey) ks.getKey(“signLegal”, “vagrant”.toCharArray());
//2.根據命令列引數取公鑰
FileInputStream certfis = new FileInputStream(args[0]);
java.security.cert.CertificateFactory cf =
java.security.cert.CertificateFactory.getInstance(“X.509”);
java.security.cert.Certificate cert = cf.generateCertificate(certfis);
PublicKey pubKey = cert.getPublicKey();
//3.使用公鑰進行加密
String data = “測試資料”;
//構建加密解密類
Cipher cipher = Cipher.getInstance(“RSA”);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);//設定為加密樣式
byte[] jmdata = cipher.doFinal(data.getBytes());
//列印加密後資料
System.out.println(bytesToHexString(jmdata));
//改為解密樣式進行解密
cipher.init(Cipher.DECRYPT_MODE, prikey);//會用私鑰解密
jmdata = cipher.doFinal(jmdata);
System.out.println(new String(jmdata));
}catch (Exception e) {
e.printStackTrace();
}
}
//這個方法用於把二進位制轉換成ASCII字串。
public static String bytesToHexString(byte[] bytes) {
if (bytes == null)
return “null!”;
int len = bytes.length;
StringBuilder ret = new StringBuilder(2 * len);
for (int i = 0; i < len; ++i) {
int b = 0xF & bytes[(i)] >> 4;
ret.append(“0123456789abcdef”.charAt(b));
b = 0xF & bytes[(i)];
ret.append(“0123456789abcdef”.charAt(b));
}
return ret.toString();
}
}
編譯,並執行
$ javac RSAEntry.java
$ java RSAEntry StanSmith.crt
8fceea48e34fdc786bde05459f3366714b650ff04f4e81e52eca139d8ee0b4acbcad019cd496de3589765894b2d5f4a2af38914af614d9e9b73e551ae01830cd6f49505685d7e527e3adc2b7a2a75608068627c0a12b338d3c743a5de2af2de327a0de14b548604e5c8905747aef077852ecfd2eb4a134ca0f3a56b23db8ae4beb07add5ba3725ab3ee0ffa7481494856144ba5004a329cfe2c43078f0cd95aebcbbfc6c1894efafacac90615e549cb8432c125d912a5e54ce4884f633f3e96bd7b61c1d538e38713716367f7ec6f5ca01288e6d96ad9e3d6515147369144390e1d002b1beaf5797966e3b498cc7def754816c99456ef380b3a83366a44415f6
測試資料
本文展示的演演算法是一種非對稱演演算法,計算較慢。在SSL中,非對稱演演算法用於客戶端和伺服器之間交換對稱加密的一次性金鑰。客戶端將一個隨機數用伺服器的公鑰加密發給伺服器,如果伺服器持有私鑰,就能解開密文獲得隨機數(這個隨機數就是對稱演演算法的金鑰)。有了對稱演演算法金鑰,雙方就可以用對稱加密進行安全通訊了。
參考
-
Java結合keytool實現非對稱簽名與驗證
https://imaidata.github.io/blog/2017/07/29/java結合keytool實現非對稱簽名與驗證/
-
Java-web下使用RSA進行加密解密操作
http://blog.csdn.net/niemingming/article/details/10082975
【關於投稿】
如果大家有原創好文投稿,請直接給公號傳送留言。
① 留言格式:
【投稿】+《 文章標題》+ 文章連結
② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/
③ 最後請附上您的個人簡介哈~
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能