1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.conscrypt; 18 19import java.io.IOException; 20import java.io.ObjectInputStream; 21import java.io.ObjectOutputStream; 22import java.math.BigInteger; 23import java.security.InvalidKeyException; 24import java.security.interfaces.RSAPrivateCrtKey; 25import java.security.interfaces.RSAPrivateKey; 26import java.security.spec.InvalidKeySpecException; 27import java.security.spec.RSAPrivateCrtKeySpec; 28 29/** 30 * An implementation of {@link java.security.PrivateKey} for RSA keys which uses BoringSSL to 31 * perform all the operations. 32 * 33 * @hide 34 */ 35@Internal 36public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey { 37 private static final long serialVersionUID = 3785291944868707197L; 38 39 private BigInteger publicExponent; 40 41 private BigInteger primeP; 42 43 private BigInteger primeQ; 44 45 private BigInteger primeExponentP; 46 47 private BigInteger primeExponentQ; 48 49 private BigInteger crtCoefficient; 50 51 OpenSSLRSAPrivateCrtKey(OpenSSLKey key) { 52 super(key); 53 } 54 55 OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) { 56 super(key, params); 57 } 58 59 public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { 60 super(init(rsaKeySpec)); 61 } 62 63 private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { 64 BigInteger modulus = rsaKeySpec.getModulus(); 65 BigInteger privateExponent = rsaKeySpec.getPrivateExponent(); 66 67 if (modulus == null) { 68 throw new InvalidKeySpecException("modulus == null"); 69 } else if (privateExponent == null) { 70 throw new InvalidKeySpecException("privateExponent == null"); 71 } 72 73 try { 74 /* 75 * OpenSSL uses the public modulus to do RSA blinding. If 76 * the public modulus is not available, the call to 77 * EVP_PKEY_new_RSA will turn off blinding for this key 78 * instance. 79 */ 80 final BigInteger publicExponent = rsaKeySpec.getPublicExponent(); 81 final BigInteger primeP = rsaKeySpec.getPrimeP(); 82 final BigInteger primeQ = rsaKeySpec.getPrimeQ(); 83 final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP(); 84 final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ(); 85 final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient(); 86 87 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 88 modulus.toByteArray(), 89 publicExponent == null ? null : publicExponent.toByteArray(), 90 privateExponent.toByteArray(), 91 primeP == null ? null : primeP.toByteArray(), 92 primeQ == null ? null : primeQ.toByteArray(), 93 primeExponentP == null ? null : primeExponentP.toByteArray(), 94 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 95 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 96 } catch (Exception e) { 97 throw new InvalidKeySpecException(e); 98 } 99 } 100 101 static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException { 102 /** 103 * If the key is not encodable (PKCS11-like key), then wrap it and use 104 * JNI upcalls to satisfy requests. 105 */ 106 if (rsaPrivateKey.getFormat() == null) { 107 return wrapPlatformKey(rsaPrivateKey); 108 } 109 110 BigInteger modulus = rsaPrivateKey.getModulus(); 111 BigInteger privateExponent = rsaPrivateKey.getPrivateExponent(); 112 113 if (modulus == null) { 114 throw new InvalidKeyException("modulus == null"); 115 } else if (privateExponent == null) { 116 throw new InvalidKeyException("privateExponent == null"); 117 } 118 119 try { 120 /* 121 * OpenSSL uses the public modulus to do RSA blinding. If 122 * the public modulus is not available, the call to 123 * EVP_PKEY_new_RSA will turn off blinding for this key 124 * instance. 125 */ 126 final BigInteger publicExponent = rsaPrivateKey.getPublicExponent(); 127 final BigInteger primeP = rsaPrivateKey.getPrimeP(); 128 final BigInteger primeQ = rsaPrivateKey.getPrimeQ(); 129 final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP(); 130 final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ(); 131 final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient(); 132 133 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 134 modulus.toByteArray(), 135 publicExponent == null ? null : publicExponent.toByteArray(), 136 privateExponent.toByteArray(), 137 primeP == null ? null : primeP.toByteArray(), 138 primeQ == null ? null : primeQ.toByteArray(), 139 primeExponentP == null ? null : primeExponentP.toByteArray(), 140 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 141 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 142 } catch (Exception e) { 143 throw new InvalidKeyException(e); 144 } 145 } 146 147 @Override 148 synchronized void readParams(byte[][] params) { 149 super.readParams(params); 150 // params[0] read in super.readParams 151 if (params[1] != null) { 152 publicExponent = new BigInteger(params[1]); 153 } 154 // params[2] read in super.readParams 155 if (params[3] != null) { 156 primeP = new BigInteger(params[3]); 157 } 158 if (params[4] != null) { 159 primeQ = new BigInteger(params[4]); 160 } 161 if (params[5] != null) { 162 primeExponentP = new BigInteger(params[5]); 163 } 164 if (params[6] != null) { 165 primeExponentQ = new BigInteger(params[6]); 166 } 167 if (params[7] != null) { 168 crtCoefficient = new BigInteger(params[7]); 169 } 170 } 171 172 @Override 173 public BigInteger getPublicExponent() { 174 ensureReadParams(); 175 return publicExponent; 176 } 177 178 @Override 179 public BigInteger getPrimeP() { 180 ensureReadParams(); 181 return primeP; 182 } 183 184 @Override 185 public BigInteger getPrimeQ() { 186 ensureReadParams(); 187 return primeQ; 188 } 189 190 @Override 191 public BigInteger getPrimeExponentP() { 192 ensureReadParams(); 193 return primeExponentP; 194 } 195 196 @Override 197 public BigInteger getPrimeExponentQ() { 198 ensureReadParams(); 199 return primeExponentQ; 200 } 201 202 @Override 203 public BigInteger getCrtCoefficient() { 204 ensureReadParams(); 205 return crtCoefficient; 206 } 207 208 @Override 209 public boolean equals(Object o) { 210 if (o == this) { 211 return true; 212 } 213 214 if (o instanceof OpenSSLRSAPrivateKey) { 215 OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o; 216 return getOpenSSLKey().equals(other.getOpenSSLKey()); 217 } 218 219 if (o instanceof RSAPrivateCrtKey) { 220 ensureReadParams(); 221 RSAPrivateCrtKey other = (RSAPrivateCrtKey) o; 222 223 return getModulus().equals(other.getModulus()) 224 && publicExponent.equals(other.getPublicExponent()) 225 && getPrivateExponent().equals(other.getPrivateExponent()) 226 && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ()) 227 && primeExponentP.equals(other.getPrimeExponentP()) 228 && primeExponentQ.equals(other.getPrimeExponentQ()) 229 && crtCoefficient.equals(other.getCrtCoefficient()); 230 } else if (o instanceof RSAPrivateKey) { 231 ensureReadParams(); 232 RSAPrivateKey other = (RSAPrivateKey) o; 233 234 return getModulus().equals(other.getModulus()) 235 && getPrivateExponent().equals(other.getPrivateExponent()); 236 } 237 238 return false; 239 } 240 241 @Override 242 public final int hashCode() { 243 int hashCode = super.hashCode(); 244 if (publicExponent != null) { 245 hashCode ^= publicExponent.hashCode(); 246 } 247 return hashCode; 248 } 249 250 @Override 251 public String toString() { 252 final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{"); 253 254 ensureReadParams(); 255 sb.append("modulus="); 256 sb.append(getModulus().toString(16)); 257 258 if (publicExponent != null) { 259 sb.append(','); 260 sb.append("publicExponent="); 261 sb.append(publicExponent.toString(16)); 262 } 263 264 sb.append('}'); 265 return sb.toString(); 266 } 267 268 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 269 stream.defaultReadObject(); 270 271 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 272 modulus.toByteArray(), 273 publicExponent == null ? null : publicExponent.toByteArray(), 274 privateExponent.toByteArray(), 275 primeP == null ? null : primeP.toByteArray(), 276 primeQ == null ? null : primeQ.toByteArray(), 277 primeExponentP == null ? null : primeExponentP.toByteArray(), 278 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 279 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 280 fetchedParams = true; 281 } 282 283 private void writeObject(ObjectOutputStream stream) throws IOException { 284 ensureReadParams(); 285 stream.defaultWriteObject(); 286 } 287} 288