本文轉載和翻譯自:techxperiment.blogspot.com/2016/10/cre…html
在這篇簡短的文章中,我將向您展現如何在 java 中以 pkcs8 格式存儲私鑰,並再次在 java 中讀回存儲的密鑰。java
PKCS#8 定義了用於存儲私鑰信息的標準語法。咱們能夠經過 2 種方式存儲 pkcs8 格式的私鑰。算法
1)未加密密鑰 2)加密密鑰dom
我將在 java 中建立兩種類型的密鑰並將它們存儲在文件中。以後我將從文件中讀取它們並從存儲文件中建立 privatekey java 對象。咱們正在使用充氣城堡 API 進行此計劃ui
import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.util.io.pem.PemObject;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
public class App3 {
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, OperatorCreationException, InvalidKeySpecException {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(2048, new SecureRandom());
KeyPair keyPair = kpGen.generateKeyPair();
//unencrypted form of PKCS#8 file
JcaPKCS8Generator gen1 = new JcaPKCS8Generator(keyPair.getPrivate(), null);
PemObject obj1 = gen1.generate();
StringWriter sw1 = new StringWriter();
try (JcaPEMWriter pw = new JcaPEMWriter(sw1)) {
pw.writeObject(obj1);
}
String pkcs8Key1 = sw1.toString();
FileOutputStream fos1 = new FileOutputStream("D:\\privatekey-unencrypted.pkcs8");
fos1.write(pkcs8Key1.getBytes());
fos1.flush();
fos1.close();
//encrypted form of PKCS#8 file
JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.PBE_SHA1_RC2_128);
encryptorBuilder.setRandom(new SecureRandom());
encryptorBuilder.setPasssword("abcde".toCharArray()); // password
OutputEncryptor encryptor = encryptorBuilder.build();
JcaPKCS8Generator gen2 = new JcaPKCS8Generator(keyPair.getPrivate(), encryptor);
PemObject obj2 = gen2.generate();
StringWriter sw2 = new StringWriter();
try (JcaPEMWriter pw = new JcaPEMWriter(sw2)) {
pw.writeObject(obj2);
}
String pkcs8Key2 = sw2.toString();
FileOutputStream fos2 = new FileOutputStream("D:\\privatekey-encrypted.pkcs8");
fos2.write(pkcs8Key2.getBytes());
fos2.flush();
fos2.close();
}
}
複製代碼
所以,您能夠看到,對於未加密的密鑰,咱們不提供任何包含有關算法,密碼等信息的加密器對象。在建立加密密鑰時,咱們會提供詳細信息。加密
做爲此計劃的結果,咱們的文件系統中將包含如下 2 個文件 spa
讓咱們在記事本中打開它們並檢查差別。加密密鑰文件:翻譯
未加密的密鑰文件: 您能夠看到兩個文件的開始和結束標記的區別。import org.bouncycastle.util.encoders.Base64;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
public class App4 {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
String encrypted = new String(Files.readAllBytes(Paths.get("D:\\privatekey-encrypted.pkcs8")));
String unencrypted = new String(Files.readAllBytes(Paths.get("D:\\privatekey-unencrypted.pkcs8")));
//Create object from unencrypted private key
unencrypted = unencrypted.replace("-----BEGIN PRIVATE KEY-----", "");
unencrypted = unencrypted.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decode(unencrypted);
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey unencryptedPrivateKey = kf.generatePrivate(kspec);
//Create object from encrypted private key
encrypted = encrypted.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
encrypted = encrypted.replace("-----END ENCRYPTED PRIVATE KEY-----", "");
EncryptedPrivateKeyInfo pkInfo = new EncryptedPrivateKeyInfo(Base64.decode(encrypted));
PBEKeySpec keySpec = new PBEKeySpec("abcde".toCharArray()); // password
SecretKeyFactory pbeKeyFactory = SecretKeyFactory.getInstance(pkInfo.getAlgName());
PKCS8EncodedKeySpec encodedKeySpec = pkInfo.getKeySpec(pbeKeyFactory.generateSecret(keySpec));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey encryptedPrivateKey = keyFactory.generatePrivate(encodedKeySpec);
//comparing both private key for equality
System.out.println(unencryptedPrivateKey.equals(encryptedPrivateKey));
}
}
複製代碼
輸出:code
因此在這裏你能夠在從文件生成私鑰對象以後咱們將它們進行了相等的比較,而且它們返回 true,由於它們是從相同的私鑰建立的並存儲在文件中。