Merge "Late binding: supplied Provider should be used"
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index 6299f80..91789b4 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -397,50 +397,65 @@
private static Engine.SpiAndProvider tryTransform(Key key, Provider provider, String transform,
String[] transformParts, NeedToSet type) {
- Engine.SpiAndProvider sap;
- ArrayList<Provider.Service> services = ENGINE.getServices(transform, provider);
+ if (provider != null) {
+ Provider.Service service = provider.getService(SERVICE, transform);
+ if (service == null) {
+ return null;
+ }
+ return tryTransformWithProvider(key, transformParts, type, service);
+ }
+ ArrayList<Provider.Service> services = ENGINE.getServices(transform);
if (services == null) {
return null;
}
for (Provider.Service service : services) {
- try {
- if (key != null && !service.supportsParameter(key)) {
- continue;
- }
-
- /*
- * Check to see if the Cipher even supports the attributes
- * before trying to instantiate it.
- */
- if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1])
- || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) {
- continue;
- }
-
- sap = ENGINE.getInstance(service, null);
- if (sap.spi == null || sap.provider == null) {
- continue;
- }
- if (!(sap.spi instanceof CipherSpi)) {
- continue;
- }
- CipherSpi spi = (CipherSpi) sap.spi;
- if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
- && (transformParts[1] != null)) {
- spi.engineSetMode(transformParts[1]);
- }
- if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH))
- && (transformParts[2] != null)) {
- spi.engineSetPadding(transformParts[2]);
- }
+ Engine.SpiAndProvider sap = tryTransformWithProvider(key, transformParts, type, service);
+ if (sap != null) {
return sap;
- } catch (NoSuchAlgorithmException ignored) {
- } catch (NoSuchPaddingException ignored) {
}
}
return null;
}
+ private static Engine.SpiAndProvider tryTransformWithProvider(Key key, String[] transformParts,
+ NeedToSet type, Provider.Service service) {
+ try {
+ if (key != null && !service.supportsParameter(key)) {
+ return null;
+ }
+
+ /*
+ * Check to see if the Cipher even supports the attributes before
+ * trying to instantiate it.
+ */
+ if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1])
+ || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) {
+ return null;
+ }
+
+ Engine.SpiAndProvider sap = ENGINE.getInstance(service, null);
+ if (sap.spi == null || sap.provider == null) {
+ return sap;
+ }
+ if (!(sap.spi instanceof CipherSpi)) {
+ return sap;
+ }
+ CipherSpi spi = (CipherSpi) sap.spi;
+ if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
+ && (transformParts[1] != null)) {
+ spi.engineSetMode(transformParts[1]);
+ }
+ if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH))
+ && (transformParts[2] != null)) {
+ spi.engineSetPadding(transformParts[2]);
+ }
+ return sap;
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (NoSuchPaddingException ignored) {
+ }
+ return null;
+ }
+
/**
* If the attribute listed exists, check that it matches the regular
* expression.
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index b9954bc..006dda8 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -26,7 +26,6 @@
import java.security.Provider;
import java.util.ArrayList;
import java.util.Locale;
-import java.util.Objects;
/**
* This class implements common functionality for Provider supplied
@@ -93,19 +92,15 @@
private static final class ServiceCacheEntry {
/** used to test for cache hit */
private final String algorithm;
- /** used to test for cache hit */
- private final Provider provider;
/** used to test for cache validity */
private final int cacheVersion;
/** cached result */
private final ArrayList<Provider.Service> services;
private ServiceCacheEntry(String algorithm,
- Provider provider,
int cacheVersion,
ArrayList<Provider.Service> services) {
this.algorithm = algorithm;
- this.provider = provider;
this.cacheVersion = cacheVersion;
this.services = services;
}
@@ -139,7 +134,7 @@
if (algorithm == null) {
throw new NoSuchAlgorithmException("Null algorithm name");
}
- ArrayList<Provider.Service> services = getServices(algorithm, null);
+ ArrayList<Provider.Service> services = getServices(algorithm);
if (services == null) {
throw notFound(this.serviceName, algorithm);
}
@@ -159,32 +154,19 @@
/**
* Returns a list of all possible matches for a given algorithm.
*/
- public ArrayList<Provider.Service> getServices(String algorithm, Provider provider) {
+ public ArrayList<Provider.Service> getServices(String algorithm) {
int newCacheVersion = Services.getCacheVersion();
ServiceCacheEntry cacheEntry = this.serviceCache;
final String algoUC = algorithm.toUpperCase(Locale.US);
if (cacheEntry != null
&& cacheEntry.algorithm.equalsIgnoreCase(algoUC)
- && Objects.equals(cacheEntry.provider, provider)
&& newCacheVersion == cacheEntry.cacheVersion) {
return cacheEntry.services;
}
String name = this.serviceName + "." + algoUC;
ArrayList<Provider.Service> services = Services.getServices(name);
- if (provider == null || services == null) {
- this.serviceCache = new ServiceCacheEntry(algoUC, provider, newCacheVersion, services);
- return services;
- }
- ArrayList<Provider.Service> filteredServices = new ArrayList<Provider.Service>(
- services.size());
- for (Provider.Service service : services) {
- if (provider.equals(service.getProvider())) {
- filteredServices.add(service);
- }
- }
- this.serviceCache = new ServiceCacheEntry(algoUC, provider, newCacheVersion,
- filteredServices);
- return filteredServices;
+ this.serviceCache = new ServiceCacheEntry(algoUC, newCacheVersion, services);
+ return services;
}
/**
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index b9241c0..21cc5da 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -26,6 +26,7 @@
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
@@ -832,6 +833,59 @@
public abstract void setup();
}
+ public void testCipher_getInstance_SuppliedProviderNotRegistered_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ {
+ Cipher c = Cipher.getInstance("FOO", mockProvider);
+ c.init(Cipher.ENCRYPT_MODE, new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ }
+ }
+
+ public void testCipher_getInstance_SuppliedProviderNotRegistered_MultipartTransform_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ {
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO", mockProvider);
+ c.init(Cipher.ENCRYPT_MODE, new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ }
+ }
+
+ public void testCipher_getInstance_OnlyUsesSpecifiedProvider_SameNameAndClass_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ {
+ Provider mockProvider2 = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+ Cipher c = Cipher.getInstance("FOO", mockProvider2);
+ assertEquals(mockProvider2, c.getProvider());
+ }
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testCipher_getInstance_DelayedInitialization_KeyType() throws Exception {
Provider mockProviderSpecific = new MockProvider("MockProviderSpecific") {
public void setup() {
diff --git a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
index b09d883..eb950cc 100644
--- a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
+++ b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java
@@ -51,12 +51,16 @@
@Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
- throw new UnsupportedOperationException("not implemented");
+ if (!"FOO".equals(mode)) {
+ throw new UnsupportedOperationException("not implemented");
+ }
}
@Override
protected void engineSetPadding(String padding) throws NoSuchPaddingException {
- throw new UnsupportedOperationException("not implemented");
+ if (!"FOO".equals(padding)) {
+ throw new UnsupportedOperationException("not implemented");
+ }
}
@Override