Oops.. I think I suggested something that only works in my development repo with PBES2.

I ran you code and it worked on jdk-dev. Other than setting -v2 on the 'openssl pkcs8' cmdline,

en javax.crypto.EncryptedPrivateKeyInfo@46d56d67 alg=PBEWithHmacSHA1AndAES_256 p=PBEWithHmacSHA1AndAES_256
k=SunRsaSign RSA private CRT key, 2048 bits
  params: null
  modulus: ...

Tony

On 8/8/22 5:12 PM, Anthony Scarpino wrote:
Hi,

I did this not long ago. You are close, but you do not need to do the Cipher.init() separately, it is done as part of EncryptedPrivateKeyInfo.getKeySpec().  It also reads the encoding for the count and iv.

The below will decrypt the DER-encoded 'data' into a PKCS8EncryptedKeySpec for you to use.

EncryptedPrivateKeyInfo epki = new EncryptedPrivateKeyInfo(data);
PBEKeySpec pks = new PBEKeySpec(password);
SecretKeyFactory skf = SecretKeyFactory.getInstance(epki.getAlgName());
SecretKey sk = skf.generateSecret(pks);
PKCS8EncodedKeySpec keySpec = epki.getKeySpec(sk);

Tony

On 8/7/22 12:18 PM, Bernd wrote:
Hello,

there is a longstanding issue in the PostgreSQL JDBC driver which reads secret keys in PKCS#8 format, but does not support the newer PKCS#5 2.0 (PBES2) modes (-v1 works). The (naive) code is here:

pgjdbc/LazyKeyManager.java at 80d4ed34c99d51dd8b06df00baad0265fd620fec · pgjdbc/pgjdbc · GitHub <https://github.com/pgjdbc/pgjdbc/blob/80d4ed34c99d51dd8b06df00baad0265fd620fec/pgjdbc/src/main/java/org/postgresql/ssl/LazyKeyManager.java#L220>

I was playing around with EncryptedPrivateKeyInfo in order to see whats needed to get it working with PBES2 encryption, but it did not work with quite a few tries.

I wonder is the Code behind PBES2Parameters in JCE supposed to work and interoperable with openssl PKCS#8? If I understand the api correctly the following code should work, but it results in a padding error:

     public static void main(String[] args) throws Throwable
     {
         byte[] b = readFileFully("test-key.p8"); // DER Format
         EncryptedPrivateKeyInfo ePKInfo = new EncryptedPrivateKeyInfo(b);          System.out.println("en " + ePKInfo + " alg=" + ePKInfo.getAlgName()                                         + " p=" + ePKInfo.getAlgParameters().toString());
         AlgorithmParameters algParams = ePKInfo.getAlgParameters();
         //PBEParameterSpec pbep = algParams.getParameterSpec(PBEParameterSpec.class);
         //System.out.println("pbep " + pbep);
         //AlgorithmParameterSpec cp = pbep.getParameterSpec();
         //System.out.println("cp = " + cp ); // IvParameters

         PBEKeySpec pbeKeySpec = new PBEKeySpec("test".toCharArray());
         //PBEKeySpec pbeKeySpec = new PBEKeySpec("test".toCharArray(),
         //   pbep.getSalt(), pbep.getIterationCount(), 256);
         SecretKeyFactory skFac = SecretKeyFactory.getInstance(algParams.toString());
         Key pbeKey = skFac.generateSecret(pbeKeySpec);

         Cipher cipher = Cipher.getInstance(algParams.toString());
         cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);

         // Decrypt the encrypted private key
         // when passing pbeKey here instead of cipher the algParams are lost          KeySpec pkcs8KeySpec = ePKInfo.getKeySpec(cipher); // L61 --> throws

         // not reached
         KeyFactory kf = KeyFactory.getInstance("RSA");
         PrivateKey key = kf.generatePrivate(pkcs8KeySpec);
         System.out.println("k=" + key);
}

