Cipher: always select a SPI in init according to the parameters
Behaviour before this CL was to avoid selecting a SPI if there
was a previously selected one. That is an incompatibility wrt M.
This CL makes Cipher compatible with the M behaviour
(cherry picked from commit 264d21f1e86e7ec7976fc5346c21a8e17d8635b1)
Bug: 29038928
Change-Id: Iad68ec2c1eca99c4e98f5179429498cff9b42c36
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 13c9ceb..cc5376a 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -3902,4 +3902,111 @@
}
}
+ /**
+ * http://b/29038928
+ * If in a second call to init the current spi doesn't support the new specified key, look for
+ * another suitable spi.
+ */
+ public void test_init_onKeyTypeChange_reInitCipher() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes.class.getName());
+ }
+ };
+ Provider mockProvider2 = new MockProvider("MockProvider2") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes2.class.getName());
+ }
+ };
+ try {
+ Security.addProvider(mockProvider);
+ Security.addProvider(mockProvider2);
+ Cipher cipher = Cipher.getInstance("FOO");
+ cipher.init(Cipher.ENCRYPT_MODE, new MockKey());
+ assertEquals("MockProvider", cipher.getProvider().getName());
+ // Using a different key...
+ cipher.init(Cipher.ENCRYPT_MODE, new MockKey2());
+ // ...results in a different provider.
+ assertEquals("MockProvider2", cipher.getProvider().getName());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ Security.removeProvider(mockProvider2.getName());
+ }
+ }
+
+ /**
+ * http://b/29038928
+ * If in a second call to init the current spi doesn't support the new specified
+ * {@link AlgorithmParameterSpec}, look for another suitable spi.
+ */
+ public void test_init_onAlgorithmParameterTypeChange_reInitCipher() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.SpecificAlgorithmParameterSpecTypes.class.getName());
+ }
+ };
+ Provider mockProvider2 = new MockProvider("MockProvider2") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.SpecificAlgorithmParameterSpecTypes2.class.getName());
+ }
+ };
+ try {
+ Security.addProvider(mockProvider);
+ Security.addProvider(mockProvider2);
+ Cipher cipher = Cipher.getInstance("FOO");
+ cipher.init(Cipher.ENCRYPT_MODE,
+ new MockKey(),
+ new MockCipherSpi.MockAlgorithmParameterSpec());
+ assertEquals("MockProvider", cipher.getProvider().getName());
+ // Using a different AlgorithmParameterSpec...
+ cipher.init(Cipher.ENCRYPT_MODE,
+ new MockKey(),
+ new MockCipherSpi.MockAlgorithmParameterSpec2());
+ // ...results in a different provider.
+ assertEquals("MockProvider2", cipher.getProvider().getName());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ Security.removeProvider(mockProvider2.getName());
+ }
+ }
+
+ /**
+ * http://b/29038928
+ * If in a second call to init the current spi doesn't support the new specified
+ * {@link AlgorithmParameters}, look for another suitable spi.
+ */
+ public void test_init_onAlgorithmParametersChange_reInitCipher() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.SpecificAlgorithmParameterAesAlgorithm.class.getName());
+ }
+ };
+ Provider mockProvider2 = new MockProvider("MockProvider2") {
+ public void setup() {
+ put("Cipher.FOO",
+ MockCipherSpi.SpecificAlgorithmParametersDesAlgorithm.class.getName());
+ }
+ };
+ try {
+ Security.addProvider(mockProvider);
+ Security.addProvider(mockProvider2);
+ Cipher cipher = Cipher.getInstance("FOO");
+ cipher.init(Cipher.ENCRYPT_MODE,
+ new MockKey(),
+ AlgorithmParameters.getInstance("AES"));
+ assertEquals("MockProvider", cipher.getProvider().getName());
+ // Using a different AlgorithmParameters...
+ cipher.init(Cipher.ENCRYPT_MODE,
+ new MockKey(),
+ AlgorithmParameters.getInstance("DES"));
+ // ...results in a different provider.
+ assertEquals("MockProvider2", cipher.getProvider().getName());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ Security.removeProvider(mockProvider2.getName());
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
index c1b1bd2..0fd2aaa 100644
--- a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
+++ b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
@@ -54,6 +54,48 @@
}
}
+ public static class SpecificAlgorithmParameterSpecTypes extends MockCipherSpi {
+ @Override
+ public void checkAlgorithmParameterSpec(AlgorithmParameterSpec aps)
+ throws InvalidAlgorithmParameterException {
+ if (!(aps instanceof MockAlgorithmParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("Must be "
+ + MockAlgorithmParameterSpec.class.getName());
+ }
+ }
+ }
+
+ public static class SpecificAlgorithmParameterSpecTypes2 extends MockCipherSpi {
+ @Override
+ public void checkAlgorithmParameterSpec(AlgorithmParameterSpec aps)
+ throws InvalidAlgorithmParameterException {
+ if (!(aps instanceof MockAlgorithmParameterSpec2)) {
+ throw new InvalidAlgorithmParameterException("Must be "
+ + MockAlgorithmParameterSpec2.class.getName());
+ }
+ }
+ }
+
+ public static class SpecificAlgorithmParameterAesAlgorithm extends MockCipherSpi {
+ @Override
+ public void checkAlgorithmParameters(AlgorithmParameters ap)
+ throws InvalidAlgorithmParameterException {
+ if (!ap.getAlgorithm().equals("AES")) {
+ throw new InvalidAlgorithmParameterException("Must be AES");
+ }
+ }
+ }
+
+ public static class SpecificAlgorithmParametersDesAlgorithm extends MockCipherSpi {
+ @Override
+ public void checkAlgorithmParameters(AlgorithmParameters ap)
+ throws InvalidAlgorithmParameterException {
+ if ((!ap.getAlgorithm().equals("DES"))) {
+ throw new InvalidAlgorithmParameterException("Must be DES");
+ }
+ }
+ }
+
public static class AllKeyTypes extends MockCipherSpi {
}
@@ -146,6 +188,15 @@
public void checkKeyType(Key key) throws InvalidKeyException {
}
+ public void checkAlgorithmParameterSpec(AlgorithmParameterSpec aps)
+ throws InvalidAlgorithmParameterException {
+ }
+
+ public void checkAlgorithmParameters(AlgorithmParameters ap)
+ throws InvalidAlgorithmParameterException {
+ }
+
+
@Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if (!"FOO".equals(mode)) {
@@ -189,12 +240,14 @@
protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeyType(key);
+ checkAlgorithmParameterSpec(params);
}
@Override
protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
checkKeyType(key);
+ checkAlgorithmParameters(params);
}
@Override
@@ -220,4 +273,10 @@
BadPaddingException {
throw new UnsupportedOperationException("not implemented");
}
+
+ public static class MockAlgorithmParameterSpec implements AlgorithmParameterSpec {
+ }
+
+ public static class MockAlgorithmParameterSpec2 implements AlgorithmParameterSpec {
+ }
}
diff --git a/ojluni/src/main/java/javax/crypto/Cipher.java b/ojluni/src/main/java/javax/crypto/Cipher.java
index 39dd524..2d9c207 100755
--- a/ojluni/src/main/java/javax/crypto/Cipher.java
+++ b/ojluni/src/main/java/javax/crypto/Cipher.java
@@ -1195,15 +1195,11 @@
initialized = false;
checkOpmode(opmode);
- if (spi != null && (key == null)) {
- spi.engineInit(opmode, key, random);
- } else {
- try {
- chooseProvider(InitType.KEY, opmode, key, null, null, random);
- } catch (InvalidAlgorithmParameterException e) {
- // should never occur
- throw new InvalidKeyException(e);
- }
+ try {
+ chooseProvider(InitType.KEY, opmode, key, null, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // should never occur
+ throw new InvalidKeyException(e);
}
initialized = true;
@@ -1330,11 +1326,7 @@
initialized = false;
checkOpmode(opmode);
- if (spi != null) {
- spi.engineInit(opmode, key, params, random);
- } else {
- chooseProvider(InitType.ALGORITHM_PARAM_SPEC, opmode, key, params, null, random);
- }
+ chooseProvider(InitType.ALGORITHM_PARAM_SPEC, opmode, key, params, null, random);
initialized = true;
this.opmode = opmode;
@@ -1460,11 +1452,7 @@
initialized = false;
checkOpmode(opmode);
- if (spi != null) {
- spi.engineInit(opmode, key, params, random);
- } else {
- chooseProvider(InitType.ALGORITHM_PARAMS, opmode, key, null, params, random);
- }
+ chooseProvider(InitType.ALGORITHM_PARAMS, opmode, key, null, params, random);
initialized = true;
this.opmode = opmode;
@@ -1599,8 +1587,7 @@
*/
public final void init(int opmode, Certificate certificate,
SecureRandom random)
- throws InvalidKeyException
- {
+ throws InvalidKeyException {
initialized = false;
checkOpmode(opmode);
@@ -1609,38 +1596,34 @@
if (certificate instanceof java.security.cert.X509Certificate) {
// Check whether the cert has a key usage extension
// marked as a critical extension.
- X509Certificate cert = (X509Certificate)certificate;
+ X509Certificate cert = (X509Certificate) certificate;
Set critSet = cert.getCriticalExtensionOIDs();
if (critSet != null && !critSet.isEmpty()
- && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
+ && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
boolean[] keyUsageInfo = cert.getKeyUsage();
// keyUsageInfo[2] is for keyEncipherment;
// keyUsageInfo[3] is for dataEncipherment.
if ((keyUsageInfo != null) &&
- (((opmode == Cipher.ENCRYPT_MODE) &&
- (keyUsageInfo.length > 3) &&
- (keyUsageInfo[3] == false)) ||
- ((opmode == Cipher.WRAP_MODE) &&
- (keyUsageInfo.length > 2) &&
- (keyUsageInfo[2] == false)))) {
+ (((opmode == Cipher.ENCRYPT_MODE) &&
+ (keyUsageInfo.length > 3) &&
+ (keyUsageInfo[3] == false)) ||
+ ((opmode == Cipher.WRAP_MODE) &&
+ (keyUsageInfo.length > 2) &&
+ (keyUsageInfo[2] == false)))) {
throw new InvalidKeyException("Wrong key usage");
}
}
}
PublicKey publicKey =
- (certificate==null? null:certificate.getPublicKey());
+ (certificate == null ? null : certificate.getPublicKey());
- if (spi != null) {
- spi.engineInit(opmode, publicKey, random);
- } else {
- try {
- chooseProvider(InitType.KEY, opmode, (Key)publicKey, null, null, random);
- } catch (InvalidAlgorithmParameterException e) {
- // should never occur
- throw new InvalidKeyException(e);
- }
+ try {
+ chooseProvider(InitType.KEY, opmode, (Key) publicKey, null, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // should never occur
+ throw new InvalidKeyException(e);
}
initialized = true;