如何在 Java 中将私钥写入受密码保护的 DER 格式?
How to write private key to password protected DER format in Java?
我有一个在 Java 中生成的 RSA 密钥对,我需要以编程方式将私钥写入 运行 此命令时 openssl 执行的相同格式(并输入适当的提示数据,即保护私钥的密码:
openssl req -out request.csr -newkey rsa:2048 -keyout privkeyfile
生成密钥对的Java代码非常标准:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
openssl 命令(在我的 Windows 机器上)的 运行ning 示例输出是:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI1c9lGdEA388CAggA
MBQGCCqGSIb3DQMHBAgKdWZEOyS2XgSCBMgI7b/vAeE6yz136BZkOzOPLv0uTz/Z
5mP4xO8IdAybE+PHJ71Mro4kgz+EMN39dk0ZWxbNnPpHGD+a6LfNKxos8fJL+dbz
dgc7I4fH9UQFLnYM64Xmq4aG66fIehuhqXBUUru+PJdBf5bfPDJDYAVEUsZ2J8bW
n4pLeS62Orwe+hhe/i/Y4gmgGAxGhUlDGc7T/N4RvhWUVNXQKGCGynj9Mv+LRzW6
rkGbBALQAKnj2tuihGSKhhR3WoNxTFqU9HsRGkzbJ5AiYhyBk7ObQw285TyIQS6k
OH25byIeaqzQ3Xn/wB6VrOQrsCvbWim1DZEIGRp6B+RKd0vUrkxFZRBsLdGXN1w/
bCM4dmhUJng2O+a9tSif7CC0emJqXgvkE2lGA9RMZltfOK+Kohi4L0WKxIX8TQqP
KzDhecSOaOkdXI0Tpho1QZDS6D+nvN2OiXlswgB0By3pkLdx4j7ZtjhqH/cg4rlE
8R1HzcilIrSlMK579UNGieis2wHaWobeinJqP6ruHK3HiAvG/WLFQ4TKexFa4/gy
EdXPaV9owRi+9nyRZGT8NsfzUDg5oTBLcg08uOlNHr8z8pF6a7l2sr4bzgcYFlko
BCIunMJpXYp/lUnL9daElbOPbGgeLNa8KfU7tXnzYsCg3iUx79fQUoql2pn2wMc3
0vQVTZ7/Enzl8cM2srl0uf1JMxMGOJ2kbdYZ8VwxaaMHnghN97eBsp+aRFCuAN4x
+D90ABBxRcBwzBOf8sT77vYXvQZNqUnzl5GJh2hlXCB5upNFqbSGaa6Yk+y4cw5e
3tB3/BHwZop2AAnPexnnQuCsn+SpCiLF+/agMouph61oWWJYQMwmUemNy/5G6AoP
KdBGqBAXonRSk8pBNqglHl0GOiBITl45+Bk4JBGM6+NcEpQ8B3OA+Vkj0n/aF/Iw
66Fo+UyA64fboC3q6DLxHZuTAY/giytwUW2QM4yFkEOm1v1WisTf0MO3Zt+ghuBn
8DG9MXGxP0XA9QzHAjCcDD8DK/hXsxaBg6xOV4bV+HhhJXsyWQAqcqKQro9Ik3L9
YvdJNU9BWyzKV79j5gYkDgLZgcA8QrGDArFZ5Hr9HdepBu8Njk09YDKJsfVMmk4E
6NbzxqHgPyYY3QtANLKg3EImBfuRHwfgfbaamrmYE0fSyh/QJMK0zDtDpkgiiTre
A8b16rBdBxZBSaO/J+Oje0pePLBRRhwX4WxcPsZeN5fO6S2NTECrWsf0jDG4D6pa
cannasXB4LoBifAYhKKTXFbQRY74wOxVfI7gw0qEjB7Jb1M2zCMwddgumOiCzGpu
d9voABJdGMdhwZ/FLbuxcr0y3p8Y5N9vW8ffSlxEtvhbPlszpgTPi2WWTNE+wTUQ
so4cvWFq9SP3Mg6Te6AStjdN1Mnhj2fb7ogxa5rsNxVrE/guRVgly4i9vG7Mi2Wd
bhT1vQypyL9g97nq0rRznDAjAtLenOagK4h+WJgZN2RpUhkWmO1trLGao/PrhgvD
8mOMCnZIQGMk5vS55druRoakPjsx4yZpzZvw5gPBXJ0H1KmbFUO1aSy/6N4nVBW+
Khr+ZHxboPD0zxJMzANjuOIJ/C46Hx5Wb/VP49NDmOLzLAi3+YSAhi3PB9D8vzxQ
MwM=
-----END ENCRYPTED PRIVATE KEY-----
编辑 更改了 openssl
的示例输出
EDIT 我试着用 Java 读取 openssl 生成的私钥文件,使用下面的代码尝试获取一些参数,但我最终得到了以下异常:
Exception in thread "main" java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48)
at sun.security.util.ObjectIdentifier.<init>(Unknown Source)
at sun.security.util.DerInputStream.getOID(Unknown Source)
at com.sun.crypto.provider.PBES2Parameters.engineInit(PBES2Parameters.java:267)
at java.security.AlgorithmParameters.init(Unknown Source)
at sun.security.x509.AlgorithmId.decodeParams(Unknown Source)
at sun.security.x509.AlgorithmId.<init>(Unknown Source)
at sun.security.x509.AlgorithmId.parse(Unknown Source)
at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:95)
at crypto.ReadOpensslKey.main(ReadOpensslKey.java:35)
Java 读取文件的代码:
package crypto;
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 ReadOpensslKey {
public static void main(String[] args) throws Exception {
String encrypted = new String(Files.readAllBytes(Paths.get("<insert path to openssl generated privkeyfile>")));
//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)); // exception is thrown here
System.out.println(pkInfo.getAlgName());
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);
}
}
首先,您真的需要这种特定格式,还是只需要一种 OpenSSL 格式(以及使用 OpenSSL 的程序,如 Apache httpd、nginx、curl 和 PHP 等等)可以使用?如果是后者,还有其他几个更容易和更好的选择。不过你没问,我就不回答了。
其次,您必须有一个非常古老的 OpenSSL。自 2010 年发布 1.0.0 以来,req -newkey -keyout
编写 PKCS8 格式,而不是传统格式。
第三,这个格式是PEM不是DER;有传统的 DER 格式,但不能加密。 (PKCS8 可以用 DER 或 PEM 加密。)
第四,如果你会用BouncyCastle,它可以直接这样做;从(任何最新版本的)bcpkix 在您的 standard-JCE PrivateKey
上使用 org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator
和指定 DES-EDE3-CBC
的 JcePEMEncryptorBuilder
在内存中创建一个 PEMObject
,然后 PEMWriter
写出来。
即使您实际上不能使用 BC,它也是开源的(并且在 IMO 中设计得很好,尽管大多数评论很少)并且它可能会帮助您查看他们的代码。
那些说,PEM_write_RSAPrivateKey
的手册页(应该在您的系统上,但由于您的版本较旧,您最好使用 the web copy)的手册页(几乎没有)记录在案标题为 'PEM ENCRYPTION FORMAT' 的部分接近尾声,结合 EVP_BytesToKey
的参考手册页。具体来说:
- 构造'traditional'编码,即JCE
PrivateKey.getEncoded()
返回的RSAPrivateKey
from PKCS1 (currently rfc8017), not the PKCS8/rfc5208 PrivateKeyInfo
编码。 PKCS8 编码确实包括 PKCS1 编码作为一部分(PKCS8 是 algorithm-generic 对任意数量 algorithm-specific 编码的包装)因此您可以从 PKCS8 中提取 PKCS1(如 BC 所做的那样)或构造PKCS1直接来自关键组件n,e,d,p,q,dmp1,dmq1,qinvp。 (otherPrimeInfos
仅适用于 so-called 'multiprime' RSA,这意味着 n 的因子超过 2 个,几乎没有人实际使用。)
使用应用于 password||salt
的一次(!)次 MD5 迭代从密码中导出实际加密密钥,其中盐是随机 IV 的副本(3DES 为 8 字节)加上(因为这还不够)MD5(firstblock||password||salt)
然后将总数截断为 24 个字节。
使用 3DES(JCE 称为 DESEDE)和 CBC(如上所述使用 IV)和 PKCS5 填充进行加密。 (对于3DES或DES,密钥的每个字节的低位名义上是奇偶校验,但你不需要设置它们,因为JCE没有实现它们。)
转换为 base64,每 64 个字符换行一次,并添加 BEGIN 和 END 行以及 header 行,如您所猜,包括十六进制的 IV
我最终使用以下代码让它工作:
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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.OutputEncryptor;
import org.bouncycastle.util.io.pem.PemObject;
public class WriteOpensslKey {
public static void main(String[] args) throws Exception {
// provider is needed for the encryptor builder
Security.addProvider(new BouncyCastleProvider());
// generate key pair
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(2048, new SecureRandom());
KeyPair keyPair = kpGen.generateKeyPair();
// construct encryptor builder to encrypt the private key
JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.AES_256_CBC);
encryptorBuilder.setRandom(new SecureRandom());
encryptorBuilder.setPasssword("password".toCharArray());
OutputEncryptor encryptor = encryptorBuilder.build();
// construct object to create the PKCS8 object from the private key and encryptor
JcaPKCS8Generator pkcsGenerator = new JcaPKCS8Generator(keyPair.getPrivate(), encryptor);
PemObject pemObj = pkcsGenerator.generate();
StringWriter stringWriter = new StringWriter();
try (JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
pemWriter.writeObject(pemObj);
}
// write PKCS8 to file
String pkcs8Key = stringWriter.toString();
FileOutputStream fos = new FileOutputStream("<path to output file>");
fos.write(pkcs8Key.getBytes(StandardCharsets.UTF_8));
fos.flush();
fos.close();
}
}
然后我可以使用这个私钥和 openssl 来签署一个文件作为一个快速测试它是否有效。
非常感谢@dave_thompson_085 为我指明了正确的方向!
我有一个在 Java 中生成的 RSA 密钥对,我需要以编程方式将私钥写入 运行 此命令时 openssl 执行的相同格式(并输入适当的提示数据,即保护私钥的密码:
openssl req -out request.csr -newkey rsa:2048 -keyout privkeyfile
生成密钥对的Java代码非常标准:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
openssl 命令(在我的 Windows 机器上)的 运行ning 示例输出是:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI1c9lGdEA388CAggA
MBQGCCqGSIb3DQMHBAgKdWZEOyS2XgSCBMgI7b/vAeE6yz136BZkOzOPLv0uTz/Z
5mP4xO8IdAybE+PHJ71Mro4kgz+EMN39dk0ZWxbNnPpHGD+a6LfNKxos8fJL+dbz
dgc7I4fH9UQFLnYM64Xmq4aG66fIehuhqXBUUru+PJdBf5bfPDJDYAVEUsZ2J8bW
n4pLeS62Orwe+hhe/i/Y4gmgGAxGhUlDGc7T/N4RvhWUVNXQKGCGynj9Mv+LRzW6
rkGbBALQAKnj2tuihGSKhhR3WoNxTFqU9HsRGkzbJ5AiYhyBk7ObQw285TyIQS6k
OH25byIeaqzQ3Xn/wB6VrOQrsCvbWim1DZEIGRp6B+RKd0vUrkxFZRBsLdGXN1w/
bCM4dmhUJng2O+a9tSif7CC0emJqXgvkE2lGA9RMZltfOK+Kohi4L0WKxIX8TQqP
KzDhecSOaOkdXI0Tpho1QZDS6D+nvN2OiXlswgB0By3pkLdx4j7ZtjhqH/cg4rlE
8R1HzcilIrSlMK579UNGieis2wHaWobeinJqP6ruHK3HiAvG/WLFQ4TKexFa4/gy
EdXPaV9owRi+9nyRZGT8NsfzUDg5oTBLcg08uOlNHr8z8pF6a7l2sr4bzgcYFlko
BCIunMJpXYp/lUnL9daElbOPbGgeLNa8KfU7tXnzYsCg3iUx79fQUoql2pn2wMc3
0vQVTZ7/Enzl8cM2srl0uf1JMxMGOJ2kbdYZ8VwxaaMHnghN97eBsp+aRFCuAN4x
+D90ABBxRcBwzBOf8sT77vYXvQZNqUnzl5GJh2hlXCB5upNFqbSGaa6Yk+y4cw5e
3tB3/BHwZop2AAnPexnnQuCsn+SpCiLF+/agMouph61oWWJYQMwmUemNy/5G6AoP
KdBGqBAXonRSk8pBNqglHl0GOiBITl45+Bk4JBGM6+NcEpQ8B3OA+Vkj0n/aF/Iw
66Fo+UyA64fboC3q6DLxHZuTAY/giytwUW2QM4yFkEOm1v1WisTf0MO3Zt+ghuBn
8DG9MXGxP0XA9QzHAjCcDD8DK/hXsxaBg6xOV4bV+HhhJXsyWQAqcqKQro9Ik3L9
YvdJNU9BWyzKV79j5gYkDgLZgcA8QrGDArFZ5Hr9HdepBu8Njk09YDKJsfVMmk4E
6NbzxqHgPyYY3QtANLKg3EImBfuRHwfgfbaamrmYE0fSyh/QJMK0zDtDpkgiiTre
A8b16rBdBxZBSaO/J+Oje0pePLBRRhwX4WxcPsZeN5fO6S2NTECrWsf0jDG4D6pa
cannasXB4LoBifAYhKKTXFbQRY74wOxVfI7gw0qEjB7Jb1M2zCMwddgumOiCzGpu
d9voABJdGMdhwZ/FLbuxcr0y3p8Y5N9vW8ffSlxEtvhbPlszpgTPi2WWTNE+wTUQ
so4cvWFq9SP3Mg6Te6AStjdN1Mnhj2fb7ogxa5rsNxVrE/guRVgly4i9vG7Mi2Wd
bhT1vQypyL9g97nq0rRznDAjAtLenOagK4h+WJgZN2RpUhkWmO1trLGao/PrhgvD
8mOMCnZIQGMk5vS55druRoakPjsx4yZpzZvw5gPBXJ0H1KmbFUO1aSy/6N4nVBW+
Khr+ZHxboPD0zxJMzANjuOIJ/C46Hx5Wb/VP49NDmOLzLAi3+YSAhi3PB9D8vzxQ
MwM=
-----END ENCRYPTED PRIVATE KEY-----
编辑 更改了 openssl
的示例输出EDIT 我试着用 Java 读取 openssl 生成的私钥文件,使用下面的代码尝试获取一些参数,但我最终得到了以下异常:
Exception in thread "main" java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48)
at sun.security.util.ObjectIdentifier.<init>(Unknown Source)
at sun.security.util.DerInputStream.getOID(Unknown Source)
at com.sun.crypto.provider.PBES2Parameters.engineInit(PBES2Parameters.java:267)
at java.security.AlgorithmParameters.init(Unknown Source)
at sun.security.x509.AlgorithmId.decodeParams(Unknown Source)
at sun.security.x509.AlgorithmId.<init>(Unknown Source)
at sun.security.x509.AlgorithmId.parse(Unknown Source)
at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:95)
at crypto.ReadOpensslKey.main(ReadOpensslKey.java:35)
Java 读取文件的代码:
package crypto;
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 ReadOpensslKey {
public static void main(String[] args) throws Exception {
String encrypted = new String(Files.readAllBytes(Paths.get("<insert path to openssl generated privkeyfile>")));
//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)); // exception is thrown here
System.out.println(pkInfo.getAlgName());
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);
}
}
首先,您真的需要这种特定格式,还是只需要一种 OpenSSL 格式(以及使用 OpenSSL 的程序,如 Apache httpd、nginx、curl 和 PHP 等等)可以使用?如果是后者,还有其他几个更容易和更好的选择。不过你没问,我就不回答了。
其次,您必须有一个非常古老的 OpenSSL。自 2010 年发布 1.0.0 以来,req -newkey -keyout
编写 PKCS8 格式,而不是传统格式。
第三,这个格式是PEM不是DER;有传统的 DER 格式,但不能加密。 (PKCS8 可以用 DER 或 PEM 加密。)
第四,如果你会用BouncyCastle,它可以直接这样做;从(任何最新版本的)bcpkix 在您的 standard-JCE PrivateKey
上使用 org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator
和指定 DES-EDE3-CBC
的 JcePEMEncryptorBuilder
在内存中创建一个 PEMObject
,然后 PEMWriter
写出来。
即使您实际上不能使用 BC,它也是开源的(并且在 IMO 中设计得很好,尽管大多数评论很少)并且它可能会帮助您查看他们的代码。
那些说,PEM_write_RSAPrivateKey
的手册页(应该在您的系统上,但由于您的版本较旧,您最好使用 the web copy)的手册页(几乎没有)记录在案标题为 'PEM ENCRYPTION FORMAT' 的部分接近尾声,结合 EVP_BytesToKey
的参考手册页。具体来说:
- 构造'traditional'编码,即JCE
PrivateKey.getEncoded()
返回的RSAPrivateKey
from PKCS1 (currently rfc8017), not the PKCS8/rfc5208PrivateKeyInfo
编码。 PKCS8 编码确实包括 PKCS1 编码作为一部分(PKCS8 是 algorithm-generic 对任意数量 algorithm-specific 编码的包装)因此您可以从 PKCS8 中提取 PKCS1(如 BC 所做的那样)或构造PKCS1直接来自关键组件n,e,d,p,q,dmp1,dmq1,qinvp。 (otherPrimeInfos
仅适用于 so-called 'multiprime' RSA,这意味着 n 的因子超过 2 个,几乎没有人实际使用。)
使用应用于
password||salt
的一次(!)次 MD5 迭代从密码中导出实际加密密钥,其中盐是随机 IV 的副本(3DES 为 8 字节)加上(因为这还不够)MD5(firstblock||password||salt)
然后将总数截断为 24 个字节。使用 3DES(JCE 称为 DESEDE)和 CBC(如上所述使用 IV)和 PKCS5 填充进行加密。 (对于3DES或DES,密钥的每个字节的低位名义上是奇偶校验,但你不需要设置它们,因为JCE没有实现它们。)
转换为 base64,每 64 个字符换行一次,并添加 BEGIN 和 END 行以及 header 行,如您所猜,包括十六进制的 IV
我最终使用以下代码让它工作:
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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.OutputEncryptor;
import org.bouncycastle.util.io.pem.PemObject;
public class WriteOpensslKey {
public static void main(String[] args) throws Exception {
// provider is needed for the encryptor builder
Security.addProvider(new BouncyCastleProvider());
// generate key pair
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(2048, new SecureRandom());
KeyPair keyPair = kpGen.generateKeyPair();
// construct encryptor builder to encrypt the private key
JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.AES_256_CBC);
encryptorBuilder.setRandom(new SecureRandom());
encryptorBuilder.setPasssword("password".toCharArray());
OutputEncryptor encryptor = encryptorBuilder.build();
// construct object to create the PKCS8 object from the private key and encryptor
JcaPKCS8Generator pkcsGenerator = new JcaPKCS8Generator(keyPair.getPrivate(), encryptor);
PemObject pemObj = pkcsGenerator.generate();
StringWriter stringWriter = new StringWriter();
try (JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
pemWriter.writeObject(pemObj);
}
// write PKCS8 to file
String pkcs8Key = stringWriter.toString();
FileOutputStream fos = new FileOutputStream("<path to output file>");
fos.write(pkcs8Key.getBytes(StandardCharsets.UTF_8));
fos.flush();
fos.close();
}
}
然后我可以使用这个私钥和 openssl 来签署一个文件作为一个快速测试它是否有效。
非常感谢@dave_thompson_085 为我指明了正确的方向!