The test object created with openssl:
 > openssl req -x509 -newkey rsa:2048 -keyout test-key.pem -out test-cert.pem -sha256 -days 365 -nodes  > openssl pkcs8 -topk8 -in test-key.pem -out test-key.p8 -outform der # password "test"
 > openssl asn1parse -in test-key.p8 -inform DER
     0:d=0  hl=4 l=1325 cons: SEQUENCE
     4:d=1  hl=2 l=  87 cons: SEQUENCE
     6:d=2  hl=2 l=   9 prim: OBJECT            :PBES2
    17:d=2  hl=2 l=  74 cons: SEQUENCE
    19:d=3  hl=2 l=  41 cons: SEQUENCE
    21:d=4  hl=2 l=   9 prim: OBJECT            :PBKDF2
    32:d=4  hl=2 l=  28 cons: SEQUENCE
    34:d=5  hl=2 l=   8 prim: OCTET STRING      [HEX DUMP]:BDCF0B11DB8BAFAB
    44:d=5  hl=2 l=   2 prim: INTEGER           :0800
    48:d=5  hl=2 l=  12 cons: SEQUENCE
    50:d=6  hl=2 l=   8 prim: OBJECT            :hmacWithSHA256
    60:d=6  hl=2 l=   0 prim: NULL
    62:d=3  hl=2 l=  29 cons: SEQUENCE
    64:d=4  hl=2 l=   9 prim: OBJECT            :aes-256-cbc
    75:d=4  hl=2 l=  16 prim: OCTET STRING      [HEX DUMP]:E355E1C72C9F486DDBE2E1F58EE7B61E     93:d=1  hl=4 l=1232 prim: OCTET STRING      [HEX DUMP]:E4D9C29E4789840093EE371AB6EACB3111920E636CCB924651125D97CBD5312156214AD173CF4159AEEDBB497900815FE3B24184846CA252A421784CAD121B59C93EE3427BEA7CF0E404FAD0F226A2D13B86BD4898455B0750FBA6C4FB5F0B66980BD586CFFCBB5FA2170A67917FD55F7AF0E03D03078E5191965F74C099E357F28B6DA969E3CF3D713ABBC35C20A513E8068822A1C9B67BAFB650FB4B8EB7755A9F1760CD0B82AEBFBCCA01F575C377CD5AA2732D42F10A43EEF46048650E492F9FE1FD56596DDAC70461BF3E60CEA97F7EA99741254D1C1452CF1081DD799EACC74C8C0E806104230AE91E560C8F458B7BB358F031726355E99D31938CF39EC40B76D963FC3D45A59C7BE14CC769E7E4DA8C9FC08F4BD1A4C4CC07141BA0D5A31F0319E32D48A12A2BA4ABA4979A68447AFA57B8A9F82D465B1E765169B1C339C88F9EC9934B0B1B58C5793991FB9990F44C9C7A816ABE97015ECFB408CBF906BABAF9C7F5D0F32673AA1D9D72A0C3738FC9C1909FB24A029A3928C583B2DE4CCF3247F7C89D97E8DEEF3E08796789D43B56A66D1C07B3D368948964FAA1746EEC59605A14934B02BFE14B6BC8A281973E76215E7FF9A43FD33780F34D76A21791586EDBA5999BCE08D8DF5E20B736DDA9B91091991B0EE883CC3E8358D8403486B53D205C0DD33EE3224D1BE40DE9FCD444D70BDE6500B08FF843153EC8EF01F5CDC9D01CB9372BBCA6F42D5D13159AC9E67CAB075A20D86F9538AE604E87DEBF1300D3E6A8BEB72F1F2124F903E95A558DE3BEB61A1AAE792E9A77A6F860BD736D2C0BA97FDA25D4E3AEAF8149415E68E473F48D99860DC2A49F108AE5468DFC36A5764E3B06412D2C3498D87E9F5D487421FD5C15C0EA8306A69BFA2956D8F8C1F4CD4786EDE575515202F8442CBA2E3AA21CB267DDEC5BA7BB1CBC54F471E84CD522FCE9A69F084DD4EB100F00875A0A32BCCD6D5F5473FF8CA6E6B448BAB76A659E0350AAFC3A2EFBCCAF1AFB52F3C8A7F3B452E5B35CDC2CD05710D86529EE3544DE9AB5A7FAA9AD8ADC93B0F7F5432FF8EB280A3BEE3C094796C9938DC5A4956D47CE4CE7A7D2300E328D47F030332EC84296CD57F02B61B63A099210C78F64B3DB618E79A17585030CB82B8B39BB34333D148F5856D04B4083BD0F006B8A747D7E020DDD8DCA99AEF6B719367DB619C7736D7897F071875CC9C17F7AF3E742F06CDBEBECDF486CC6B143BB96FC4FE34A54CB1CBFDF877598094B459DBAA6B101B0DE8000A5E2D06ABAE1C651EDF3EA3A7D37EA263AC999B65F621E1F65FFD06F461B7285EB90AE2C32AA60C8424966BF37F2C4F502BFE253E252C1CD652FC8667E488BF8B282D0379B38AC9B53014C87C55E8DE8EB7A217F521F46FC13F983C3E77B61417A552D7ACC147FC40C295DD87DDC4972AF340384B449A8A888BD1F4AB7B5B2D6AB3E963F7E90870639709075FA4A618A640753B6E2B6B4C0734BFEEE7A14C94C64131C666749E813A07FB8622278BF7F823675883F8B57C9BC081420F96C7F71E006D3A41299711E6E283F7C97E1ECC1202D98DF0BB13742D8DB5FDFE4569C35E207983645AE86AA2286680A9EDB69742DBD164D499096C90A063EE6304C81D2DB8311A73F80D7E1BB14B2C0C249D14F7D953369513731A5DEDB2AAD671E74F704CAFBCF4CDEDB72E42A238DD9CA2AB77ABAE80350F508062276A66C9BF81C325368E496C9490B

 From debugging it looks like it picked up the salt for PBKFD#2 and the Iv for AES, but it is a bit nested, so I tried passing Cipher and/or Key to getKeySpec().

The output

en javax.crypto.EncryptedPrivateKeyInfo@27716f4 alg=1.2.840.113549.1.5.13 p=PBEWithHmacSHA1AndAES_256 Exception in thread "main" java.security.spec.InvalidKeySpecException: Cannot retrieve the PKCS8EncodedKeySpec at javax.crypto.EncryptedPrivateKeyInfo.getKeySpec(EncryptedPrivateKeyInfo.java:255)
at bernd.TestKey.main(TestKey.java:61)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at com.sun.crypto.provider.PBES2Core.engineDoFinal(PBES2Core.java:323)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at javax.crypto.EncryptedPrivateKeyInfo.getKeySpec(EncryptedPrivateKeyInfo.java:250)
... 1 more

I see there are some test cases for a similar usage, but they depend on an initialized key with defaults, so I am not sure if that would actually use AES IV?

https://github.com/openjdk/jdk/blob/357f990e3244feaba6d8709b7ea50660220a418b/test/jdk/sun/security/x509/AlgorithmId/PBES2.java#L89
 
<https://github.com/openjdk/jdk/blob/357f990e3244feaba6d8709b7ea50660220a418b/test/jdk/sun/security/x509/AlgorithmId/PBES2.java#L89>

BTW: its hard to say if the problem is "only" caused by UTF-8 vs. UTF-16 password encoding. In that case it would be a bit unfortunate, is it maybe an option to add that support? (however I am not sure what password encoding openssl uses in this case).

Reply via email to