在java程序中建立和读取PKCS#8格式的私钥

本文转载和翻译自:techxperiment.blogspot.com/2016/10/cre…html


在这篇简短的文章中,我将向您展现如何在 java 中以 pkcs8 格式存储私钥,并再次在 java 中读回存储的密钥。java

PKCS#8 定义了用于存储私钥信息的标准语法。咱们能够经过 2 种方式存储 pkcs8 格式的私钥。算法

1)未加密密钥 2)加密密钥dom

我将在 java 中建立两种类型的密钥并将它们存储在文件中。以后我将从文件中读取它们并从存储文件中建立 privatekey java 对象。咱们正在使用充气城堡 API 进行此计划ui

  1. 建立 pkcs8 密钥 代码以建立 pkcs8:
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

让咱们在记事本中打开它们并检查差别。加密密钥文件:翻译

未加密的密钥文件:

您能够看到两个文件的开始和结束标记的区别。

  1. 读取 pkcs8 密钥代码以读取 pkcs8:
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,由于它们是从相同的私钥建立的并存储在文件中。
相关文章
相关标签/搜索