summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-06-08 18:10:05 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-06-08 18:10:09 +0000
commit2c500236f4892b62b4df140f7e61f219a07371e0 (patch)
treef407cd0c036e6acd4fe986f63adcbc648b5b0fb8 /keystore
parent5b688e848c05d8ce0903348b3644184df3d5711a (diff)
parent5552c89fa9cb5ac72edbbcb5a71ef14a07f5ea11 (diff)
downloadframeworks_base-2c500236f4892b62b4df140f7e61f219a07371e0.zip
frameworks_base-2c500236f4892b62b4df140f7e61f219a07371e0.tar.gz
frameworks_base-2c500236f4892b62b4df140f7e61f219a07371e0.tar.bz2
Merge "RSA encrypt with private key in Android Keystore." into mnc-dev
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java28
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java69
2 files changed, 85 insertions, 12 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index fd9bdb8..0e8d03e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -56,6 +56,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
// Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
// doFinal finishes.
private boolean mEncrypting;
+ private int mKeymasterPurposeOverride = -1;
private AndroidKeyStoreKey mKey;
private SecureRandom mRng;
@@ -165,6 +166,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
mKeyStore.abort(operationToken);
}
mEncrypting = false;
+ mKeymasterPurposeOverride = -1;
mKey = null;
mRng = null;
mOperationToken = null;
@@ -210,9 +212,16 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, getAdditionalEntropyAmountForBegin());
+ int purpose;
+ if (mKeymasterPurposeOverride != -1) {
+ purpose = mKeymasterPurposeOverride;
+ } else {
+ purpose = mEncrypting
+ ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT;
+ }
OperationResult opResult = mKeyStore.begin(
mKey.getAlias(),
- mEncrypting ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT,
+ purpose,
true, // permit aborting this operation if keystore runs out of resources
keymasterInputArgs,
additionalEntropy);
@@ -346,11 +355,11 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
} catch (KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
- throw new IllegalBlockSizeException();
+ throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
- throw new BadPaddingException();
+ throw (BadPaddingException) new BadPaddingException().initCause(e);
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- throw new AEADBadTagException();
+ throw (AEADBadTagException) new AEADBadTagException().initCause(e);
default:
throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
}
@@ -437,6 +446,17 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
}
/**
+ * Overrides the default purpose/type of the crypto operation.
+ */
+ protected final void setKeymasterPurposeOverride(int keymasterPurpose) {
+ mKeymasterPurposeOverride = keymasterPurpose;
+ }
+
+ protected final int getKeymasterPurposeOverride() {
+ return mKeymasterPurposeOverride;
+ }
+
+ /**
* Returns {@code true} if this cipher is initialized for encryption, {@code false} if this
* cipher is initialized for decryption.
*/
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index f70c323..5643caf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -60,6 +60,13 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
@Override
+ protected boolean isEncryptingUsingPrivateKeyPermitted() {
+ // RSA encryption with no padding using private key is is a way to implement raw RSA
+ // signatures. We have to support this.
+ return true;
+ }
+
+ @Override
protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
@Override
@@ -152,8 +159,11 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
paddedInput.length - bufferedInput.length,
bufferedInput.length);
} else {
- // No need to pad input
- paddedInput = bufferedInput;
+ // RI throws BadPaddingException in this scenario. INVALID_ARGUMENT below will
+ // be translated into BadPaddingException.
+ throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT,
+ "Message size (" + bufferedInput.length + " bytes) must be smaller than"
+ + " modulus (" + mModulusSizeBytes + " bytes)");
}
return mDelegate.doFinal(paddedInput, 0, paddedInput.length);
}
@@ -412,14 +422,46 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
if (keystoreKey instanceof PrivateKey) {
- if ((opmode != Cipher.DECRYPT_MODE) && (opmode != Cipher.UNWRAP_MODE)) {
- throw new InvalidKeyException("Private key cannot be used with opmode: " + opmode
- + ". Only DECRYPT_MODE and UNWRAP_MODE supported");
+ // Private key
+ switch (opmode) {
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ // Permitted
+ break;
+ case Cipher.ENCRYPT_MODE:
+ if (!isEncryptingUsingPrivateKeyPermitted()) {
+ throw new InvalidKeyException(
+ "RSA private keys cannot be used with Cipher.ENCRYPT_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;
+ 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:
+ throw new InvalidKeyException(
+ "RSA private keys cannot be used with opmode: " + opmode);
}
} else {
- if ((opmode != Cipher.ENCRYPT_MODE) && (opmode != Cipher.WRAP_MODE)) {
- throw new InvalidKeyException("Public key cannot be used with opmode: " + opmode
- + ". Only ENCRYPT_MODE and WRAP_MODE supported");
+ // Public key
+ switch (opmode) {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ // Permitted
+ return;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ throw new InvalidKeyException("RSA public keys cannot be used with opmode: "
+ + opmode + ". Only RSA private keys supported for this opmode.");
+ // break;
+ default:
+ throw new InvalidKeyException(
+ "RSA public keys cannot be used with opmode: " + opmode);
}
}
@@ -438,6 +480,10 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
setKey(keystoreKey);
}
+ protected boolean isEncryptingUsingPrivateKeyPermitted() {
+ return false;
+ }
+
@Override
protected final void resetAll() {
mModulusSizeBytes = -1;
@@ -454,6 +500,13 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
@NonNull KeymasterArguments keymasterArgs) {
keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
keymasterArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
+ int purposeOverride = getKeymasterPurposeOverride();
+ if ((purposeOverride != -1)
+ && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
+ || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) {
+ // Keymaster sign/verify requires digest to be specified. For raw sign/verify it's NONE.
+ keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
+ }
}
@Override