|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.rsa; |
|
|
|
import java.math.BigInteger; |
|
|
|
import java.security.*; |
|
import java.security.interfaces.*; |
|
import java.security.spec.*; |
|
import java.util.Arrays; |
|
|
|
import sun.security.action.GetPropertyAction; |
|
import sun.security.rsa.RSAUtil.KeyType; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class RSAKeyFactory extends KeyFactorySpi { |
|
|
|
private static final Class<?> RSA_PUB_KEYSPEC_CLS = RSAPublicKeySpec.class; |
|
private static final Class<?> RSA_PRIV_KEYSPEC_CLS = |
|
RSAPrivateKeySpec.class; |
|
private static final Class<?> RSA_PRIVCRT_KEYSPEC_CLS = |
|
RSAPrivateCrtKeySpec.class; |
|
private static final Class<?> X509_KEYSPEC_CLS = X509EncodedKeySpec.class; |
|
private static final Class<?> PKCS8_KEYSPEC_CLS = PKCS8EncodedKeySpec.class; |
|
|
|
public static final int MIN_MODLEN = 512; |
|
public static final int MAX_MODLEN = 16384; |
|
|
|
private final KeyType type; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static final int MAX_MODLEN_RESTRICT_EXP = 3072; |
|
public static final int MAX_RESTRICTED_EXPLEN = 64; |
|
|
|
private static final boolean restrictExpLen = |
|
"true".equalsIgnoreCase(GetPropertyAction.privilegedGetProperty( |
|
"sun.security.rsa.restrictRSAExponent", "true")); |
|
|
|
static RSAKeyFactory getInstance(KeyType type) { |
|
return new RSAKeyFactory(type); |
|
} |
|
|
|
|
|
static void checkKeyAlgo(Key key, String expectedAlg) |
|
throws InvalidKeyException { |
|
String keyAlg = key.getAlgorithm(); |
|
if (keyAlg == null || !(keyAlg.equalsIgnoreCase(expectedAlg))) { |
|
throw new InvalidKeyException("Expected a " + expectedAlg |
|
+ " key, but got " + keyAlg); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static RSAKey toRSAKey(Key key) throws InvalidKeyException { |
|
if (key == null) { |
|
throw new InvalidKeyException("Key must not be null"); |
|
} |
|
if ((key instanceof RSAPrivateKeyImpl) || |
|
(key instanceof RSAPrivateCrtKeyImpl) || |
|
(key instanceof RSAPublicKeyImpl)) { |
|
return (RSAKey)key; |
|
} else { |
|
try { |
|
KeyType type = KeyType.lookup(key.getAlgorithm()); |
|
RSAKeyFactory kf = RSAKeyFactory.getInstance(type); |
|
return (RSAKey) kf.engineTranslateKey(key); |
|
} catch (ProviderException e) { |
|
throw new InvalidKeyException(e); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent) |
|
throws InvalidKeyException { |
|
checkKeyLengths(((modulusLen + 7) & ~7), exponent, |
|
RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
if (modulusLen > maxLen) { |
|
throw new InvalidKeyException( |
|
"RSA keys must be no longer than " + maxLen + " bits"); |
|
} |
|
|
|
|
|
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"); |
|
} |
|
} |
|
|
|
|
|
private RSAKeyFactory() { |
|
this.type = KeyType.RSA; |
|
} |
|
|
|
public RSAKeyFactory(KeyType type) { |
|
this.type = type; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected Key engineTranslateKey(Key key) throws InvalidKeyException { |
|
if (key == null) { |
|
throw new InvalidKeyException("Key must not be null"); |
|
} |
|
|
|
checkKeyAlgo(key, type.keyAlgo); |
|
|
|
|
|
if ((key instanceof RSAPrivateKeyImpl) || |
|
(key instanceof RSAPrivateCrtKeyImpl) || |
|
(key instanceof RSAPublicKeyImpl)) { |
|
return key; |
|
} |
|
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"); |
|
} |
|
} |
|
|
|
|
|
protected PublicKey engineGeneratePublic(KeySpec keySpec) |
|
throws InvalidKeySpecException { |
|
try { |
|
return generatePublic(keySpec); |
|
} catch (InvalidKeySpecException e) { |
|
throw e; |
|
} catch (GeneralSecurityException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
} |
|
|
|
|
|
protected PrivateKey engineGeneratePrivate(KeySpec keySpec) |
|
throws InvalidKeySpecException { |
|
try { |
|
return generatePrivate(keySpec); |
|
} catch (InvalidKeySpecException e) { |
|
throw e; |
|
} catch (GeneralSecurityException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
} |
|
|
|
|
|
private PublicKey translatePublicKey(PublicKey key) |
|
throws InvalidKeyException { |
|
if (key instanceof RSAPublicKey) { |
|
RSAPublicKey rsaKey = (RSAPublicKey)key; |
|
try { |
|
return new RSAPublicKeyImpl( |
|
type, rsaKey.getParams(), |
|
rsaKey.getModulus(), |
|
rsaKey.getPublicExponent()); |
|
} catch (ProviderException e) { |
|
|
|
throw new InvalidKeyException("Invalid key", e); |
|
} |
|
} else { |
|
|
|
return RSAPublicKeyImpl.newKey(type, key.getFormat(), |
|
key.getEncoded()); |
|
} |
|
} |
|
|
|
|
|
private PrivateKey translatePrivateKey(PrivateKey key) |
|
throws InvalidKeyException { |
|
if (key instanceof RSAPrivateCrtKey) { |
|
RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key; |
|
try { |
|
return new RSAPrivateCrtKeyImpl( |
|
type, rsaKey.getParams(), |
|
rsaKey.getModulus(), |
|
rsaKey.getPublicExponent(), |
|
rsaKey.getPrivateExponent(), |
|
rsaKey.getPrimeP(), |
|
rsaKey.getPrimeQ(), |
|
rsaKey.getPrimeExponentP(), |
|
rsaKey.getPrimeExponentQ(), |
|
rsaKey.getCrtCoefficient() |
|
); |
|
} catch (ProviderException e) { |
|
|
|
throw new InvalidKeyException("Invalid key", e); |
|
} |
|
} else if (key instanceof RSAPrivateKey) { |
|
RSAPrivateKey rsaKey = (RSAPrivateKey)key; |
|
try { |
|
return new RSAPrivateKeyImpl( |
|
type, rsaKey.getParams(), |
|
rsaKey.getModulus(), |
|
rsaKey.getPrivateExponent() |
|
); |
|
} catch (ProviderException e) { |
|
|
|
throw new InvalidKeyException("Invalid key", e); |
|
} |
|
} else { |
|
byte[] encoded = key.getEncoded(); |
|
try { |
|
return RSAPrivateCrtKeyImpl.newKey(type, key.getFormat(), encoded); |
|
} finally { |
|
if (encoded != null) { |
|
Arrays.fill(encoded, (byte)0); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
private PublicKey generatePublic(KeySpec keySpec) |
|
throws GeneralSecurityException { |
|
if (keySpec instanceof X509EncodedKeySpec) { |
|
return RSAPublicKeyImpl.newKey(type, "X.509", |
|
((X509EncodedKeySpec)keySpec).getEncoded()); |
|
} else if (keySpec instanceof RSAPublicKeySpec) { |
|
RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec; |
|
try { |
|
return new RSAPublicKeyImpl( |
|
type, rsaSpec.getParams(), |
|
rsaSpec.getModulus(), |
|
rsaSpec.getPublicExponent() |
|
); |
|
} catch (ProviderException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
} else { |
|
throw new InvalidKeySpecException("Only RSAPublicKeySpec " |
|
+ "and X509EncodedKeySpec supported for RSA public keys"); |
|
} |
|
} |
|
|
|
|
|
private PrivateKey generatePrivate(KeySpec keySpec) |
|
throws GeneralSecurityException { |
|
if (keySpec instanceof PKCS8EncodedKeySpec) { |
|
byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); |
|
try { |
|
return RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8", encoded); |
|
} finally { |
|
Arrays.fill(encoded, (byte)0); |
|
} |
|
} else if (keySpec instanceof RSAPrivateCrtKeySpec) { |
|
RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec; |
|
try { |
|
return new RSAPrivateCrtKeyImpl( |
|
type, rsaSpec.getParams(), |
|
rsaSpec.getModulus(), |
|
rsaSpec.getPublicExponent(), |
|
rsaSpec.getPrivateExponent(), |
|
rsaSpec.getPrimeP(), |
|
rsaSpec.getPrimeQ(), |
|
rsaSpec.getPrimeExponentP(), |
|
rsaSpec.getPrimeExponentQ(), |
|
rsaSpec.getCrtCoefficient() |
|
); |
|
} catch (ProviderException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
} else if (keySpec instanceof RSAPrivateKeySpec) { |
|
RSAPrivateKeySpec rsaSpec = (RSAPrivateKeySpec)keySpec; |
|
try { |
|
return new RSAPrivateKeyImpl( |
|
type, rsaSpec.getParams(), |
|
rsaSpec.getModulus(), |
|
rsaSpec.getPrivateExponent() |
|
); |
|
} catch (ProviderException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
} 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 or PKCS#1 for public/private |
|
|
|
key = engineTranslateKey(key); |
|
} catch (InvalidKeyException e) { |
|
throw new InvalidKeySpecException(e); |
|
} |
|
if (key instanceof RSAPublicKey) { |
|
RSAPublicKey rsaKey = (RSAPublicKey)key; |
|
if (keySpec.isAssignableFrom(RSA_PUB_KEYSPEC_CLS)) { |
|
return keySpec.cast(new RSAPublicKeySpec( |
|
rsaKey.getModulus(), |
|
rsaKey.getPublicExponent(), |
|
rsaKey.getParams() |
|
)); |
|
} else if (keySpec.isAssignableFrom(X509_KEYSPEC_CLS)) { |
|
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); |
|
} else { |
|
throw new InvalidKeySpecException |
|
("KeySpec must be RSAPublicKeySpec or " |
|
+ "X509EncodedKeySpec for RSA public keys"); |
|
} |
|
} else if (key instanceof RSAPrivateKey) { |
|
if (keySpec.isAssignableFrom(PKCS8_KEYSPEC_CLS)) { |
|
byte[] encoded = key.getEncoded(); |
|
try { |
|
return keySpec.cast(new PKCS8EncodedKeySpec(encoded)); |
|
} finally { |
|
Arrays.fill(encoded, (byte)0); |
|
} |
|
} else if (keySpec.isAssignableFrom(RSA_PRIVCRT_KEYSPEC_CLS)) { |
|
|
|
if (key instanceof RSAPrivateCrtKey) { |
|
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key; |
|
return keySpec.cast(new RSAPrivateCrtKeySpec( |
|
crtKey.getModulus(), |
|
crtKey.getPublicExponent(), |
|
crtKey.getPrivateExponent(), |
|
crtKey.getPrimeP(), |
|
crtKey.getPrimeQ(), |
|
crtKey.getPrimeExponentP(), |
|
crtKey.getPrimeExponentQ(), |
|
crtKey.getCrtCoefficient(), |
|
crtKey.getParams() |
|
)); |
|
} else { |
|
if (!keySpec.isAssignableFrom(RSA_PRIV_KEYSPEC_CLS)) { |
|
throw new InvalidKeySpecException |
|
("RSAPrivateCrtKeySpec can only be used with CRT keys"); |
|
} |
|
|
|
|
|
RSAPrivateKey rsaKey = (RSAPrivateKey) key; |
|
return keySpec.cast(new RSAPrivateKeySpec( |
|
rsaKey.getModulus(), |
|
rsaKey.getPrivateExponent(), |
|
rsaKey.getParams() |
|
)); |
|
} |
|
} else { |
|
throw new InvalidKeySpecException |
|
("KeySpec must be RSAPrivate(Crt)KeySpec or " |
|
+ "PKCS8EncodedKeySpec for RSA private keys"); |
|
} |
|
} else { |
|
|
|
throw new InvalidKeySpecException("Neither public nor private key"); |
|
} |
|
} |
|
|
|
public static final class Legacy extends RSAKeyFactory { |
|
public Legacy() { |
|
super(KeyType.RSA); |
|
} |
|
} |
|
|
|
public static final class PSS extends RSAKeyFactory { |
|
public PSS() { |
|
super(KeyType.PSS); |
|
} |
|
} |
|
} |