简体   繁体   English

如何使用私有密钥加密PBEWithHmacSHA512AndAES_128创建PKCS12密钥库

[英]How to create a PKCS12 keystore with privatekey encryption PBEWithHmacSHA512AndAES_128

I need to build a PKCS-12 file in Scala/Java and I wish to use an AES based encryption of the private-key (eg PBEWithHmacSHA512AndAES_128) 我需要在Scala / Java中构建PKCS-12文件,并且希望使用基于AES的私钥加密(例如PBEWithHmacSHA512AndAES_128)

I use this code (taken from 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)

now, when checking the result with 现在,当用

 openssl pkcs12 -info -in filename.p12  -noout

I'm getting: 我越来越:

MAC:sha1 Iteration 100000 PKCS7 Data Shrouded Keybag: PBES2<unsupported parameters> PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000 Certificate bag' MAC:sha1迭代100000 PKCS7数据覆盖密钥袋:PBES2 <不支持的参数> PKCS7加密数据:pbeWithSHA1And40BitRC2-CBC,迭代50000证书袋

Why am I getting a "PKCS7 Encrypted data" instead of PKCS12? 为什么我得到的是“ PKCS7加密数据”而不是PKCS12? I understand from the 我从

"PBES2<unsupported parameters>" “ PBES2 <不支持的参数>”

message that the provider does not support the requested algorithm. 消息,指示提供程序不支持所请求的算法。 Is there a PKCS12 provider that does? 是否有提供的PKCS12提供程序?

Why am I getting a "PKCS7 Encrypted data" instead of PKCS12? 为什么我得到的是“ PKCS7加密数据”而不是PKCS12?

PKCS is a stack of specifications, ie each higher level spec re-uses lower-level specs. PKCS是规范的堆栈,即,每个较高级别的规范都会重复使用较低级别的规范。

In case of PKCS#12, we encounter at least: 对于PKCS#12,我们至少遇到:

  • PKCS#12 (keystore format) PKCS#12(密钥库格式)
  • PKCS#7 (signed/encrypted message) PKCS#7(签名/加密的消息)
  • PKCS#5 (PBKDF2) PKCS#5(PBKDF2)
  • PKCS#9 (message digest) PKCS#9(消息摘要)
  • PKCS#8 (keypair format) PKCS#8(密钥对格式)

So it's normal that you see messages relating to PKCS#7 in the output. 因此,在输出中看到与PKCS#7相关的消息是正常的。

I understand from the " PBES2<unsupported parameters> " that the provider does not support the requested algorithm. 我从“ PBES2<unsupported parameters> ”中了解到,提供程序不支持所请求的算法。

Yes, it's a bug in Java. 是的,这是Java中的错误。 The built-in JCE provider erroneously encodes the PBES2 tag twice in the output stream: 内置的JCE提供程序在输出流中错误地对PBES2标签进行了两次编码:

Once in AlgorithmId.derEncode() 进入AlgorithmId.derEncode()

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

And once in PBES2Parameters.engineGetEncoded() : 然后进入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

Here's what it produces (I'm using HMAC SHA256 with AES256): 这是产生的结果(我将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...

And here's how it should be (output from openssl pkcs12 -encode ): 这是应该的样子(从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...

How it should be is specified in RFC 2898, Appendix A.4 . RFC 2898附录A.4中指定了应如何指定。

Is there a PKCS12 provider that does? 是否有提供的PKCS12提供程序?

Yes, here's how to create a valid PKCS#12 keystore using BouncyCastle: 是的,以下是使用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));
}

The result: 结果:

$ 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM