|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  |  | 
|  | package java.security; | 
|  |  | 
|  | import java.util.*; | 
|  |  | 
|  | import java.security.spec.AlgorithmParameterSpec; | 
|  |  | 
|  | import java.security.Provider.Service; | 
|  |  | 
|  | import sun.security.jca.*; | 
|  | import sun.security.jca.GetInstance.Instance; | 
|  | import sun.security.util.Debug; | 
|  |  | 
|  | /** | 
|  |  * The KeyPairGenerator class is used to generate pairs of | 
|  |  * public and private keys. Key pair generators are constructed using the | 
|  |  * {@code getInstance} factory methods (static methods that | 
|  |  * return instances of a given class). | 
|  |  * | 
|  |  * <p>A Key pair generator for a particular algorithm creates a public/private | 
|  |  * key pair that can be used with this algorithm. It also associates | 
|  |  * algorithm-specific parameters with each of the generated keys. | 
|  |  * | 
|  |  * <p>There are two ways to generate a key pair: in an algorithm-independent | 
|  |  * manner, and in an algorithm-specific manner. | 
|  |  * The only difference between the two is the initialization of the object: | 
|  |  * | 
|  |  * <ul> | 
|  |  * <li><b>Algorithm-Independent Initialization</b> | 
|  |  * <p>All key pair generators share the concepts of a keysize and a | 
|  |  * source of randomness. The keysize is interpreted differently for different | 
|  |  * algorithms (e.g., in the case of the <i>DSA</i> algorithm, the keysize | 
|  |  * corresponds to the length of the modulus). | 
|  |  * There is an | 
|  |  * {@link #initialize(int, java.security.SecureRandom) initialize} | 
|  |  * method in this KeyPairGenerator class that takes these two universally | 
|  |  * shared types of arguments. There is also one that takes just a | 
|  |  * {@code keysize} argument, and uses the {@code SecureRandom} | 
|  |  * implementation of the highest-priority installed provider as the source | 
|  |  * of randomness. (If none of the installed providers supply an implementation | 
|  |  * of {@code SecureRandom}, a system-provided source of randomness is | 
|  |  * used.) | 
|  |  * | 
|  |  * <p>Since no other parameters are specified when you call the above | 
|  |  * algorithm-independent {@code initialize} methods, it is up to the | 
|  |  * provider what to do about the algorithm-specific parameters (if any) to be | 
|  |  * associated with each of the keys. | 
|  |  * | 
|  |  * <p>If the algorithm is the <i>DSA</i> algorithm, and the keysize (modulus | 
|  |  * size) is 512, 768, 1024, or 2048, then the <i>Sun</i> provider uses a set of | 
|  |  * precomputed values for the {@code p}, {@code q}, and | 
|  |  * {@code g} parameters. If the modulus size is not one of the above | 
|  |  * values, the <i>Sun</i> provider creates a new set of parameters. Other | 
|  |  * providers might have precomputed parameter sets for more than just the | 
|  |  * modulus sizes mentioned above. Still others might not have a list of | 
|  |  * precomputed parameters at all and instead always create new parameter sets. | 
|  |  * | 
|  |  * <li><b>Algorithm-Specific Initialization</b> | 
|  |  * <p>For situations where a set of algorithm-specific parameters already | 
|  |  * exists (e.g., so-called <i>community parameters</i> in DSA), there are two | 
|  |  * {@link #initialize(java.security.spec.AlgorithmParameterSpec) | 
|  |  * initialize} methods that have an {@code AlgorithmParameterSpec} | 
|  |  * argument. One also has a {@code SecureRandom} argument, while | 
|  |  * the other uses the {@code SecureRandom} | 
|  |  * implementation of the highest-priority installed provider as the source | 
|  |  * of randomness. (If none of the installed providers supply an implementation | 
|  |  * of {@code SecureRandom}, a system-provided source of randomness is | 
|  |  * used.) | 
|  |  * </ul> | 
|  |  * | 
|  |  * <p>In case the client does not explicitly initialize the KeyPairGenerator | 
|  |  * (via a call to an {@code initialize} method), each provider must | 
|  |  * supply (and document) a default initialization. | 
|  |  * See the Keysize Restriction sections of the | 
|  |  * {@extLink security_guide_jdk_providers JDK Providers} | 
|  |  * document for information on the KeyPairGenerator defaults used by | 
|  |  * JDK providers. | 
|  |  * However, note that defaults may vary across different providers. | 
|  |  * Additionally, the default value for a provider may change in a future | 
|  |  * version. Therefore, it is recommended to explicitly initialize the | 
|  |  * KeyPairGenerator instead of relying on provider-specific defaults. | 
|  |  * | 
|  |  * <p>Note that this class is abstract and extends from | 
|  |  * {@code KeyPairGeneratorSpi} for historical reasons. | 
|  |  * Application developers should only take notice of the methods defined in | 
|  |  * this {@code KeyPairGenerator} class; all the methods in | 
|  |  * the superclass are intended for cryptographic service providers who wish to | 
|  |  * supply their own implementations of key pair generators. | 
|  |  * | 
|  |  * <p> Every implementation of the Java platform is required to support the | 
|  |  * following standard {@code KeyPairGenerator} algorithms and keysizes in | 
|  |  * parentheses: | 
|  |  * <ul> | 
|  |  * <li>{@code DiffieHellman} (1024, 2048, 4096)</li> | 
|  |  * <li>{@code DSA} (1024, 2048)</li> | 
|  |  * <li>{@code RSA} (1024, 2048, 4096)</li> | 
|  |  * </ul> | 
|  |  * These algorithms are described in the <a href= | 
|  |  * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms"> | 
|  |  * KeyPairGenerator section</a> of the | 
|  |  * Java Security Standard Algorithm Names Specification. | 
|  |  * Consult the release documentation for your implementation to see if any | 
|  |  * other algorithms are supported. | 
|  |  * | 
|  |  * @author Benjamin Renaud | 
|  |  * @since 1.1 | 
|  |  * | 
|  |  * @see java.security.spec.AlgorithmParameterSpec | 
|  |  */ | 
|  |  | 
|  | public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { | 
|  |  | 
|  |     private static final Debug pdebug = | 
|  |                         Debug.getInstance("provider", "Provider"); | 
|  |     private static final boolean skipDebug = | 
|  |         Debug.isOn("engine=") && !Debug.isOn("keypairgenerator"); | 
|  |  | 
|  |     private final String algorithm; | 
|  |  | 
|  |      | 
|  |     Provider provider; | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     protected KeyPairGenerator(String algorithm) { | 
|  |         this.algorithm = algorithm; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public String getAlgorithm() { | 
|  |         return this.algorithm; | 
|  |     } | 
|  |  | 
|  |     private static KeyPairGenerator getInstance(Instance instance, | 
|  |             String algorithm) { | 
|  |         KeyPairGenerator kpg; | 
|  |         if (instance.impl instanceof KeyPairGenerator) { | 
|  |             kpg = (KeyPairGenerator)instance.impl; | 
|  |         } else { | 
|  |             KeyPairGeneratorSpi spi = (KeyPairGeneratorSpi)instance.impl; | 
|  |             kpg = new Delegate(spi, algorithm); | 
|  |         } | 
|  |         kpg.provider = instance.provider; | 
|  |  | 
|  |         if (!skipDebug && pdebug != null) { | 
|  |             pdebug.println("KeyPairGenerator." + algorithm + | 
|  |                 " algorithm from: " + kpg.provider.getName()); | 
|  |         } | 
|  |  | 
|  |         return kpg; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public static KeyPairGenerator getInstance(String algorithm) | 
|  |             throws NoSuchAlgorithmException { | 
|  |         Objects.requireNonNull(algorithm, "null algorithm name"); | 
|  |         List<Service> list = | 
|  |                 GetInstance.getServices("KeyPairGenerator", algorithm); | 
|  |         Iterator<Service> t = list.iterator(); | 
|  |         if (t.hasNext() == false) { | 
|  |             throw new NoSuchAlgorithmException | 
|  |                 (algorithm + " KeyPairGenerator not available"); | 
|  |         } | 
|  |          | 
|  |         NoSuchAlgorithmException failure = null; | 
|  |         do { | 
|  |             Service s = t.next(); | 
|  |             try { | 
|  |                 Instance instance = | 
|  |                     GetInstance.getInstance(s, KeyPairGeneratorSpi.class); | 
|  |                 if (instance.impl instanceof KeyPairGenerator) { | 
|  |                     return getInstance(instance, algorithm); | 
|  |                 } else { | 
|  |                     return new Delegate(instance, t, algorithm); | 
|  |                 } | 
|  |             } catch (NoSuchAlgorithmException e) { | 
|  |                 if (failure == null) { | 
|  |                     failure = e; | 
|  |                 } | 
|  |             } | 
|  |         } while (t.hasNext()); | 
|  |         throw failure; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public static KeyPairGenerator getInstance(String algorithm, | 
|  |             String provider) | 
|  |             throws NoSuchAlgorithmException, NoSuchProviderException { | 
|  |         Objects.requireNonNull(algorithm, "null algorithm name"); | 
|  |         Instance instance = GetInstance.getInstance("KeyPairGenerator", | 
|  |                 KeyPairGeneratorSpi.class, algorithm, provider); | 
|  |         return getInstance(instance, algorithm); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public static KeyPairGenerator getInstance(String algorithm, | 
|  |             Provider provider) throws NoSuchAlgorithmException { | 
|  |         Objects.requireNonNull(algorithm, "null algorithm name"); | 
|  |         Instance instance = GetInstance.getInstance("KeyPairGenerator", | 
|  |                 KeyPairGeneratorSpi.class, algorithm, provider); | 
|  |         return getInstance(instance, algorithm); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public final Provider getProvider() { | 
|  |         disableFailover(); | 
|  |         return this.provider; | 
|  |     } | 
|  |  | 
|  |     void disableFailover() { | 
|  |         // empty, overridden in Delegate | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void initialize(int keysize) { | 
|  |         initialize(keysize, JCAUtil.getDefSecureRandom()); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void initialize(int keysize, SecureRandom random) { | 
|  |         // This does nothing, because either | 
|  |         // 1. the implementation object returned by getInstance() is an | 
|  |         //    instance of KeyPairGenerator which has its own | 
|  |         //    initialize(keysize, random) method, so the application would | 
|  |         //    be calling that method directly, or | 
|  |         // 2. the implementation returned by getInstance() is an instance | 
|  |         //    of Delegate, in which case initialize(keysize, random) is | 
|  |         //    overridden to call the corresponding SPI method. | 
|  |         // (This is a special case, because the API and SPI method have the | 
|  |         // same name.) | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void initialize(AlgorithmParameterSpec params) | 
|  |             throws InvalidAlgorithmParameterException { | 
|  |         initialize(params, JCAUtil.getDefSecureRandom()); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void initialize(AlgorithmParameterSpec params, | 
|  |                            SecureRandom random) | 
|  |         throws InvalidAlgorithmParameterException | 
|  |     { | 
|  |         // This does nothing, because either | 
|  |         // 1. the implementation object returned by getInstance() is an | 
|  |         //    instance of KeyPairGenerator which has its own | 
|  |         //    initialize(params, random) method, so the application would | 
|  |         //    be calling that method directly, or | 
|  |         // 2. the implementation returned by getInstance() is an instance | 
|  |         //    of Delegate, in which case initialize(params, random) is | 
|  |         //    overridden to call the corresponding SPI method. | 
|  |         // (This is a special case, because the API and SPI method have the | 
|  |         // same name.) | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public final KeyPair genKeyPair() { | 
|  |         return generateKeyPair(); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public KeyPair generateKeyPair() { | 
|  |         // This does nothing (except returning null), because either: | 
|  |         // | 
|  |         // 1. the implementation object returned by getInstance() is an | 
|  |         //    instance of KeyPairGenerator which has its own implementation | 
|  |         //    of generateKeyPair (overriding this one), so the application | 
|  |         //    would be calling that method directly, or | 
|  |         // | 
|  |         // 2. the implementation returned by getInstance() is an instance | 
|  |         //    of Delegate, in which case generateKeyPair is | 
|  |         //    overridden to invoke the corresponding SPI method. | 
|  |         // | 
|  |         // (This is a special case, because in JDK 1.1.x the generateKeyPair | 
|  |          | 
|  |         return null; | 
|  |     } | 
|  |  | 
|  |  | 
|  |     /* | 
|  |      * The following class allows providers to extend from KeyPairGeneratorSpi | 
|  |      * rather than from KeyPairGenerator. It represents a KeyPairGenerator | 
|  |      * with an encapsulated, provider-supplied SPI object (of type | 
|  |      * KeyPairGeneratorSpi). | 
|  |      * If the provider implementation is an instance of KeyPairGeneratorSpi, | 
|  |      * the getInstance() methods above return an instance of this class, with | 
|  |      * the SPI object encapsulated. | 
|  |      * | 
|  |      * Note: All SPI methods from the original KeyPairGenerator class have been | 
|  |      * moved up the hierarchy into a new class (KeyPairGeneratorSpi), which has | 
|  |      * been interposed in the hierarchy between the API (KeyPairGenerator) | 
|  |      * and its original parent (Object). | 
|  |      */ | 
|  |  | 
|  |     // | 
|  |     // error failover notes: | 
|  |     // | 
|  |     //  . we failover if the implementation throws an error during init | 
|  |     //    by retrying the init on other providers | 
|  |     // | 
|  |     //  . we also failover if the init succeeded but the subsequent call | 
|  |     //    to generateKeyPair() fails. In order for this to work, we need | 
|  |     //    to remember the parameters to the last successful call to init | 
|  |     //    and initialize() the next spi using them. | 
|  |     // | 
|  |     //  . although not specified, KeyPairGenerators could be thread safe, | 
|  |     //    so we make sure we do not interfere with that | 
|  |     // | 
|  |     //  . failover is not available, if: | 
|  |     //    . getInstance(algorithm, provider) was used | 
|  |     //    . a provider extends KeyPairGenerator rather than | 
|  |     //      KeyPairGeneratorSpi (JDK 1.1 style) | 
|  |     //    . once getProvider() is called | 
|  |     // | 
|  |  | 
|  |     private static final class Delegate extends KeyPairGenerator { | 
|  |  | 
|  |          | 
|  |         private volatile KeyPairGeneratorSpi spi; | 
|  |  | 
|  |         private final Object lock = new Object(); | 
|  |  | 
|  |         private Iterator<Service> serviceIterator; | 
|  |  | 
|  |         private static final int I_NONE   = 1; | 
|  |         private static final int I_SIZE   = 2; | 
|  |         private static final int I_PARAMS = 3; | 
|  |  | 
|  |         private int initType; | 
|  |         private int initKeySize; | 
|  |         private AlgorithmParameterSpec initParams; | 
|  |         private SecureRandom initRandom; | 
|  |  | 
|  |          | 
|  |         Delegate(KeyPairGeneratorSpi spi, String algorithm) { | 
|  |             super(algorithm); | 
|  |             this.spi = spi; | 
|  |         } | 
|  |  | 
|  |         Delegate(Instance instance, Iterator<Service> serviceIterator, | 
|  |                 String algorithm) { | 
|  |             super(algorithm); | 
|  |             spi = (KeyPairGeneratorSpi)instance.impl; | 
|  |             provider = instance.provider; | 
|  |             this.serviceIterator = serviceIterator; | 
|  |             initType = I_NONE; | 
|  |  | 
|  |             if (!skipDebug && pdebug != null) { | 
|  |                 pdebug.println("KeyPairGenerator." + algorithm + | 
|  |                     " algorithm from: " + provider.getName()); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |          | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |          */ | 
|  |         private KeyPairGeneratorSpi nextSpi(KeyPairGeneratorSpi oldSpi, | 
|  |                 boolean reinit) { | 
|  |             synchronized (lock) { | 
|  |                 // somebody else did a failover concurrently | 
|  |                  | 
|  |                 if ((oldSpi != null) && (oldSpi != spi)) { | 
|  |                     return spi; | 
|  |                 } | 
|  |                 if (serviceIterator == null) { | 
|  |                     return null; | 
|  |                 } | 
|  |                 while (serviceIterator.hasNext()) { | 
|  |                     Service s = serviceIterator.next(); | 
|  |                     try { | 
|  |                         Object inst = s.newInstance(null); | 
|  |                          | 
|  |                         if (!(inst instanceof KeyPairGeneratorSpi spi)) { | 
|  |                             continue; | 
|  |                         } | 
|  |                         if (inst instanceof KeyPairGenerator) { | 
|  |                             continue; | 
|  |                         } | 
|  |                         if (reinit) { | 
|  |                             if (initType == I_SIZE) { | 
|  |                                 spi.initialize(initKeySize, initRandom); | 
|  |                             } else if (initType == I_PARAMS) { | 
|  |                                 spi.initialize(initParams, initRandom); | 
|  |                             } else if (initType != I_NONE) { | 
|  |                                 throw new AssertionError | 
|  |                                     ("KeyPairGenerator initType: " + initType); | 
|  |                             } | 
|  |                         } | 
|  |                         provider = s.getProvider(); | 
|  |                         this.spi = spi; | 
|  |                         return spi; | 
|  |                     } catch (Exception e) { | 
|  |                         // ignore | 
|  |                     } | 
|  |                 } | 
|  |                 disableFailover(); | 
|  |                 return null; | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         void disableFailover() { | 
|  |             serviceIterator = null; | 
|  |             initType = 0; | 
|  |             initParams = null; | 
|  |             initRandom = null; | 
|  |         } | 
|  |  | 
|  |          | 
|  |         public void initialize(int keysize, SecureRandom random) { | 
|  |             if (serviceIterator == null) { | 
|  |                 spi.initialize(keysize, random); | 
|  |                 return; | 
|  |             } | 
|  |             RuntimeException failure = null; | 
|  |             KeyPairGeneratorSpi mySpi = spi; | 
|  |             do { | 
|  |                 try { | 
|  |                     mySpi.initialize(keysize, random); | 
|  |                     initType = I_SIZE; | 
|  |                     initKeySize = keysize; | 
|  |                     initParams = null; | 
|  |                     initRandom = random; | 
|  |                     return; | 
|  |                 } catch (RuntimeException e) { | 
|  |                     if (failure == null) { | 
|  |                         failure = e; | 
|  |                     } | 
|  |                     mySpi = nextSpi(mySpi, false); | 
|  |                 } | 
|  |             } while (mySpi != null); | 
|  |             throw failure; | 
|  |         } | 
|  |  | 
|  |          | 
|  |         public void initialize(AlgorithmParameterSpec params, | 
|  |                 SecureRandom random) throws InvalidAlgorithmParameterException { | 
|  |             if (serviceIterator == null) { | 
|  |                 spi.initialize(params, random); | 
|  |                 return; | 
|  |             } | 
|  |             Exception failure = null; | 
|  |             KeyPairGeneratorSpi mySpi = spi; | 
|  |             do { | 
|  |                 try { | 
|  |                     mySpi.initialize(params, random); | 
|  |                     initType = I_PARAMS; | 
|  |                     initKeySize = 0; | 
|  |                     initParams = params; | 
|  |                     initRandom = random; | 
|  |                     return; | 
|  |                 } catch (Exception e) { | 
|  |                     if (failure == null) { | 
|  |                         failure = e; | 
|  |                     } | 
|  |                     mySpi = nextSpi(mySpi, false); | 
|  |                 } | 
|  |             } while (mySpi != null); | 
|  |             if (failure instanceof RuntimeException) { | 
|  |                 throw (RuntimeException)failure; | 
|  |             } | 
|  |              | 
|  |             throw (InvalidAlgorithmParameterException)failure; | 
|  |         } | 
|  |  | 
|  |          | 
|  |         public KeyPair generateKeyPair() { | 
|  |             if (serviceIterator == null) { | 
|  |                 return spi.generateKeyPair(); | 
|  |             } | 
|  |             RuntimeException failure = null; | 
|  |             KeyPairGeneratorSpi mySpi = spi; | 
|  |             do { | 
|  |                 try { | 
|  |                     return mySpi.generateKeyPair(); | 
|  |                 } catch (RuntimeException e) { | 
|  |                     if (failure == null) { | 
|  |                         failure = e; | 
|  |                     } | 
|  |                     mySpi = nextSpi(mySpi, true); | 
|  |                 } | 
|  |             } while (mySpi != null); | 
|  |             throw failure; | 
|  |         } | 
|  |     } | 
|  |  | 
|  | } |