|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.rsa; |
|
|
|
import java.io.IOException; |
|
import java.math.BigInteger; |
|
|
|
import java.security.*; |
|
import java.security.spec.*; |
|
import java.security.interfaces.*; |
|
import java.util.Arrays; |
|
|
|
import sun.security.util.*; |
|
|
|
import sun.security.pkcs.PKCS8Key; |
|
|
|
import sun.security.rsa.RSAUtil.KeyType; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class RSAPrivateCrtKeyImpl |
|
extends PKCS8Key implements RSAPrivateCrtKey { |
|
|
|
@java.io.Serial |
|
private static final long serialVersionUID = -1326088454257084918L; |
|
|
|
private BigInteger n; |
|
private BigInteger e; |
|
private BigInteger d; |
|
private BigInteger p; |
|
private BigInteger q; |
|
private BigInteger pe; |
|
private BigInteger qe; |
|
private BigInteger coeff; |
|
|
|
private transient KeyType type; |
|
|
|
// Optional parameters associated with this RSA key |
|
// specified in the encoding of its AlgorithmId. |
|
|
|
private transient AlgorithmParameterSpec keyParams; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static RSAPrivateKey newKey(KeyType type, String format, |
|
byte[] encoded) throws InvalidKeyException { |
|
if (encoded == null || encoded.length == 0) { |
|
throw new InvalidKeyException("Missing key encoding"); |
|
} |
|
switch (format) { |
|
case "PKCS#8": |
|
RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded); |
|
RSAKeyFactory.checkKeyAlgo(key, type.keyAlgo); |
|
// check all CRT-specific components are available, if any one |
|
|
|
if ((key.getPublicExponent().signum() == 0) || |
|
(key.getPrimeExponentP().signum() == 0) || |
|
(key.getPrimeExponentQ().signum() == 0) || |
|
(key.getPrimeP().signum() == 0) || |
|
(key.getPrimeQ().signum() == 0) || |
|
(key.getCrtCoefficient().signum() == 0)) { |
|
return new RSAPrivateKeyImpl(key.type, key.keyParams, |
|
key.getModulus(), key.getPrivateExponent()); |
|
} else { |
|
return key; |
|
} |
|
case "PKCS#1": |
|
try { |
|
BigInteger[] comps = parseASN1(encoded); |
|
if ((comps[1].signum() == 0) || (comps[3].signum() == 0) || |
|
(comps[4].signum() == 0) || (comps[5].signum() == 0) || |
|
(comps[6].signum() == 0) || (comps[7].signum() == 0)) { |
|
return new RSAPrivateKeyImpl(type, null, comps[0], |
|
comps[2]); |
|
} else { |
|
return new RSAPrivateCrtKeyImpl(type, null, comps[0], |
|
comps[1], comps[2], comps[3], comps[4], comps[5], |
|
comps[6], comps[7]); |
|
} |
|
} catch (IOException ioe) { |
|
throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe); |
|
} |
|
default: |
|
throw new InvalidKeyException("Unsupported RSA Private(Crt)Key " |
|
+ "format: " + format); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static RSAPrivateKey newKey(KeyType type, |
|
AlgorithmParameterSpec params, |
|
BigInteger n, BigInteger e, BigInteger d, |
|
BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, |
|
BigInteger coeff) throws InvalidKeyException { |
|
RSAPrivateKey key; |
|
if ((e.signum() == 0) || (p.signum() == 0) || |
|
(q.signum() == 0) || (pe.signum() == 0) || |
|
(qe.signum() == 0) || (coeff.signum() == 0)) { |
|
|
|
return new RSAPrivateKeyImpl(type, params, n, d); |
|
} else { |
|
return new RSAPrivateCrtKeyImpl(type, params, n, e, d, |
|
p, q, pe, qe, coeff); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { |
|
super(encoded); |
|
parseKeyBits(); |
|
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); |
|
try { |
|
|
|
Object[] o = RSAUtil.getTypeAndParamSpec(algid); |
|
this.type = (KeyType) o[0]; |
|
this.keyParams = (AlgorithmParameterSpec) o[1]; |
|
} catch (ProviderException e) { |
|
throw new InvalidKeyException(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
RSAPrivateCrtKeyImpl(KeyType type, AlgorithmParameterSpec keyParams, |
|
BigInteger n, BigInteger e, BigInteger d, |
|
BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, |
|
BigInteger coeff) throws InvalidKeyException { |
|
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); |
|
|
|
this.n = n; |
|
this.e = e; |
|
this.d = d; |
|
this.p = p; |
|
this.q = q; |
|
this.pe = pe; |
|
this.qe = qe; |
|
this.coeff = coeff; |
|
|
|
try { |
|
|
|
algid = RSAUtil.createAlgorithmId(type, keyParams); |
|
} catch (ProviderException exc) { |
|
throw new InvalidKeyException(exc); |
|
} |
|
|
|
this.type = type; |
|
this.keyParams = keyParams; |
|
|
|
try { |
|
byte[][] nbytes = new byte[8][]; |
|
nbytes[0] = n.toByteArray(); |
|
nbytes[1] = e.toByteArray(); |
|
nbytes[2] = d.toByteArray(); |
|
nbytes[3] = p.toByteArray(); |
|
nbytes[4] = q.toByteArray(); |
|
nbytes[5] = pe.toByteArray(); |
|
nbytes[6] = qe.toByteArray(); |
|
nbytes[7] = coeff.toByteArray(); |
|
|
|
// Initiate with a big enough size so there's no need to |
|
// reallocate memory later and thus can be cleaned up |
|
|
|
DerOutputStream out = new DerOutputStream( |
|
nbytes[0].length + nbytes[1].length + |
|
nbytes[2].length + nbytes[3].length + |
|
nbytes[4].length + nbytes[5].length + |
|
nbytes[6].length + nbytes[7].length + |
|
100); |
|
out.putInteger(0); |
|
out.putInteger(nbytes[0]); |
|
out.putInteger(nbytes[1]); |
|
out.putInteger(nbytes[2]); |
|
out.putInteger(nbytes[3]); |
|
out.putInteger(nbytes[4]); |
|
out.putInteger(nbytes[5]); |
|
out.putInteger(nbytes[6]); |
|
out.putInteger(nbytes[7]); |
|
|
|
Arrays.fill(nbytes[2], (byte)0); |
|
Arrays.fill(nbytes[3], (byte)0); |
|
Arrays.fill(nbytes[4], (byte)0); |
|
Arrays.fill(nbytes[5], (byte)0); |
|
Arrays.fill(nbytes[6], (byte)0); |
|
Arrays.fill(nbytes[7], (byte)0); |
|
DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); |
|
key = val.toByteArray(); |
|
val.clear(); |
|
} catch (IOException exc) { |
|
|
|
throw new InvalidKeyException(exc); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
public String getAlgorithm() { |
|
return type.keyAlgo; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getModulus() { |
|
return n; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPublicExponent() { |
|
return e; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPrivateExponent() { |
|
return d; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPrimeP() { |
|
return p; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPrimeQ() { |
|
return q; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPrimeExponentP() { |
|
return pe; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getPrimeExponentQ() { |
|
return qe; |
|
} |
|
|
|
|
|
@Override |
|
public BigInteger getCrtCoefficient() { |
|
return coeff; |
|
} |
|
|
|
|
|
@Override |
|
public AlgorithmParameterSpec getParams() { |
|
return keyParams; |
|
} |
|
|
|
|
|
@Override |
|
public String toString() { |
|
return "SunRsaSign " + type.keyAlgo + " private CRT key, " |
|
+ n.bitLength() + " bits" + "\n params: " + keyParams |
|
+ "\n modulus: " + n + "\n private exponent: " + d; |
|
} |
|
|
|
// utility method for parsing DER encoding of RSA private keys in PKCS#1 |
|
// format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n, |
|
|
|
private static BigInteger[] parseASN1(byte[] raw) throws IOException { |
|
DerValue derValue = new DerValue(raw); |
|
try { |
|
if (derValue.tag != DerValue.tag_Sequence) { |
|
throw new IOException("Not a SEQUENCE"); |
|
} |
|
int version = derValue.data.getInteger(); |
|
if (version != 0) { |
|
throw new IOException("Version must be 0"); |
|
} |
|
|
|
BigInteger[] result = new BigInteger[8]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
for (int i = 0; i < result.length; i++) { |
|
result[i] = derValue.data.getPositiveBigInteger(); |
|
} |
|
if (derValue.data.available() != 0) { |
|
throw new IOException("Extra data available"); |
|
} |
|
return result; |
|
} finally { |
|
derValue.clear(); |
|
} |
|
} |
|
|
|
private void parseKeyBits() throws InvalidKeyException { |
|
try { |
|
BigInteger[] comps = parseASN1(key); |
|
n = comps[0]; |
|
e = comps[1]; |
|
d = comps[2]; |
|
p = comps[3]; |
|
q = comps[4]; |
|
pe = comps[5]; |
|
qe = comps[6]; |
|
coeff = comps[7]; |
|
} catch (IOException e) { |
|
throw new InvalidKeyException("Invalid RSA private key", e); |
|
} |
|
} |
|
} |