in an Android project I need to authenticate my app for an https connection. Using the following method I'm trying to decrypt my private key, provided by the server developers in a .pem file. I use SpongyCastle, and at the top of the same class where the methods are I already changed the security provider like this:
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
In this case my object is an instance of PKCS8EncryptedPrivateKeyInfo. This is the method:
/**
* Parses a PrivateKey instance from a PEM representation.
*
* When the provided key is encrypted, the provided pass phrase is applied.
*
* @param pemRepresentation a PEM representation of a private key (cannot be null or empty)
* @param passPhrase optional pass phrase (must be present if the private key is encrypted).
* @return a PrivateKey instance (never null)
*/
public static PrivateKey parsePrivateKey(InputStream pemRepresentation, String passPhrase) throws IOException {
if ( passPhrase == null ) {
passPhrase = "";
}
try (Reader reader = new InputStreamReader(pemRepresentation); //
PEMParser pemParser = new PEMParser(reader)) {
final Object object = pemParser.readObject();
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider( "BC" );
final KeyPair kp;
if ( object instanceof PEMEncryptedKeyPair )
{
// Encrypted key - we will use provided password
final PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build( passPhrase.toCharArray() );
kp = converter.getKeyPair( ( (PEMEncryptedKeyPair) object ).decryptKeyPair( decProv ) );
}
else if ( object instanceof PKCS8EncryptedPrivateKeyInfo )
{
// Encrypted key - we will use provided password
try
{
final PKCS8EncryptedPrivateKeyInfo encryptedInfo = (PKCS8EncryptedPrivateKeyInfo) object;
final InputDecryptorProvider provider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build( passPhrase.toCharArray() );
final PrivateKeyInfo privateKeyInfo = encryptedInfo.decryptPrivateKeyInfo( provider );
return converter.getPrivateKey( privateKeyInfo );
}
catch ( PKCSException | OperatorCreationException e )
{
throw new IOException( "Unable to decrypt private key.", e );
}
}
else if ( object instanceof PrivateKeyInfo )
{
return converter.getPrivateKey( (PrivateKeyInfo) object );
}
else
{
// Unencrypted key - no password needed
kp = converter.getKeyPair( (PEMKeyPair) object );
}
return kp.getPrivate();
}
}
When I arrive at:
encryptedInfo.decryptPrivateKeyInfo( provider );
I encounter the following exception:
org.spongycastle.pkcs.PKCSException: unable to read encrypted data: Error while finalizing cipher
at org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(PKCS8EncryptedPrivateKeyInfo.java:73)
[...]
at android.view.View.performClick(View.java:5184)
at android.view.View$PerformClick.run(View.java:20893)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5938)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.io.IOException: Error while finalizing cipher
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:104)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:155)
at org.spongycastle.util.io.Streams.pipeAll(Streams.java:114)
at org.spongycastle.util.io.Streams.readAll(Streams.java:41)
at org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(PKCS8EncryptedPrivateKeyInfo.java:69)
... 21 more
Caused by: javax.crypto.BadPaddingException: pad block corrupted
at org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(BaseBlockCipher.java:1227)
at org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:1103)
at javax.crypto.Cipher.doFinal(Cipher.java:1314)
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:102)
... 25 more
Any suggestion? Thanks.