一個項目中先使用了AES對稱加密,之後覺得密鑰、摘要等還是不安全,所以又需要使用非對稱加密RSA,加密密鑰、摘要等信息。
之前沒有接觸過,實際使用過程中遇到的最大疑惑就是:
找了一堆資料,大家都在說明keytool怎麼生成密鑰、導出證書、各個參數是什麼含義》...,keytool 生成的密鑰庫KeyStore中包含密鑰(私鑰/公鑰)、證書。
可惜, 無法通過keytool工具來提取私鑰...
那怎麼獲得私鑰、公鑰?
以Java為例:通過KeyStore類getEntry() 或者getKey()來提取私鑰;通過Certificate類getPublicKey()獲取公鑰
工具/原料
keytool
Eclipse
Keytool生成KeyStore文件
-- 生成密碼倉庫Hearty.store
keytool -genkey -v -alias Hearty -dname "CN=Hearty,OU=HE,O=CUI,L=HAIDIAN,ST=BEIJING,C=CN" -keyalg RSA -keysize 2048 -keypass 5201314 -keystore Hearty.store -storepass 5201314 -validity 10000 -storetype JCEKS
-- 導出證書HRFax.crt
keytool -exportcert -alias Hearty -file Hearty.crt -keystore Hearty.store -storepass 5201314 -rfc -storetype JCEKS
keytool更多使用方法 及 參數說明自行查閱資料(一查一大把)
生成私鑰、公鑰
獲取私鑰:
private static PrivateKey getPrivateKeyFromStore() throws Exception
{
String alias = "Hearty"; // KeyTool中生成KeyStore時設置的alias
String storeType = "JCEKS"; // KeyTool中生成KeyStore時設置的storetype
char[] pw = "5201314".toCharArray(); // KeyTool中生成KeyStore時設置的storepass
String storePath = "E:/key/Hearty.store"; // KeyTool中已生成的KeyStore文件
storeType = null == storeType ? KeyStore.getDefaultType() : storeType;
KeyStore keyStore = KeyStore.getInstance(storeType);
InputStream is = new FileInputStream(storePath);
keyStore.load(is, pw);
// 由密鑰庫獲取密鑰的兩種方式
// KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pw));
// return pkEntry.getPrivateKey();
return (PrivateKey) keyStore.getKey(alias, pw);
}
保存私鑰之文件:
String privatePath = "E:/key/HeartyPri.key"; // 準備導出的私鑰
private static void createKeyFile(Object key, String filePath) throws Exception
{
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(key);
oos.flush();
oos.close();
}
獲取公鑰:
private static PublicKey getPublicKeyFromCrt() throws Exception
{
String crtPath = "E:/key/Hearty.crt"; // KeyTool中已生成的證書文件
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream in = new FileInputStream(crtPath);
Certificate crt = cf.generateCertificate(in);
return crt.getPublicKey();
}
保存公鑰至文件:
String privatePath = "E:/key/HeartyPub.key"; // 準備導出的私鑰
private static void createKeyFile(Object key, String filePath) throws Exception
{
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(key);
oos.flush();
oos.close();
}
測試加密、解密
1、一般公鑰加密、私鑰解密
2、私鑰加密、公鑰解密也是可以的
完整源碼
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
public class KeyStoreHelper
{
public static void main(String[] args) throws Exception
{
String privatePath = "E:/key/HeartyPri.key"; // 準備導出的私鑰
String publicPath = "E:/key/HeartyPub.key"; // 準備導出的公鑰
PrivateKey privateKey = getPrivateKeyFromStore();
createKeyFile(privateKey, privatePath);
PublicKey publicKey = getPublicKeyFromCrt();
createKeyFile(publicKey, publicPath);
test(privateKey, publicKey);
test(publicKey, privateKey);
test(privateKey, privateKey);
test(publicKey, publicKey);
}
private static PrivateKey getPrivateKeyFromStore() throws Exception
{
String alias = "Hearty"; // KeyTool中生成KeyStore時設置的alias
String storeType = "JCEKS"; // KeyTool中生成KeyStore時設置的storetype
char[] pw = "5201314".toCharArray(); // KeyTool中生成KeyStore時設置的storepass
String storePath = "E:/key/Hearty.store"; // KeyTool中已生成的KeyStore文件
storeType = null == storeType ? KeyStore.getDefaultType() : storeType;
KeyStore keyStore = KeyStore.getInstance(storeType);
InputStream is = new FileInputStream(storePath);
keyStore.load(is, pw);
// 由密鑰庫獲取密鑰的兩種方式
// KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pw));
// return pkEntry.getPrivateKey();
return (PrivateKey) keyStore.getKey(alias, pw);
}
private static PublicKey getPublicKeyFromCrt() throws CertificateException, FileNotFoundException
{
String crtPath = "E:/key/Hearty.crt"; // KeyTool中已生成的證書文件
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream in = new FileInputStream(crtPath);
Certificate crt = cf.generateCertificate(in);
PublicKey publicKey = crt.getPublicKey();
return publicKey;
}
private static void test(Key encryptKey, Key decryptKey) throws Exception
{
System.out.println();
String data = encryptKey.getClass().getSimpleName() + "加密" + " ~ " + decryptKey.getClass().getSimpleName() + "解密";
System.out.println("明文 ~ " + data);
byte[] enb = Base64.encode(RSAencrypt(encryptKey, data.getBytes()));
String en = new String(enb);
System.out.println("加密結果 ~ " + new String(enb));
byte[] deb = Base64.decode(en);
byte[] result = RSAdecrypt(decryptKey, deb);
System.out.println("解密結果 ~ " + new String(result));
}
private static byte[] RSAencrypt(Key pk, byte[] data) throws Exception
{
Cipher cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(data.length);
int leavedSize = data.length % blockSize;
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * blockSize > 0)
{
if (data.length - i * blockSize > blockSize)
{
cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
}
else
{
cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
}
i++;
}
return raw;
}
private static byte[] RSAdecrypt(Key pk, byte[] raw) throws Exception
{
Cipher cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, pk);
ByteArrayOutputStream bout = null;
try
{
bout = new ByteArrayOutputStream(64);
int j = 0;
int blockSize = cipher.getBlockSize();
while (raw.length - j * blockSize > 0)
{
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
j++;
}
return bout.toByteArray();
}
catch (Exception e)
{
throw e;
}
finally
{
if (bout != null)
{
try
{
bout.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
private static void createKeyFile(Object key, String filePath) throws Exception
{
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(key);
oos.flush();
oos.close();
}
}
注意事項
代碼格式無法格式化,罪過罪過~~~