/** * Returns the value attached to a provider property. * * <p>Supports aliases, i.e. if there is no property named type.name but one named * Alg.Alias.type.name, the value of Alg.Alias.type.name is assumed to be the <b>name</b> of the * actual property. * * @param provider JCE provider * @param type type (Cipher, Algorithm, ...) * @param name transformation * @return the properties value which usually is the implementing class'es name */ private static String resolveProperty( final Provider provider, final String type, final String name) { if (Provider.getProperty(type + "." + name) != null) return Provider.getProperty(type + "." + name); else if (Provider.getProperty("Alg.Alias." + type + "." + name) != null) return resolveProperty( provider, type, Provider.getProperty("Alg.Alias." + type + "." + name)); else return null; }
/** * Replacement for JCA/JCE's {@link javax.crypto.Cipher#getInstance}. The original method only * accepts JCE providers from signed jars, which prevents us from bundling our cryptography * provider Bouncy Caster with the application. * * @param transformation the transformation to find an implementation for */ public static Cipher getCipher(final String transformation) { try { /* Split the transformation into algorithm, mode and padding */ final Matcher transformation_matcher = s_transformation_pattern.matcher(transformation.toUpperCase()); if (!transformation_matcher.matches()) throw new RuntimeException("Transformation " + transformation + " is invalid"); final String algorithm = transformation_matcher.group(1); final String mode = transformation_matcher.group(3); final String padding = transformation_matcher.group(4); final boolean isBareAlgorithm = (mode == null) && (padding == null); /* Build the property values we need to search for. */ final String algorithmModePadding = !isBareAlgorithm ? algorithm + "/" + mode + "/" + padding : null; final String algorithmMode = !isBareAlgorithm ? algorithm + "/" + mode : null; final String algorithmPadding = !isBareAlgorithm ? algorithm + "//" + padding : null; /* Search the provider for implementations. We ask for more specific (i.e matching * the requested mode and or padding) implementation first, then fall back to more * generals ones which we then must configure for the mode and padding. */ final CipherSpi cipherSpi; if (!isBareAlgorithm && (resolveProperty(Provider, "Cipher", algorithmModePadding) != null)) { @SuppressWarnings("unchecked") final Class<? extends CipherSpi> cipherSpiClass = (Class<? extends CipherSpi>) Class.forName(resolveProperty(Provider, "Cipher", algorithmModePadding)); cipherSpi = cipherSpiClass.newInstance(); } else if (!isBareAlgorithm && (resolveProperty(Provider, "Cipher", algorithmMode) != null)) { @SuppressWarnings("unchecked") final Class<? extends CipherSpi> cipherSpiClass = (Class<? extends CipherSpi>) Class.forName(resolveProperty(Provider, "Cipher", algorithmMode)); cipherSpi = cipherSpiClass.newInstance(); if (!isBareAlgorithm) cipherSpiSetPadding(cipherSpi, padding); } else if (!isBareAlgorithm && (resolveProperty(Provider, "Cipher", algorithmPadding) != null)) { @SuppressWarnings("unchecked") final Class<? extends CipherSpi> cipherSpiClass = (Class<? extends CipherSpi>) Class.forName(resolveProperty(Provider, "Cipher", algorithmPadding)); cipherSpi = cipherSpiClass.newInstance(); if (!isBareAlgorithm) cipherSpiSetMode(cipherSpi, mode); } else if (resolveProperty(Provider, "Cipher", algorithm) != null) { @SuppressWarnings("unchecked") final Class<? extends CipherSpi> cipherSpiClass = (Class<? extends CipherSpi>) Class.forName(resolveProperty(Provider, "Cipher", algorithm)); cipherSpi = cipherSpiClass.newInstance(); if (!isBareAlgorithm) { cipherSpiSetMode(cipherSpi, mode); cipherSpiSetPadding(cipherSpi, padding); } } else { throw new RuntimeException( "Provider " + Provider.getName() + " (" + Provider.getClass() + ") does not implement " + transformation); } /* Create a {@link javax.crypto.Cipher} instance from the {@link javax.crypto.CipherSpi} the provider gave us */ s_logger.info("Using SPI " + cipherSpi.getClass() + " for " + transformation); return getCipher(cipherSpi, transformation.toUpperCase()); } catch (final RuntimeException e) { throw e; } catch (final Error e) { throw e; } catch (final Throwable e) { throw new RuntimeException( "Provider " + Provider.getName() + " (" + Provider.getClass() + ") failed to instanciate " + transformation, e); } }