PKCS8 with PBES2 protection supported by EncryptedPrivateKeyInfo?
Anthony Scarpino
anthony.scarpino at oracle.com
Tue Aug 9 01:26:46 UTC 2022
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 at 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 at 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).
>>
More information about the security-dev
mailing list