2677 lines · 110.0 KB · Java
RawDownload
            Transform tr = getTransform(s, transforms);            if (tr == null) {                // should never happen                continue;            }            int canuse = tr.supportsModePadding(s);            if (canuse == S_NO) {                // does not support mode or padding we need, ignore                continue;            }            if (canuse == S_YES) {                return new Cipher(null, s, t, transformation, transforms);            } else { // S_MAYBE, try out if it works                try {                    CipherSpi spi = (CipherSpi)s.newInstance(null);                    tr.setModePadding(spi);                    return new Cipher(spi, s, t, transformation, transforms);                } catch (Exception e) {                    failure = e;                }            }        }        throw new NoSuchAlgorithmException            ("Cannot find any provider supporting " + transformation, failure);    }     /**     * Returns a <code>Cipher</code> object that implements the specified     * transformation.     *     * <p> A new Cipher object encapsulating the     * CipherSpi implementation from the specified provider     * is returned.  The specified provider must be registered     * in the security provider list.     *     * <p> Note that the list of registered providers may be retrieved via     * the {@link Security#getProviders() Security.getProviders()} method.     *     * @param transformation the name of the transformation,     * e.g., <i>DES/CBC/PKCS5Padding</i>.     * See the Cipher section in the <a href=     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard transformation names.     *     * @param provider the name of the provider.     *     * @return a cipher that implements the requested transformation.     *     * @exception NoSuchAlgorithmException if <code>transformation</code>     *          is null, empty, in an invalid format,     *          or if a CipherSpi implementation for the specified algorithm     *          is not available from the specified provider.     *     * @exception NoSuchProviderException if the specified provider is not     *          registered in the security provider list.     *     * @exception NoSuchPaddingException if <code>transformation</code>     *          contains a padding scheme that is not available.     *     * @exception IllegalArgumentException if the <code>provider</code>     *          is null or empty.     *     * @see java.security.Provider     */    public static final Cipher getInstance(String transformation,                                           String provider)            throws NoSuchAlgorithmException, NoSuchProviderException,            NoSuchPaddingException    {        if ((provider == null) || (provider.length() == 0)) {            throw new IllegalArgumentException("Missing provider");        }        Provider p = Security.getProvider(provider);        if (p == null) {            throw new NoSuchProviderException("No such provider: " +                                              provider);        }        return getInstance(transformation, p);    }     /**     * Returns a <code>Cipher</code> object that implements the specified     * transformation.     *     * <p> A new Cipher object encapsulating the     * CipherSpi implementation from the specified Provider     * object is returned.  Note that the specified Provider object     * does not have to be registered in the provider list.     *     * @param transformation the name of the transformation,     * e.g., <i>DES/CBC/PKCS5Padding</i>.     * See the Cipher section in the <a href=     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard transformation names.     *     * @param provider the provider.     *     * @return a cipher that implements the requested transformation.     *     * @exception NoSuchAlgorithmException if <code>transformation</code>     *          is null, empty, in an invalid format,     *          or if a CipherSpi implementation for the specified algorithm     *          is not available from the specified Provider object.     *     * @exception NoSuchPaddingException if <code>transformation</code>     *          contains a padding scheme that is not available.     *     * @exception IllegalArgumentException if the <code>provider</code>     *          is null.     *     * @see java.security.Provider     */    public static final Cipher getInstance(String transformation,                                           Provider provider)            throws NoSuchAlgorithmException, NoSuchPaddingException    {        if (provider == null) {            throw new IllegalArgumentException("Missing provider");        }        Exception failure = null;        List transforms = getTransforms(transformation);        boolean providerChecked = false;        String paddingError = null;        for (Iterator t = transforms.iterator(); t.hasNext();) {            Transform tr = (Transform)t.next();            Service s = provider.getService("Cipher", tr.transform);            if (s == null) {                continue;            }            if (providerChecked == false) {                // for compatibility, first do the lookup and then verify                // the provider. this makes the difference between a NSAE                // and a SecurityException if the                // provider does not support the algorithm.                Exception ve = JceSecurity.getVerificationResult(provider);                if (ve != null) {                    String msg = "JCE cannot authenticate the provider "                        + provider.getName();                    throw new SecurityException(msg, ve);                }                providerChecked = true;            }            if (tr.supportsMode(s) == S_NO) {                continue;            }            if (tr.supportsPadding(s) == S_NO) {                paddingError = tr.pad;                continue;            }            try {                CipherSpi spi = (CipherSpi)s.newInstance(null);                tr.setModePadding(spi);                Cipher cipher = new Cipher(spi, transformation);                cipher.provider = s.getProvider();                cipher.initCryptoPermission();                return cipher;            } catch (Exception e) {                failure = e;            }        }         // throw NoSuchPaddingException if the problem is with padding        if (failure instanceof NoSuchPaddingException) {            throw (NoSuchPaddingException)failure;        }        if (paddingError != null) {            throw new NoSuchPaddingException                ("Padding not supported: " + paddingError);        }        throw new NoSuchAlgorithmException                ("No such algorithm: " + transformation, failure);    }     // If the requested crypto service is export-controlled,    // determine the maximum allowable keysize.    private void initCryptoPermission() throws NoSuchAlgorithmException {        if (JceSecurity.isRestricted() == false) {            cryptoPerm = CryptoAllPermission.INSTANCE;            exmech = null;            return;        }        cryptoPerm = getConfiguredPermission(transformation);        // Instantiate the exemption mechanism (if required)        String exmechName = cryptoPerm.getExemptionMechanism();        if (exmechName != null) {            exmech = ExemptionMechanism.getInstance(exmechName);        }    }     // max number of debug warnings to print from chooseFirstProvider()    private static int warnCount = 10;     /**     * Choose the Spi from the first provider available. Used if     * delayed provider selection is not possible because init()     * is not the first method called.     */    void chooseFirstProvider() {        if (spi != null) {            return;        }        synchronized (lock) {            if (spi != null) {                return;            }            if (debug != null) {                int w = --warnCount;                if (w >= 0) {                    debug.println("Cipher.init() not first method "                        + "called, disabling delayed provider selection");                    if (w == 0) {                        debug.println("Further warnings of this type will "                            + "be suppressed");                    }                    new Exception("Call trace").printStackTrace();                }            }            Exception lastException = null;            while ((firstService != null) || serviceIterator.hasNext()) {                Service s;                CipherSpi thisSpi;                if (firstService != null) {                    s = firstService;                    thisSpi = firstSpi;                    firstService = null;                    firstSpi = null;                } else {                    s = (Service)serviceIterator.next();                    thisSpi = null;                }                if (JceSecurity.canUseProvider(s.getProvider()) == false) {                    continue;                }                Transform tr = getTransform(s, transforms);                if (tr == null) {                    // should never happen                    continue;                }                if (tr.supportsModePadding(s) == S_NO) {                    continue;                }                try {                    if (thisSpi == null) {                        Object obj = s.newInstance(null);                        if (obj instanceof CipherSpi == false) {                            continue;                        }                        thisSpi = (CipherSpi)obj;                    }                    tr.setModePadding(thisSpi);                    initCryptoPermission();                    spi = thisSpi;                    provider = s.getProvider();                    // not needed any more                    firstService = null;                    serviceIterator = null;                    transforms = null;                    return;                } catch (Exception e) {                    lastException = e;                }            }            ProviderException e = new ProviderException                    ("Could not construct CipherSpi instance");            if (lastException != null) {                e.initCause(lastException);            }            throw e;        }    }     private final static int I_KEY       = 1;    private final static int I_PARAMSPEC = 2;    private final static int I_PARAMS    = 3;    private final static int I_CERT      = 4;     private void implInit(CipherSpi thisSpi, int type, int opmode, Key key,            AlgorithmParameterSpec paramSpec, AlgorithmParameters params,            SecureRandom random) throws InvalidKeyException,            InvalidAlgorithmParameterException {        switch (type) {        case I_KEY:            checkCryptoPerm(thisSpi, key);            thisSpi.engineInit(opmode, key, random);            break;        case I_PARAMSPEC:            checkCryptoPerm(thisSpi, key, paramSpec);            thisSpi.engineInit(opmode, key, paramSpec, random);            break;        case I_PARAMS:            checkCryptoPerm(thisSpi, key, params);            thisSpi.engineInit(opmode, key, params, random);            break;        case I_CERT:            checkCryptoPerm(thisSpi, key);            thisSpi.engineInit(opmode, key, random);            break;        default:            throw new AssertionError("Internal Cipher error: " + type);        }    }     private void chooseProvider(int initType, int opmode, Key key,            AlgorithmParameterSpec paramSpec,            AlgorithmParameters params, SecureRandom random)            throws InvalidKeyException, InvalidAlgorithmParameterException {        synchronized (lock) {            if (spi != null) {                implInit(spi, initType, opmode, key, paramSpec, params, random);                return;            }            Exception lastException = null;            while ((firstService != null) || serviceIterator.hasNext()) {                Service s;                CipherSpi thisSpi;                if (firstService != null) {                    s = firstService;                    thisSpi = firstSpi;                    firstService = null;                    firstSpi = null;                } else {                    s = (Service)serviceIterator.next();                    thisSpi = null;                }                // if provider says it does not support this key, ignore it                if (s.supportsParameter(key) == false) {                    continue;                }                if (JceSecurity.canUseProvider(s.getProvider()) == false) {                    continue;                }                Transform tr = getTransform(s, transforms);                if (tr == null) {                    // should never happen                    continue;                }                if (tr.supportsModePadding(s) == S_NO) {                    continue;                }                try {                    if (thisSpi == null) {                        thisSpi = (CipherSpi)s.newInstance(null);                    }                    tr.setModePadding(thisSpi);                    initCryptoPermission();                    implInit(thisSpi, initType, opmode, key, paramSpec,                                                        params, random);                    provider = s.getProvider();                    this.spi = thisSpi;                    firstService = null;                    serviceIterator = null;                    transforms = null;                    return;                } catch (Exception e) {                    // NoSuchAlgorithmException from newInstance()                    // InvalidKeyException from init()                    // RuntimeException (ProviderException) from init()                    // SecurityException from crypto permission check                    if (lastException == null) {                        lastException = e;                    }                }            }            // no working provider found, fail            if (lastException instanceof InvalidKeyException) {                throw (InvalidKeyException)lastException;            }            if (lastException instanceof InvalidAlgorithmParameterException) {                throw (InvalidAlgorithmParameterException)lastException;            }            if (lastException instanceof RuntimeException) {                throw (RuntimeException)lastException;            }            String kName = (key != null) ? key.getClass().getName() : "(null)";            throw new InvalidKeyException                ("No installed provider supports this key: "                + kName, lastException);        }    }     /**     * Returns the provider of this <code>Cipher</code> object.     *     * @return the provider of this <code>Cipher</code> object     */    public final Provider getProvider() {        chooseFirstProvider();        return this.provider;    }     /**     * Returns the algorithm name of this <code>Cipher</code> object.     *     * <p>This is the same name that was specified in one of the     * <code>getInstance</code> calls that created this <code>Cipher</code>     * object..     *     * @return the algorithm name of this <code>Cipher</code> object.     */    public final String getAlgorithm() {        return this.transformation;    }     /**     * Returns the block size (in bytes).     *     * @return the block size (in bytes), or 0 if the underlying algorithm is     * not a block cipher     */    public final int getBlockSize() {        chooseFirstProvider();        return spi.engineGetBlockSize();    }     /**     * Returns the length in bytes that an output buffer would need to be in     * order to hold the result of the next <code>update</code> or     * <code>doFinal</code> operation, given the input length     * <code>inputLen</code> (in bytes).     *     * <p>This call takes into account any unprocessed (buffered) data from a     * previous <code>update</code> call, padding, and AEAD tagging.     *     * <p>The actual output length of the next <code>update</code> or     * <code>doFinal</code> call may be smaller than the length returned by     * this method.     *     * @param inputLen the input length (in bytes)     *     * @return the required output buffer size (in bytes)     *     * @exception IllegalStateException if this cipher is in a wrong state     * (e.g., has not yet been initialized)     */    public final int getOutputSize(int inputLen) {         if (!initialized && !(this instanceof NullCipher)) {            throw new IllegalStateException("Cipher not initialized");        }        if (inputLen < 0) {            throw new IllegalArgumentException("Input size must be equal " +                                               "to or greater than zero");        }        chooseFirstProvider();        return spi.engineGetOutputSize(inputLen);    }     /**     * Returns the initialization vector (IV) in a new buffer.     *     * <p>This is useful in the case where a random IV was created,     * or in the context of password-based encryption or     * decryption, where the IV is derived from a user-supplied password.     *     * @return the initialization vector in a new buffer, or null if the     * underlying algorithm does not use an IV, or if the IV has not yet     * been set.     */    public final byte[] getIV() {        chooseFirstProvider();        return spi.engineGetIV();    }     /**     * Returns the parameters used with this cipher.     *     * <p>The returned parameters may be the same that were used to initialize     * this cipher, or may contain a combination of default and random     * parameter values used by the underlying cipher implementation if this     * cipher requires algorithm parameters but was not initialized with any.     *     * @return the parameters used with this cipher, or null if this cipher     * does not use any parameters.     */    public final AlgorithmParameters getParameters() {        chooseFirstProvider();        return spi.engineGetParameters();    }     /**     * Returns the exemption mechanism object used with this cipher.     *     * @return the exemption mechanism object used with this cipher, or     * null if this cipher does not use any exemption mechanism.     */    public final ExemptionMechanism getExemptionMechanism() {        chooseFirstProvider();        return exmech;    }     //    // Crypto permission check code below    //    private void checkCryptoPerm(CipherSpi checkSpi, Key key)            throws InvalidKeyException {        if (cryptoPerm == CryptoAllPermission.INSTANCE) {            return;        }

Lines 501–1000 of 2677. Previous lines