1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.rsa; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 31 import java.security.*; 32 import java.security.interfaces.*; 33 34 import sun.security.util.*; 35 import sun.security.x509.AlgorithmId; 36 import sun.security.pkcs.PKCS8Key; 37 38 /** 39 * Key implementation for RSA private keys, CRT form. For non-CRT private 40 * keys, see RSAPrivateKeyImpl. We need separate classes to ensure 41 * correct behavior in instanceof checks, etc. 42 * 43 * Note: RSA keys must be at least 512 bits long 44 * 45 * @see RSAPrivateKeyImpl 46 * @see RSAKeyFactory 47 * 48 * @since 1.5 49 * @author Andreas Sterbenz 50 */ 51 public final class RSAPrivateCrtKeyImpl 52 extends PKCS8Key implements RSAPrivateCrtKey { 53 54 private static final long serialVersionUID = -1326088454257084918L; 55 56 private BigInteger n; // modulus 57 private BigInteger e; // public exponent 58 private BigInteger d; // private exponent 59 private BigInteger p; // prime p 60 private BigInteger q; // prime q 61 private BigInteger pe; // prime exponent p 62 private BigInteger qe; // prime exponent q 63 private BigInteger coeff; // CRT coeffcient 64 65 // algorithmId used to identify RSA keys 66 static final AlgorithmId rsaId = 67 new AlgorithmId(AlgorithmId.RSAEncryption_oid); 68 69 /** 70 * Generate a new key from its encoding. Returns a CRT key if possible 71 * and a non-CRT key otherwise. Used by RSAKeyFactory. 72 */ 73 public static RSAPrivateKey newKey(byte[] encoded) 74 throws InvalidKeyException { 75 RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded); 76 if (key.getPublicExponent().signum() == 0) { 77 // public exponent is missing, return a non-CRT key 78 return new RSAPrivateKeyImpl( 79 key.getModulus(), 80 key.getPrivateExponent() 81 ); 82 } else { 83 return key; 84 } 85 } 86 87 /** 88 * Construct a key from its encoding. Called from newKey above. 89 */ 90 RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { 91 decode(encoded); 92 RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); 93 } 94 95 /** 96 * Construct a key from its components. Used by the 97 * RSAKeyFactory and the RSAKeyPairGenerator. 98 */ 99 RSAPrivateCrtKeyImpl(BigInteger n, BigInteger e, BigInteger d, 100 BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, 101 BigInteger coeff) throws InvalidKeyException { 102 this.n = n; 103 this.e = e; 104 this.d = d; 105 this.p = p; 106 this.q = q; 107 this.pe = pe; 108 this.qe = qe; 109 this.coeff = coeff; 110 RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); 111 112 // generate the encoding 113 algid = rsaId; 114 try { 115 DerOutputStream out = new DerOutputStream(); 116 out.putInteger(0); // version must be 0 117 out.putInteger(n); 118 out.putInteger(e); 119 out.putInteger(d); 120 out.putInteger(p); 121 out.putInteger(q); 122 out.putInteger(pe); 123 out.putInteger(qe); 124 out.putInteger(coeff); 125 DerValue val = 126 new DerValue(DerValue.tag_Sequence, out.toByteArray()); 127 key = val.toByteArray(); 128 } catch (IOException exc) { 129 // should never occur 130 throw new InvalidKeyException(exc); 131 } 132 } 133 134 // see JCA doc 135 public String getAlgorithm() { 136 return "RSA"; 137 } 138 139 // see JCA doc 140 public BigInteger getModulus() { 141 return n; 142 } 143 144 // see JCA doc 145 public BigInteger getPublicExponent() { 146 return e; 147 } 148 149 // see JCA doc 150 public BigInteger getPrivateExponent() { 151 return d; 152 } 153 154 // see JCA doc 155 public BigInteger getPrimeP() { 156 return p; 157 } 158 159 // see JCA doc 160 public BigInteger getPrimeQ() { 161 return q; 162 } 163 164 // see JCA doc 165 public BigInteger getPrimeExponentP() { 166 return pe; 167 } 168 169 // see JCA doc 170 public BigInteger getPrimeExponentQ() { 171 return qe; 172 } 173 174 // see JCA doc 175 public BigInteger getCrtCoefficient() { 176 return coeff; 177 } 178 179 /** 180 * Parse the key. Called by PKCS8Key. 181 */ 182 protected void parseKeyBits() throws InvalidKeyException { 183 try { 184 DerInputStream in = new DerInputStream(key); 185 DerValue derValue = in.getDerValue(); 186 if (derValue.tag != DerValue.tag_Sequence) { 187 throw new IOException("Not a SEQUENCE"); 188 } 189 DerInputStream data = derValue.data; 190 int version = data.getInteger(); 191 if (version != 0) { 192 throw new IOException("Version must be 0"); 193 } 194 n = getBigInteger(data); 195 e = getBigInteger(data); 196 d = getBigInteger(data); 197 p = getBigInteger(data); 198 q = getBigInteger(data); 199 pe = getBigInteger(data); 200 qe = getBigInteger(data); 201 coeff = getBigInteger(data); 202 if (derValue.data.available() != 0) { 203 throw new IOException("Extra data available"); 204 } 205 } catch (IOException e) { 206 throw new InvalidKeyException("Invalid RSA private key", e); 207 } 208 } 209 210 /** 211 * Read a BigInteger from the DerInputStream. 212 */ 213 static BigInteger getBigInteger(DerInputStream data) throws IOException { 214 BigInteger b = data.getBigInteger(); 215 216 /* 217 * Some implementations do not correctly encode ASN.1 INTEGER values 218 * in 2's complement format, resulting in a negative integer when 219 * decoded. Correct the error by converting it to a positive integer. 220 * 221 * See CR 6255949 222 */ 223 if (b.signum() < 0) { 224 b = new BigInteger(1, b.toByteArray()); 225 } 226 return b; 227 } 228 }