如何使用私钥加密创建 PKCS12 密钥库 PBEWithHmacSHA512AndAES_128
How to create a PKCS12 keystore with privatekey encryption PBEWithHmacSHA512AndAES_128
我需要在 Scala/Java 中构建一个 PKCS-12 文件,并且我希望使用基于 AES 的私钥加密(例如 PBEWithHmacSHA512AndAES_128)
我使用这个代码(取自here)
val outputStream = new FileOutputStream(file)
val salt = new Array[Byte](20)
new SecureRandom().nextBytes(salt)
val kspkcs12 = KeyStore.getInstance("PKCS12")
kspkcs12.load(null, null)
kspkcs12.setEntry("test", new KeyStore.PrivateKeyEntry(keys.getPrivate, Array(cert)),
new KeyStore.PasswordProtection("changeMe".toCharArray, "PBEWithHmacSHA512AndAES_128", new PBEParameterSpec(salt,
100000)))
kspkcs12.store(outputStream, "changeMe".toArray)
现在,当用
检查结果时
openssl pkcs12 -info -in filename.p12 -noout
我得到:
MAC:sha1 Iteration 100000 PKCS7 Data Shrouded Keybag:
PBES2<unsupported parameters> PKCS7 Encrypted data:
pbeWithSHA1And40BitRC2-CBC, Iteration 50000 Certificate bag'
为什么我得到的是 "PKCS7 Encrypted data" 而不是 PKCS12?
我从
了解到
"PBES2<unsupported parameters>"
消息提供者不支持所请求的算法。有 PKCS12 供应商吗?
Why am I getting a "PKCS7 Encrypted data" instead of PKCS12?
PKCS 是一堆规范,即每个更高级别的规范重新使用较低级别的规范。
对于 PKCS#12,我们至少遇到:
- PKCS#12(密钥库格式)
- PKCS#7(signed/encrypted 消息)
- PKCS#5 (PBKDF2)
- PKCS#9(消息摘要)
- PKCS#8(密钥对格式)
所以您在输出中看到与 PKCS#7 相关的消息是正常的。
I understand from the "PBES2<unsupported parameters>
" that the provider does not support the requested algorithm.
是的,这是 Java 中的错误。内置 JCE 提供程序在输出流中错误地对 PBES2 标记进行了两次编码:
public void derEncode (OutputStream out) throws IOException {
DerOutputStream bytes = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
bytes.putOID(algid); // <<< Writes 1.2.840.113549.1.5.13
并且在 PBES2Parameters.engineGetEncoded()
中一次:
protected byte[] engineGetEncoded() throws IOException {
DerOutputStream out = new DerOutputStream();
DerOutputStream pBES2Algorithms = new DerOutputStream();
pBES2Algorithms.putOID(pkcs5PBES2_OID); // <<< Writes 1.2.840.113549.1.5.13 again
这是它生成的内容(我使用的是 HMAC SHA256 和 AES256):
$ openssl asn1parse -inform der -strparse 973 < test.p12
0:d=0 hl=4 l=1441 cons: SEQUENCE
4:d=1 hl=4 l=1437 cons: SEQUENCE
8:d=2 hl=2 l= 11 prim: OBJECT :pkcs8ShroudedKeyBag
21:d=2 hl=4 l=1358 cons: cont [ 0 ]
25:d=3 hl=4 l=1354 cons: SEQUENCE
29:d=4 hl=2 l= 116 cons: SEQUENCE
31:d=5 hl=2 l= 9 prim: OBJECT :PBES2
42:d=5 hl=2 l= 103 cons: SEQUENCE
44:d=6 hl=2 l= 9 prim: OBJECT :PBES2 <<<<< PBES2 tag encoded twice!!
55:d=6 hl=2 l= 90 cons: SEQUENCE
57:d=7 hl=2 l= 57 cons: SEQUENCE
59:d=8 hl=2 l= 9 prim: OBJECT :PBKDF2
70:d=8 hl=2 l= 44 cons: SEQUENCE
72:d=9 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:9F642532C15BBF1E566AA6429DA450EFBF0FF265
94:d=9 hl=2 l= 3 prim: INTEGER :0186A0
99:d=9 hl=2 l= 1 prim: INTEGER :20
102:d=9 hl=2 l= 12 cons: SEQUENCE
104:d=10 hl=2 l= 8 prim: OBJECT :hmacWithSHA256
114:d=10 hl=2 l= 0 prim: NULL
116:d=7 hl=2 l= 29 cons: SEQUENCE
118:d=8 hl=2 l= 9 prim: OBJECT :aes-256-cbc
129:d=8 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:DF2D490C6BA58A19EDAF8D22E2A2CFA0
147:d=4 hl=4 l=1232 prim: OCTET STRING [HEX DUMP]:22343E6418F8C60857D9A5CC089D...
它应该是这样的(openssl pkcs12 -encode
的输出):
$ openssl asn1parse -inform der -strparse 1003 < test.p12
0:d=0 hl=4 l=1414 cons: SEQUENCE
4:d=1 hl=4 l=1410 cons: SEQUENCE
8:d=2 hl=2 l= 11 prim: OBJECT :pkcs8ShroudedKeyBag
21:d=2 hl=4 l=1329 cons: cont [ 0 ]
25:d=3 hl=4 l=1325 cons: SEQUENCE
29:d=4 hl=2 l= 87 cons: SEQUENCE
31:d=5 hl=2 l= 9 prim: OBJECT :PBES2
42:d=5 hl=2 l= 74 cons: SEQUENCE
44:d=6 hl=2 l= 41 cons: SEQUENCE
46:d=7 hl=2 l= 9 prim: OBJECT :PBKDF2
57:d=7 hl=2 l= 28 cons: SEQUENCE
59:d=8 hl=2 l= 8 prim: OCTET STRING [HEX DUMP]:6FA108004C54EAC4
69:d=8 hl=2 l= 2 prim: INTEGER :0800
73:d=8 hl=2 l= 12 cons: SEQUENCE
75:d=9 hl=2 l= 8 prim: OBJECT :hmacWithSHA256
85:d=9 hl=2 l= 0 prim: NULL
87:d=6 hl=2 l= 29 cons: SEQUENCE
89:d=7 hl=2 l= 9 prim: OBJECT :aes-256-cbc
100:d=7 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:CDACD92F68D13672599CD034CF3E791A
118:d=4 hl=4 l=1232 prim: OCTET STRING [HEX DUMP]:44725D0E70327934F75AD51CA7E3...
在 RFC 2898, Appendix A.4 中指定了它应该如何。
Is there a PKCS12 provider that does?
是的,以下是使用 BouncyCastle 创建有效 PKCS#12 密钥库的方法:
Security.addProvider(new BouncyCastleProvider());
File file = new File("test.p12");
char[] password = "test".toCharArray();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keypair = keyGen.genKeyPair();
X500Name issuer = new X500Name("CN=test");
X500Name subject = new X500Name("CN=test");
BigInteger serial = new BigInteger("1");
Date notBefore = new Date();
Date notAfter = new Date(System.currentTimeMillis() + 365 * 24 * 3600000L);
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keypair.getPublic());
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(keypair.getPrivate());
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, new BasicConstraints(true));
X509Certificate cert1 = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
OutputEncryptor pkenc = new JcePKCSPBEOutputEncryptorBuilder(NISTObjectIdentifiers.id_aes256_CBC)
.setPRF(PBKDF2Config.PRF_SHA256).setIterationCount(100000).setProvider("BC").build(password);
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
PKCS12SafeBagBuilder certBagBuilder = new JcaPKCS12SafeBagBuilder(cert1);
certBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("test"));
SubjectKeyIdentifier pubKeyId = extUtils.createSubjectKeyIdentifier(cert1.getPublicKey());
certBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(keypair.getPrivate(), pkenc);
keyBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("test"));
keyBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();
builder.addData(keyBagBuilder.build());
OutputEncryptor crtenc = new JcePKCSPBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC)
.setIterationCount(50000).setProvider("BC").build(password);
builder.addEncryptedData(crtenc, new PKCS12SafeBag[]{certBagBuilder.build()});
PKCS12PfxPdu pfx = builder.build(new JcePKCS12MacCalculatorBuilder(NISTObjectIdentifiers.id_sha256), password);
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(pfx.getEncoded(ASN1Encoding.DL));
}
结果:
$ openssl pkcs12 -info -nodes -in test3.p12 -passin pass:test -noout
MAC:sha256 Iteration 1024
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 100000, PRF hmacWithSHA256
PKCS7 Encrypted data: pbeWithSHA1And128BitRC2-CBC, Iteration 50000
Certificate bag
我需要在 Scala/Java 中构建一个 PKCS-12 文件,并且我希望使用基于 AES 的私钥加密(例如 PBEWithHmacSHA512AndAES_128)
我使用这个代码(取自here)
val outputStream = new FileOutputStream(file)
val salt = new Array[Byte](20)
new SecureRandom().nextBytes(salt)
val kspkcs12 = KeyStore.getInstance("PKCS12")
kspkcs12.load(null, null)
kspkcs12.setEntry("test", new KeyStore.PrivateKeyEntry(keys.getPrivate, Array(cert)),
new KeyStore.PasswordProtection("changeMe".toCharArray, "PBEWithHmacSHA512AndAES_128", new PBEParameterSpec(salt,
100000)))
kspkcs12.store(outputStream, "changeMe".toArray)
现在,当用
检查结果时 openssl pkcs12 -info -in filename.p12 -noout
我得到:
MAC:sha1 Iteration 100000 PKCS7 Data Shrouded Keybag: PBES2<unsupported parameters> PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000 Certificate bag'
为什么我得到的是 "PKCS7 Encrypted data" 而不是 PKCS12? 我从
了解到"PBES2<unsupported parameters>"
消息提供者不支持所请求的算法。有 PKCS12 供应商吗?
Why am I getting a "PKCS7 Encrypted data" instead of PKCS12?
PKCS 是一堆规范,即每个更高级别的规范重新使用较低级别的规范。
对于 PKCS#12,我们至少遇到:
- PKCS#12(密钥库格式)
- PKCS#7(signed/encrypted 消息)
- PKCS#5 (PBKDF2)
- PKCS#9(消息摘要)
- PKCS#8(密钥对格式)
所以您在输出中看到与 PKCS#7 相关的消息是正常的。
I understand from the "
PBES2<unsupported parameters>
" that the provider does not support the requested algorithm.
是的,这是 Java 中的错误。内置 JCE 提供程序在输出流中错误地对 PBES2 标记进行了两次编码:
public void derEncode (OutputStream out) throws IOException {
DerOutputStream bytes = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
bytes.putOID(algid); // <<< Writes 1.2.840.113549.1.5.13
并且在 PBES2Parameters.engineGetEncoded()
中一次:
protected byte[] engineGetEncoded() throws IOException {
DerOutputStream out = new DerOutputStream();
DerOutputStream pBES2Algorithms = new DerOutputStream();
pBES2Algorithms.putOID(pkcs5PBES2_OID); // <<< Writes 1.2.840.113549.1.5.13 again
这是它生成的内容(我使用的是 HMAC SHA256 和 AES256):
$ openssl asn1parse -inform der -strparse 973 < test.p12
0:d=0 hl=4 l=1441 cons: SEQUENCE
4:d=1 hl=4 l=1437 cons: SEQUENCE
8:d=2 hl=2 l= 11 prim: OBJECT :pkcs8ShroudedKeyBag
21:d=2 hl=4 l=1358 cons: cont [ 0 ]
25:d=3 hl=4 l=1354 cons: SEQUENCE
29:d=4 hl=2 l= 116 cons: SEQUENCE
31:d=5 hl=2 l= 9 prim: OBJECT :PBES2
42:d=5 hl=2 l= 103 cons: SEQUENCE
44:d=6 hl=2 l= 9 prim: OBJECT :PBES2 <<<<< PBES2 tag encoded twice!!
55:d=6 hl=2 l= 90 cons: SEQUENCE
57:d=7 hl=2 l= 57 cons: SEQUENCE
59:d=8 hl=2 l= 9 prim: OBJECT :PBKDF2
70:d=8 hl=2 l= 44 cons: SEQUENCE
72:d=9 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:9F642532C15BBF1E566AA6429DA450EFBF0FF265
94:d=9 hl=2 l= 3 prim: INTEGER :0186A0
99:d=9 hl=2 l= 1 prim: INTEGER :20
102:d=9 hl=2 l= 12 cons: SEQUENCE
104:d=10 hl=2 l= 8 prim: OBJECT :hmacWithSHA256
114:d=10 hl=2 l= 0 prim: NULL
116:d=7 hl=2 l= 29 cons: SEQUENCE
118:d=8 hl=2 l= 9 prim: OBJECT :aes-256-cbc
129:d=8 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:DF2D490C6BA58A19EDAF8D22E2A2CFA0
147:d=4 hl=4 l=1232 prim: OCTET STRING [HEX DUMP]:22343E6418F8C60857D9A5CC089D...
它应该是这样的(openssl pkcs12 -encode
的输出):
$ openssl asn1parse -inform der -strparse 1003 < test.p12
0:d=0 hl=4 l=1414 cons: SEQUENCE
4:d=1 hl=4 l=1410 cons: SEQUENCE
8:d=2 hl=2 l= 11 prim: OBJECT :pkcs8ShroudedKeyBag
21:d=2 hl=4 l=1329 cons: cont [ 0 ]
25:d=3 hl=4 l=1325 cons: SEQUENCE
29:d=4 hl=2 l= 87 cons: SEQUENCE
31:d=5 hl=2 l= 9 prim: OBJECT :PBES2
42:d=5 hl=2 l= 74 cons: SEQUENCE
44:d=6 hl=2 l= 41 cons: SEQUENCE
46:d=7 hl=2 l= 9 prim: OBJECT :PBKDF2
57:d=7 hl=2 l= 28 cons: SEQUENCE
59:d=8 hl=2 l= 8 prim: OCTET STRING [HEX DUMP]:6FA108004C54EAC4
69:d=8 hl=2 l= 2 prim: INTEGER :0800
73:d=8 hl=2 l= 12 cons: SEQUENCE
75:d=9 hl=2 l= 8 prim: OBJECT :hmacWithSHA256
85:d=9 hl=2 l= 0 prim: NULL
87:d=6 hl=2 l= 29 cons: SEQUENCE
89:d=7 hl=2 l= 9 prim: OBJECT :aes-256-cbc
100:d=7 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:CDACD92F68D13672599CD034CF3E791A
118:d=4 hl=4 l=1232 prim: OCTET STRING [HEX DUMP]:44725D0E70327934F75AD51CA7E3...
在 RFC 2898, Appendix A.4 中指定了它应该如何。
Is there a PKCS12 provider that does?
是的,以下是使用 BouncyCastle 创建有效 PKCS#12 密钥库的方法:
Security.addProvider(new BouncyCastleProvider());
File file = new File("test.p12");
char[] password = "test".toCharArray();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keypair = keyGen.genKeyPair();
X500Name issuer = new X500Name("CN=test");
X500Name subject = new X500Name("CN=test");
BigInteger serial = new BigInteger("1");
Date notBefore = new Date();
Date notAfter = new Date(System.currentTimeMillis() + 365 * 24 * 3600000L);
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keypair.getPublic());
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(keypair.getPrivate());
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, new BasicConstraints(true));
X509Certificate cert1 = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
OutputEncryptor pkenc = new JcePKCSPBEOutputEncryptorBuilder(NISTObjectIdentifiers.id_aes256_CBC)
.setPRF(PBKDF2Config.PRF_SHA256).setIterationCount(100000).setProvider("BC").build(password);
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
PKCS12SafeBagBuilder certBagBuilder = new JcaPKCS12SafeBagBuilder(cert1);
certBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("test"));
SubjectKeyIdentifier pubKeyId = extUtils.createSubjectKeyIdentifier(cert1.getPublicKey());
certBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(keypair.getPrivate(), pkenc);
keyBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("test"));
keyBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();
builder.addData(keyBagBuilder.build());
OutputEncryptor crtenc = new JcePKCSPBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC)
.setIterationCount(50000).setProvider("BC").build(password);
builder.addEncryptedData(crtenc, new PKCS12SafeBag[]{certBagBuilder.build()});
PKCS12PfxPdu pfx = builder.build(new JcePKCS12MacCalculatorBuilder(NISTObjectIdentifiers.id_sha256), password);
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(pfx.getEncoded(ASN1Encoding.DL));
}
结果:
$ openssl pkcs12 -info -nodes -in test3.p12 -passin pass:test -noout
MAC:sha256 Iteration 1024
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 100000, PRF hmacWithSHA256
PKCS7 Encrypted data: pbeWithSHA1And128BitRC2-CBC, Iteration 50000
Certificate bag