<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Hello,<div><br></div><div>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:</div><div><br></div><div><a href="https://github.com/pgjdbc/pgjdbc/blob/80d4ed34c99d51dd8b06df00baad0265fd620fec/pgjdbc/src/main/java/org/postgresql/ssl/LazyKeyManager.java#L220">pgjdbc/LazyKeyManager.java at 80d4ed34c99d51dd8b06df00baad0265fd620fec · pgjdbc/pgjdbc · GitHub</a><br></div><div><br></div><div>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.</div><div><br></div><div>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:</div><div><br></div><div><div>    public static void main(String[] args) throws Throwable<br>    {</div><div>        byte[] b = readFileFully("test-key.p8"); // DER Format</div><div>        EncryptedPrivateKeyInfo ePKInfo = new EncryptedPrivateKeyInfo(b);<br><div>        System.out.println("en " + ePKInfo + " alg=" + ePKInfo.getAlgName() <br>                                       + " p=" + ePKInfo.getAlgParameters().toString());</div></div><div>        AlgorithmParameters algParams = ePKInfo.getAlgParameters();<br></div><div>        //PBEParameterSpec pbep = algParams.getParameterSpec(PBEParameterSpec.class);</div><div>        //System.out.println("pbep " + pbep);</div><div>        //AlgorithmParameterSpec cp = pbep.getParameterSpec();</div><div>        //System.out.println("cp = " + cp ); // IvParameters</div><div><br>        PBEKeySpec pbeKeySpec = new PBEKeySpec("test".toCharArray());</div><div><div>        //PBEKeySpec pbeKeySpec = new PBEKeySpec("test".toCharArray(),<br>        //                                                       pbep.getSalt(), pbep.getIterationCount(), 256);</div><div>        SecretKeyFactory skFac = SecretKeyFactory.getInstance(algParams.toString());<br></div></div><div>        Key pbeKey = skFac.generateSecret(pbeKeySpec);</div><div><br></div><div>        Cipher cipher = Cipher.getInstance(algParams.toString());<br></div><div>        cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);</div><div><br></div><div>        // Decrypt the encrypted private key<br>        // when passing pbeKey here instead of cipher the algParams are lost</div><div>        KeySpec pkcs8KeySpec = ePKInfo.getKeySpec(cipher); // L61 --> throws<br><br></div><div>        // not reached</div><div>        KeyFactory kf = KeyFactory.getInstance("RSA");</div><div>        PrivateKey key = kf.generatePrivate(pkcs8KeySpec);</div><div>        System.out.println("k=" + key);</div></div><div>}</div><div><br></div><div>The test object created with openssl:</div><div>> openssl req -x509 -newkey rsa:2048 -keyout test-key.pem -out test-cert.pem -sha256 -days 365 -nodes<br>> openssl pkcs8 -topk8 -in test-key.pem -out test-key.p8 -outform der  # password "test"<br>> openssl asn1parse -in test-key.p8 -inform DER</div><div>    0:d=0  hl=4 l=1325 cons: SEQUENCE</div><div>    4:d=1  hl=2 l=  87 cons: SEQUENCE</div><div>    6:d=2  hl=2 l=   9 prim: OBJECT            :PBES2</div><div>   17:d=2  hl=2 l=  74 cons: SEQUENCE</div><div>   19:d=3  hl=2 l=  41 cons: SEQUENCE</div><div>   21:d=4  hl=2 l=   9 prim: OBJECT            :PBKDF2</div><div>   32:d=4  hl=2 l=  28 cons: SEQUENCE</div><div>   34:d=5  hl=2 l=   8 prim: OCTET STRING      [HEX DUMP]:BDCF0B11DB8BAFAB</div><div>   44:d=5  hl=2 l=   2 prim: INTEGER           :0800</div><div>   48:d=5  hl=2 l=  12 cons: SEQUENCE</div><div>   50:d=6  hl=2 l=   8 prim: OBJECT            :hmacWithSHA256</div><div>   60:d=6  hl=2 l=   0 prim: NULL</div><div>   62:d=3  hl=2 l=  29 cons: SEQUENCE</div><div>   64:d=4  hl=2 l=   9 prim: OBJECT            :aes-256-cbc</div><div>   75:d=4  hl=2 l=  16 prim: OCTET STRING      [HEX DUMP]:E355E1C72C9F486DDBE2E1F58EE7B61E</div><div>   93:d=1  hl=4 l=1232 prim: OCTET STRING      [HEX DUMP]:E4D9C29E4789840093EE371AB6EACB3111920E636CCB924651125D97CBD5312156214AD173CF4159AEEDBB497900815FE3B24184846CA252A421784CAD121B59C93EE3427BEA7CF0E404FAD0F226A2D13B86BD4898455B0750FBA6C4FB5F0B66980BD586CFFCBB5FA2170A67917FD55F7AF0E03D03078E5191965F74C099E357F28B6DA969E3CF3D713ABBC35C20A513E8068822A1C9B67BAFB650FB4B8EB7755A9F1760CD0B82AEBFBCCA01F575C377CD5AA2732D42F10A43EEF46048650E492F9FE1FD56596DDAC70461BF3E60CEA97F7EA99741254D1C1452CF1081DD799EACC74C8C0E806104230AE91E560C8F458B7BB358F031726355E99D31938CF39EC40B76D963FC3D45A59C7BE14CC769E7E4DA8C9FC08F4BD1A4C4CC07141BA0D5A31F0319E32D48A12A2BA4ABA4979A68447AFA57B8A9F82D465B1E765169B1C339C88F9EC9934B0B1B58C5793991FB9990F44C9C7A816ABE97015ECFB408CBF906BABAF9C7F5D0F32673AA1D9D72A0C3738FC9C1909FB24A029A3928C583B2DE4CCF3247F7C89D97E8DEEF3E08796789D43B56A66D1C07B3D368948964FAA1746EEC59605A14934B02BFE14B6BC8A281973E76215E7FF9A43FD33780F34D76A21791586EDBA5999BCE08D8DF5E20B736DDA9B91091991B0EE883CC3E8358D8403486B53D205C0DD33EE3224D1BE40DE9FCD444D70BDE6500B08FF843153EC8EF01F5CDC9D01CB9372BBCA6F42D5D13159AC9E67CAB075A20D86F9538AE604E87DEBF1300D3E6A8BEB72F1F2124F903E95A558DE3BEB61A1AAE792E9A77A6F860BD736D2C0BA97FDA25D4E3AEAF8149415E68E473F48D99860DC2A49F108AE5468DFC36A5764E3B06412D2C3498D87E9F5D487421FD5C15C0EA8306A69BFA2956D8F8C1F4CD4786EDE575515202F8442CBA2E3AA21CB267DDEC5BA7BB1CBC54F471E84CD522FCE9A69F084DD4EB100F00875A0A32BCCD6D5F5473FF8CA6E6B448BAB76A659E0350AAFC3A2EFBCCAF1AFB52F3C8A7F3B452E5B35CDC2CD05710D86529EE3544DE9AB5A7FAA9AD8ADC93B0F7F5432FF8EB280A3BEE3C094796C9938DC5A4956D47CE4CE7A7D2300E328D47F030332EC84296CD57F02B61B63A099210C78F64B3DB618E79A17585030CB82B8B39BB34333D148F5856D04B4083BD0F006B8A747D7E020DDD8DCA99AEF6B719367DB619C7736D7897F071875CC9C17F7AF3E742F06CDBEBECDF486CC6B143BB96FC4FE34A54CB1CBFDF877598094B459DBAA6B101B0DE8000A5E2D06ABAE1C651EDF3EA3A7D37EA263AC999B65F621E1F65FFD06F461B7285EB90AE2C32AA60C8424966BF37F2C4F502BFE253E252C1CD652FC8667E488BF8B282D0379B38AC9B53014C87C55E8DE8EB7A217F521F46FC13F983C3E77B61417A552D7ACC147FC40C295DD87DDC4972AF340384B449A8A888BD1F4AB7B5B2D6AB3E963F7E90870639709075FA4A618A640753B6E2B6B4C0734BFEEE7A14C94C64131C666749E813A07FB8622278BF7F823675883F8B57C9BC081420F96C7F71E006D3A41299711E6E283F7C97E1ECC1202D98DF0BB13742D8DB5FDFE4569C35E207983645AE86AA2286680A9EDB69742DBD164D499096C90A063EE6304C81D2DB8311A73F80D7E1BB14B2C0C249D14F7D953369513731A5DEDB2AAD671E74F704CAFBCF4CDEDB72E42A238DD9CA2AB77ABAE80350F508062276A66C9BF81C325368E496C9490B</div><div><br></div><div>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().</div><div><br></div><div>The output</div><div><div><br></div></div><div><div>en javax.crypto.EncryptedPrivateKeyInfo@27716f4 alg=1.2.840.113549.1.5.13 p=PBEWithHmacSHA1AndAES_256</div><div>Exception in thread "main" java.security.spec.InvalidKeySpecException: Cannot retrieve the PKCS8EncodedKeySpec</div><div><span style="white-space:pre-wrap">        </span>at javax.crypto.EncryptedPrivateKeyInfo.getKeySpec(EncryptedPrivateKeyInfo.java:255)</div><div><span style="white-space:pre-wrap">     </span>at bernd.TestKey.main(TestKey.java:61)</div><div>Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.</div><div><span style="white-space:pre-wrap">   </span>at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)</div><div><span style="white-space:pre-wrap"> </span>at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)</div><div><span style="white-space:pre-wrap">     </span>at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)</div><div><span style="white-space:pre-wrap">       </span>at com.sun.crypto.provider.PBES2Core.engineDoFinal(PBES2Core.java:323)</div><div><span style="white-space:pre-wrap">   </span>at javax.crypto.Cipher.doFinal(Cipher.java:2168)</div><div><span style="white-space:pre-wrap"> </span>at javax.crypto.EncryptedPrivateKeyInfo.getKeySpec(EncryptedPrivateKeyInfo.java:250)</div><div><span style="white-space:pre-wrap">     </span>... 1 more</div></div><div><br></div><div>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?</div><div><br></div><div><a href="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</a><br></div><div><br></div><div>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).</div><div><br></div></div></div></div></div></div></div></div></div></div></div></div></div>