- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个用 Java 生成的 RSA key 对,我需要以编程方式将私钥写入与运行此命令时 openssl 相同的格式(并根据提示输入相应的数据,即要保护的密码)私钥):
openssl req -out request.csr -newkey rsa:2048 -keyout privkeyfile
生成 key 对的 Java 代码非常标准:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
运行 openssl 命令(在我的 Windows 计算机上)的示例输出是:
-----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 的示例输出
编辑我尝试使用下面的代码使用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 在标准 JCE PrivateKey
上使用 org.bouncycaSTLe.openssl.jcajce.JcaMiscPEMGenerator
和 JcePEMEncryptorBuilder
指定 DES-EDE3-CBC
在内存中创建一个 PEMObject
,然后使用 PEMWriter
将其写出。即使您实际上无法使用 BC,它也是开源的(在我看来,设计得相当好,尽管大多数评论很少),并且它可能会帮助您查看他们的代码。
也就是说,您所询问的内容(几乎)由 PEM_write_RSAPrivateKey
的手册页记录(它应该在您的系统上,但由于您的版本较旧,您最好使用 the web copy ),位于接近结尾处标题为“PEM ENCRYPTION FORMAT”的部分,结合 EVP_BytesToKey
的引用手册页。具体来说:
RSAPrivateKey
from PKCS1 (currently rfc8017) ,而不是PKCS8/rfc5208 PrivateKeyInfo
JCE PrivateKey.getEncoded()
返回的编码。 PKCS8 编码确实包含 PKCS1 编码作为一部分(PKCS8 是围绕任意数量的特定于算法的编码的算法通用包装器),因此您可以从 PKCS8 中提取 PKCS1(如 BC 所做的那样)或直接从关键组件n、e、d、p、q、dmp1、dmq1、qinvp。 (otherPrimeInfos
仅适用于所谓的“多重”RSA,这意味着超过 n 的 2 个因子,而且几乎没有人实际使用。)使用应用于password||salt
的一次MD5迭代从密码中导出实际的加密 key ,其中salt是随机IV的副本(3DES为8字节) )加上(因为这还不够)MD5(firstblock||password||salt)
,然后将总数截断为 24 个字节。
使用 3DES(JCE 称为 DESEDE)和 CBC(使用如上所述的 IV)和 PKCS5 填充进行加密。 (对于 3DES 或 DES, key 的每个字节的低位名义上是奇偶校验,但您不需要设置它们,因为 JCE 没有实现它们。)
转换为 base64,每 64 个字符换行一次,并添加 BEGIN 和 END 行以及标题行,正如您猜对的那样,包括十六进制的 IV
关于java - 如何在Java中将私钥写入受密码保护的DER格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48333877/
我是一名优秀的程序员,十分优秀!