401 lines · 16.0 KB · Java
RawDownload
/* * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.rsa; import java.math.BigInteger; import java.security.*;import java.security.interfaces.*;import java.security.spec.*; import sun.security.action.GetPropertyAction; /** * KeyFactory for RSA keys. Keys must be instances of PublicKey or PrivateKey * and getAlgorithm() must return "RSA". For such keys, it supports conversion * between the following: * * For public keys: *  . PublicKey with an X.509 encoding *  . RSAPublicKey *  . RSAPublicKeySpec *  . X509EncodedKeySpec * * For private keys: *  . PrivateKey with a PKCS#8 encoding *  . RSAPrivateKey *  . RSAPrivateCrtKey *  . RSAPrivateKeySpec *  . RSAPrivateCrtKeySpec *  . PKCS8EncodedKeySpec * (of course, CRT variants only for CRT keys) * * Note: as always, RSA keys should be at least 512 bits long * * @since   1.5 * @author  Andreas Sterbenz */public final class RSAKeyFactory extends KeyFactorySpi {     private final static Class<?> rsaPublicKeySpecClass =                                                RSAPublicKeySpec.class;    private final static Class<?> rsaPrivateKeySpecClass =                                                RSAPrivateKeySpec.class;    private final static Class<?> rsaPrivateCrtKeySpecClass =                                                RSAPrivateCrtKeySpec.class;     private final static Class<?> x509KeySpecClass  = X509EncodedKeySpec.class;    private final static Class<?> pkcs8KeySpecClass = PKCS8EncodedKeySpec.class;     public final static int MIN_MODLEN = 512;    public final static int MAX_MODLEN = 16384;     /*     * If the modulus length is above this value, restrict the size of     * the exponent to something that can be reasonably computed.  We     * could simply hardcode the exp len to something like 64 bits, but     * this approach allows flexibility in case impls would like to use     * larger module and exponent values.     */    public final static int MAX_MODLEN_RESTRICT_EXP = 3072;    public final static int MAX_RESTRICTED_EXPLEN = 64;     private static final boolean restrictExpLen =        "true".equalsIgnoreCase(AccessController.doPrivileged(            new GetPropertyAction(                "sun.security.rsa.restrictRSAExponent", "true")));     // instance used for static translateKey();    private final static RSAKeyFactory INSTANCE = new RSAKeyFactory();     public RSAKeyFactory() {        // empty    }     /**     * Static method to convert Key into an instance of RSAPublicKeyImpl     * or RSAPrivate(Crt)KeyImpl. If the key is not an RSA key or cannot be     * used, throw an InvalidKeyException.     *     * Used by RSASignature and RSACipher.     */    public static RSAKey toRSAKey(Key key) throws InvalidKeyException {        if ((key instanceof RSAPrivateKeyImpl) ||            (key instanceof RSAPrivateCrtKeyImpl) ||            (key instanceof RSAPublicKeyImpl)) {            return (RSAKey)key;        } else {            return (RSAKey)INSTANCE.engineTranslateKey(key);        }    }     /*     * Single test entry point for all of the mechanisms in the SunRsaSign     * provider (RSA*KeyImpls).  All of the tests are the same.     *     * For compatibility, we round up to the nearest byte here:     * some Key impls might pass in a value within a byte of the     * real value.     */    static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)            throws InvalidKeyException {        checkKeyLengths(((modulusLen + 7) & ~7), exponent,            RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);    }     /**     * Check the length of an RSA key modulus/exponent to make sure it     * is not too short or long.  Some impls have their own min and     * max key sizes that may or may not match with a system defined value.     *     * @param modulusLen the bit length of the RSA modulus.     * @param exponent the RSA exponent     * @param minModulusLen if > 0, check to see if modulusLen is at     *        least this long, otherwise unused.     * @param maxModulusLen caller will allow this max number of bits.     *        Allow the smaller of the system-defined maximum and this param.     *     * @throws InvalidKeyException if any of the values are unacceptable.     */     public static void checkKeyLengths(int modulusLen, BigInteger exponent,            int minModulusLen, int maxModulusLen) throws InvalidKeyException {         if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) {            throw new InvalidKeyException( "RSA keys must be at least " +                minModulusLen + " bits long");        }         // Even though our policy file may allow this, we don't want        // either value (mod/exp) to be too big.         int maxLen = Math.min(maxModulusLen, MAX_MODLEN);         // If a RSAPrivateKey/RSAPublicKey, make sure the        // modulus len isn't too big.        if (modulusLen > maxLen) {            throw new InvalidKeyException(                "RSA keys must be no longer than " + maxLen + " bits");        }         // If a RSAPublicKey, make sure the exponent isn't too big.        if (restrictExpLen && (exponent != null) &&                (modulusLen > MAX_MODLEN_RESTRICT_EXP) &&                (exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) {            throw new InvalidKeyException(                "RSA exponents can be no longer than " +                MAX_RESTRICTED_EXPLEN + " bits " +                " if modulus is greater than " +                MAX_MODLEN_RESTRICT_EXP + " bits");        }    }     /**     * Translate an RSA key into a SunRsaSign RSA key. If conversion is     * not possible, throw an InvalidKeyException.     * See also JCA doc.     */    protected Key engineTranslateKey(Key key) throws InvalidKeyException {        if (key == null) {            throw new InvalidKeyException("Key must not be null");        }        String keyAlg = key.getAlgorithm();        if (keyAlg.equals("RSA") == false) {            throw new InvalidKeyException("Not an RSA key: " + keyAlg);        }        if (key instanceof PublicKey) {            return translatePublicKey((PublicKey)key);        } else if (key instanceof PrivateKey) {            return translatePrivateKey((PrivateKey)key);        } else {            throw new InvalidKeyException("Neither a public nor a private key");        }    }     // see JCA doc    protected PublicKey engineGeneratePublic(KeySpec keySpec)            throws InvalidKeySpecException {        try {            return generatePublic(keySpec);        } catch (InvalidKeySpecException e) {            throw e;        } catch (GeneralSecurityException e) {            throw new InvalidKeySpecException(e);        }    }     // see JCA doc    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)            throws InvalidKeySpecException {        try {            return generatePrivate(keySpec);        } catch (InvalidKeySpecException e) {            throw e;        } catch (GeneralSecurityException e) {            throw new InvalidKeySpecException(e);        }    }     // internal implementation of translateKey() for public keys. See JCA doc    private PublicKey translatePublicKey(PublicKey key)            throws InvalidKeyException {        if (key instanceof RSAPublicKey) {            if (key instanceof RSAPublicKeyImpl) {                return key;            }            RSAPublicKey rsaKey = (RSAPublicKey)key;            try {                return new RSAPublicKeyImpl(                    rsaKey.getModulus(),                    rsaKey.getPublicExponent()                );            } catch (RuntimeException e) {                // catch providers that incorrectly implement RSAPublicKey                throw new InvalidKeyException("Invalid key", e);            }        } else if ("X.509".equals(key.getFormat())) {            byte[] encoded = key.getEncoded();            return new RSAPublicKeyImpl(encoded);        } else {            throw new InvalidKeyException("Public keys must be instance "                + "of RSAPublicKey or have X.509 encoding");        }    }     // internal implementation of translateKey() for private keys. See JCA doc    private PrivateKey translatePrivateKey(PrivateKey key)            throws InvalidKeyException {        if (key instanceof RSAPrivateCrtKey) {            if (key instanceof RSAPrivateCrtKeyImpl) {                return key;            }            RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key;            try {                return new RSAPrivateCrtKeyImpl(                    rsaKey.getModulus(),                    rsaKey.getPublicExponent(),                    rsaKey.getPrivateExponent(),                    rsaKey.getPrimeP(),                    rsaKey.getPrimeQ(),                    rsaKey.getPrimeExponentP(),                    rsaKey.getPrimeExponentQ(),                    rsaKey.getCrtCoefficient()                );            } catch (RuntimeException e) {                // catch providers that incorrectly implement RSAPrivateCrtKey                throw new InvalidKeyException("Invalid key", e);            }        } else if (key instanceof RSAPrivateKey) {            if (key instanceof RSAPrivateKeyImpl) {                return key;            }            RSAPrivateKey rsaKey = (RSAPrivateKey)key;            try {                return new RSAPrivateKeyImpl(                    rsaKey.getModulus(),                    rsaKey.getPrivateExponent()                );            } catch (RuntimeException e) {                // catch providers that incorrectly implement RSAPrivateKey                throw new InvalidKeyException("Invalid key", e);            }        } else if ("PKCS#8".equals(key.getFormat())) {            byte[] encoded = key.getEncoded();            return RSAPrivateCrtKeyImpl.newKey(encoded);        } else {            throw new InvalidKeyException("Private keys must be instance "                + "of RSAPrivate(Crt)Key or have PKCS#8 encoding");        }    }     // internal implementation of generatePublic. See JCA doc    private PublicKey generatePublic(KeySpec keySpec)            throws GeneralSecurityException {        if (keySpec instanceof X509EncodedKeySpec) {            X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;            return new RSAPublicKeyImpl(x509Spec.getEncoded());        } else if (keySpec instanceof RSAPublicKeySpec) {            RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec;            return new RSAPublicKeyImpl(                rsaSpec.getModulus(),                rsaSpec.getPublicExponent()            );        } else {            throw new InvalidKeySpecException("Only RSAPublicKeySpec "                + "and X509EncodedKeySpec supported for RSA public keys");        }    }     // internal implementation of generatePrivate. See JCA doc    private PrivateKey generatePrivate(KeySpec keySpec)            throws GeneralSecurityException {        if (keySpec instanceof PKCS8EncodedKeySpec) {            PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;            return RSAPrivateCrtKeyImpl.newKey(pkcsSpec.getEncoded());        } else if (keySpec instanceof RSAPrivateCrtKeySpec) {            RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;            return new RSAPrivateCrtKeyImpl(                rsaSpec.getModulus(),                rsaSpec.getPublicExponent(),                rsaSpec.getPrivateExponent(),                rsaSpec.getPrimeP(),                rsaSpec.getPrimeQ(),                rsaSpec.getPrimeExponentP(),                rsaSpec.getPrimeExponentQ(),                rsaSpec.getCrtCoefficient()            );        } else if (keySpec instanceof RSAPrivateKeySpec) {            RSAPrivateKeySpec rsaSpec = (RSAPrivateKeySpec)keySpec;            return new RSAPrivateKeyImpl(                rsaSpec.getModulus(),                rsaSpec.getPrivateExponent()            );        } else {            throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "                + "and PKCS8EncodedKeySpec supported for RSA private keys");        }    }     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)            throws InvalidKeySpecException {        try {            // convert key to one of our keys            // this also verifies that the key is a valid RSA key and ensures            // that the encoding is X.509/PKCS#8 for public/private keys            key = engineTranslateKey(key);        } catch (InvalidKeyException e) {            throw new InvalidKeySpecException(e);        }        if (key instanceof RSAPublicKey) {            RSAPublicKey rsaKey = (RSAPublicKey)key;            if (rsaPublicKeySpecClass.isAssignableFrom(keySpec)) {                return (T) new RSAPublicKeySpec(                    rsaKey.getModulus(),                    rsaKey.getPublicExponent()                );            } else if (x509KeySpecClass.isAssignableFrom(keySpec)) {                return (T) new X509EncodedKeySpec(key.getEncoded());            } else {                throw new InvalidKeySpecException                        ("KeySpec must be RSAPublicKeySpec or "                        + "X509EncodedKeySpec for RSA public keys");            }        } else if (key instanceof RSAPrivateKey) {            if (pkcs8KeySpecClass.isAssignableFrom(keySpec)) {                return (T) new PKCS8EncodedKeySpec(key.getEncoded());            } else if (rsaPrivateCrtKeySpecClass.isAssignableFrom(keySpec)) {                if (key instanceof RSAPrivateCrtKey) {                    RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;                    return (T) new RSAPrivateCrtKeySpec(                        crtKey.getModulus(),                        crtKey.getPublicExponent(),                        crtKey.getPrivateExponent(),                        crtKey.getPrimeP(),                        crtKey.getPrimeQ(),                        crtKey.getPrimeExponentP(),                        crtKey.getPrimeExponentQ(),                        crtKey.getCrtCoefficient()                    );                } else {                    throw new InvalidKeySpecException                    ("RSAPrivateCrtKeySpec can only be used with CRT keys");                }            } else if (rsaPrivateKeySpecClass.isAssignableFrom(keySpec)) {                RSAPrivateKey rsaKey = (RSAPrivateKey)key;                return (T) new RSAPrivateKeySpec(                    rsaKey.getModulus(),                    rsaKey.getPrivateExponent()                );            } else {                throw new InvalidKeySpecException                        ("KeySpec must be RSAPrivate(Crt)KeySpec or "                        + "PKCS8EncodedKeySpec for RSA private keys");            }        } else {            // should not occur, caught in engineTranslateKey()            throw new InvalidKeySpecException("Neither public nor private key");        }    }}