Merge "Support RSA encrypt using private key and PKCS#1 paddding." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-06-25 16:46:15 +00:00
committed by Android (Google) Code Review
2 changed files with 66 additions and 18 deletions

View File

@@ -731,6 +731,21 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
return mMainDataStreamer.getProducedOutputSizeBytes(); return mMainDataStreamer.getProducedOutputSizeBytes();
} }
static String opmodeToString(int opmode) {
switch (opmode) {
case Cipher.ENCRYPT_MODE:
return "ENCRYPT_MODE";
case Cipher.DECRYPT_MODE:
return "DECRYPT_MODE";
case Cipher.WRAP_MODE:
return "WRAP_MODE";
case Cipher.UNWRAP_MODE:
return "UNWRAP_MODE";
default:
return String.valueOf(opmode);
}
}
// The methods below need to be implemented by subclasses. // The methods below need to be implemented by subclasses.
/** /**

View File

@@ -60,9 +60,10 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
} }
@Override @Override
protected boolean isEncryptingUsingPrivateKeyPermitted() { protected boolean adjustConfigForEncryptingWithPrivateKey() {
// RSA encryption with no padding using private key is is a way to implement raw RSA // RSA encryption with no padding using private key is a way to implement raw RSA
// signatures. We have to support this. // signatures which JCA does not expose via Signature. We thus have to support this.
setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
return true; return true;
} }
@@ -197,6 +198,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT); super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
} }
@Override
protected boolean adjustConfigForEncryptingWithPrivateKey() {
// RSA encryption with PCKS#1 padding using private key is a way to implement RSA
// signatures with PKCS#1 padding. We have to support this for legacy reasons.
setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
return true;
}
@Override @Override
protected void initAlgorithmSpecificParameters() throws InvalidKeyException {} protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
@@ -425,6 +435,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
} }
private final int mKeymasterPadding; private final int mKeymasterPadding;
private int mKeymasterPaddingOverride;
private int mModulusSizeBytes = -1; private int mModulusSizeBytes = -1;
@@ -458,20 +469,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
// Permitted // Permitted
break; break;
case Cipher.ENCRYPT_MODE: case Cipher.ENCRYPT_MODE:
if (!isEncryptingUsingPrivateKeyPermitted()) { case Cipher.WRAP_MODE:
if (!adjustConfigForEncryptingWithPrivateKey()) {
throw new InvalidKeyException( throw new InvalidKeyException(
"RSA private keys cannot be used with Cipher.ENCRYPT_MODE" "RSA private keys cannot be used with " + opmodeToString(opmode)
+ " and padding "
+ KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
+ ". Only RSA public keys supported for this mode"); + ". Only RSA public keys supported for this mode");
} }
// JCA doesn't provide a way to generate raw RSA signatures (with arbitrary
// padding). Thus, encrypting with private key is used instead.
setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
break; break;
case Cipher.WRAP_MODE:
throw new InvalidKeyException(
"RSA private keys cannot be used with Cipher.WRAP_MODE"
+ ". Only RSA public keys supported for this mode");
// break;
default: default:
throw new InvalidKeyException( throw new InvalidKeyException(
"RSA private keys cannot be used with opmode: " + opmode); "RSA private keys cannot be used with opmode: " + opmode);
@@ -485,12 +491,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
break; break;
case Cipher.DECRYPT_MODE: case Cipher.DECRYPT_MODE:
case Cipher.UNWRAP_MODE: case Cipher.UNWRAP_MODE:
throw new InvalidKeyException("RSA public keys cannot be used with opmode: " throw new InvalidKeyException(
+ opmode + ". Only RSA private keys supported for this opmode."); "RSA public keys cannot be used with " + opmodeToString(opmode)
+ " and padding "
+ KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
+ ". Only RSA private keys supported for this opmode.");
// break; // break;
default: default:
throw new InvalidKeyException( throw new InvalidKeyException(
"RSA public keys cannot be used with opmode: " + opmode); "RSA public keys cannot be used with " + opmodeToString(opmode));
} }
} }
@@ -511,13 +520,22 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
setKey(keystoreKey); setKey(keystoreKey);
} }
protected boolean isEncryptingUsingPrivateKeyPermitted() { /**
* Adjusts the configuration of this cipher for encrypting using the private key.
*
* <p>The default implementation does nothing and refuses to adjust the configuration.
*
* @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
* using private key is not permitted for this cipher.
*/
protected boolean adjustConfigForEncryptingWithPrivateKey() {
return false; return false;
} }
@Override @Override
protected final void resetAll() { protected final void resetAll() {
mModulusSizeBytes = -1; mModulusSizeBytes = -1;
mKeymasterPaddingOverride = -1;
super.resetAll(); super.resetAll();
} }
@@ -530,7 +548,11 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
protected void addAlgorithmSpecificParametersToBegin( protected void addAlgorithmSpecificParametersToBegin(
@NonNull KeymasterArguments keymasterArgs) { @NonNull KeymasterArguments keymasterArgs) {
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); int keymasterPadding = getKeymasterPaddingOverride();
if (keymasterPadding == -1) {
keymasterPadding = mKeymasterPadding;
}
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
int purposeOverride = getKeymasterPurposeOverride(); int purposeOverride = getKeymasterPurposeOverride();
if ((purposeOverride != -1) if ((purposeOverride != -1)
&& ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN) && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
@@ -568,4 +590,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
} }
return mModulusSizeBytes; return mModulusSizeBytes;
} }
/**
* Overrides the default padding of the crypto operation.
*/
protected final void setKeymasterPaddingOverride(int keymasterPadding) {
mKeymasterPaddingOverride = keymasterPadding;
}
protected final int getKeymasterPaddingOverride() {
return mKeymasterPaddingOverride;
}
} }