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.NotSerializableException; 21import java.io.ObjectInputStream; 22import java.io.ObjectOutputStream; 23import java.math.BigInteger; 24import java.security.InvalidKeyException; 25import java.security.interfaces.RSAPrivateCrtKey; 26import java.security.interfaces.RSAPrivateKey; 27import java.security.spec.InvalidKeySpecException; 28import java.security.spec.RSAPrivateCrtKeySpec; 29 30public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey { 31 private static final long serialVersionUID = 3785291944868707197L; 32 33 private BigInteger publicExponent; 34 35 private BigInteger primeP; 36 37 private BigInteger primeQ; 38 39 private BigInteger primeExponentP; 40 41 private BigInteger primeExponentQ; 42 43 private BigInteger crtCoefficient; 44 45 OpenSSLRSAPrivateCrtKey(OpenSSLKey key) { 46 super(key); 47 } 48 49 OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) { 50 super(key, params); 51 } 52 53 public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { 54 super(init(rsaKeySpec)); 55 } 56 57 private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { 58 BigInteger modulus = rsaKeySpec.getModulus(); 59 BigInteger privateExponent = rsaKeySpec.getPrivateExponent(); 60 61 if (modulus == null) { 62 throw new InvalidKeySpecException("modulus == null"); 63 } else if (privateExponent == null) { 64 throw new InvalidKeySpecException("privateExponent == null"); 65 } 66 67 try { 68 /* 69 * OpenSSL uses the public modulus to do RSA blinding. If 70 * the public modulus is not available, the call to 71 * EVP_PKEY_new_RSA will turn off blinding for this key 72 * instance. 73 */ 74 final BigInteger publicExponent = rsaKeySpec.getPublicExponent(); 75 final BigInteger primeP = rsaKeySpec.getPrimeP(); 76 final BigInteger primeQ = rsaKeySpec.getPrimeQ(); 77 final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP(); 78 final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ(); 79 final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient(); 80 81 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 82 modulus.toByteArray(), 83 publicExponent == null ? null : publicExponent.toByteArray(), 84 privateExponent.toByteArray(), 85 primeP == null ? null : primeP.toByteArray(), 86 primeQ == null ? null : primeQ.toByteArray(), 87 primeExponentP == null ? null : primeExponentP.toByteArray(), 88 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 89 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 90 } catch (Exception e) { 91 throw new InvalidKeySpecException(e); 92 } 93 } 94 95 static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException { 96 BigInteger modulus = rsaPrivateKey.getModulus(); 97 BigInteger privateExponent = rsaPrivateKey.getPrivateExponent(); 98 99 if (modulus == null) { 100 throw new InvalidKeyException("modulus == null"); 101 } else if (privateExponent == null) { 102 throw new InvalidKeyException("privateExponent == null"); 103 } 104 105 try { 106 /* 107 * OpenSSL uses the public modulus to do RSA blinding. If 108 * the public modulus is not available, the call to 109 * EVP_PKEY_new_RSA will turn off blinding for this key 110 * instance. 111 */ 112 final BigInteger publicExponent = rsaPrivateKey.getPublicExponent(); 113 final BigInteger primeP = rsaPrivateKey.getPrimeP(); 114 final BigInteger primeQ = rsaPrivateKey.getPrimeQ(); 115 final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP(); 116 final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ(); 117 final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient(); 118 119 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 120 modulus.toByteArray(), 121 publicExponent == null ? null : publicExponent.toByteArray(), 122 privateExponent.toByteArray(), 123 primeP == null ? null : primeP.toByteArray(), 124 primeQ == null ? null : primeQ.toByteArray(), 125 primeExponentP == null ? null : primeExponentP.toByteArray(), 126 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 127 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 128 } catch (Exception e) { 129 throw new InvalidKeyException(e); 130 } 131 } 132 133 @Override 134 synchronized void readParams(byte[][] params) { 135 super.readParams(params); 136 // params[0] read in super.readParams 137 if (params[1] != null) { 138 publicExponent = new BigInteger(params[1]); 139 } 140 // params[2] read in super.readParams 141 if (params[3] != null) { 142 primeP = new BigInteger(params[3]); 143 } 144 if (params[4] != null) { 145 primeQ = new BigInteger(params[4]); 146 } 147 if (params[5] != null) { 148 primeExponentP = new BigInteger(params[5]); 149 } 150 if (params[6] != null) { 151 primeExponentQ = new BigInteger(params[6]); 152 } 153 if (params[7] != null) { 154 crtCoefficient = new BigInteger(params[7]); 155 } 156 } 157 158 @Override 159 public BigInteger getPublicExponent() { 160 ensureReadParams(); 161 return publicExponent; 162 } 163 164 @Override 165 public BigInteger getPrimeP() { 166 ensureReadParams(); 167 return primeP; 168 } 169 170 @Override 171 public BigInteger getPrimeQ() { 172 ensureReadParams(); 173 return primeQ; 174 } 175 176 @Override 177 public BigInteger getPrimeExponentP() { 178 ensureReadParams(); 179 return primeExponentP; 180 } 181 182 @Override 183 public BigInteger getPrimeExponentQ() { 184 ensureReadParams(); 185 return primeExponentQ; 186 } 187 188 @Override 189 public BigInteger getCrtCoefficient() { 190 ensureReadParams(); 191 return crtCoefficient; 192 } 193 194 @Override 195 public boolean equals(Object o) { 196 if (o == this) { 197 return true; 198 } 199 200 if (o instanceof OpenSSLRSAPrivateKey) { 201 OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o; 202 return getOpenSSLKey().equals(other.getOpenSSLKey()); 203 } 204 205 if (o instanceof RSAPrivateCrtKey) { 206 ensureReadParams(); 207 RSAPrivateCrtKey other = (RSAPrivateCrtKey) o; 208 209 if (getOpenSSLKey().isEngineBased()) { 210 return getModulus().equals(other.getModulus()) 211 && publicExponent.equals(other.getPublicExponent()); 212 } else { 213 return getModulus().equals(other.getModulus()) 214 && publicExponent.equals(other.getPublicExponent()) 215 && getPrivateExponent().equals(other.getPrivateExponent()) 216 && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ()) 217 && primeExponentP.equals(other.getPrimeExponentP()) 218 && primeExponentQ.equals(other.getPrimeExponentQ()) 219 && crtCoefficient.equals(other.getCrtCoefficient()); 220 } 221 } else if (o instanceof RSAPrivateKey) { 222 ensureReadParams(); 223 RSAPrivateKey other = (RSAPrivateKey) o; 224 225 if (getOpenSSLKey().isEngineBased()) { 226 return getModulus().equals(other.getModulus()); 227 } else { 228 return getModulus().equals(other.getModulus()) 229 && getPrivateExponent().equals(other.getPrivateExponent()); 230 } 231 } 232 233 return false; 234 } 235 236 @Override 237 public final int hashCode() { 238 int hashCode = super.hashCode(); 239 if (publicExponent != null) { 240 hashCode ^= publicExponent.hashCode(); 241 } 242 return hashCode; 243 } 244 245 @Override 246 public String toString() { 247 final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{"); 248 249 final boolean engineBased = getOpenSSLKey().isEngineBased(); 250 if (engineBased) { 251 sb.append("key="); 252 sb.append(getOpenSSLKey()); 253 sb.append('}'); 254 } 255 256 ensureReadParams(); 257 sb.append("modulus="); 258 sb.append(getModulus().toString(16)); 259 sb.append(','); 260 261 if (publicExponent != null) { 262 sb.append("publicExponent="); 263 sb.append(publicExponent.toString(16)); 264 sb.append(','); 265 } 266 267 if (!engineBased) { 268 sb.append("privateExponent="); 269 sb.append(getPrivateExponent().toString(16)); 270 sb.append(','); 271 } 272 273 if (primeP != null) { 274 sb.append("primeP="); 275 sb.append(primeP.toString(16)); 276 sb.append(','); 277 } 278 279 if (primeQ != null) { 280 sb.append("primeQ="); 281 sb.append(primeQ.toString(16)); 282 sb.append(','); 283 } 284 285 if (primeExponentP != null) { 286 sb.append("primeExponentP="); 287 sb.append(primeExponentP.toString(16)); 288 sb.append(','); 289 } 290 291 if (primeExponentQ != null) { 292 sb.append("primeExponentQ="); 293 sb.append(primeExponentQ.toString(16)); 294 sb.append(','); 295 } 296 297 if (crtCoefficient != null) { 298 sb.append("crtCoefficient="); 299 sb.append(crtCoefficient.toString(16)); 300 sb.append(','); 301 } 302 303 return sb.toString(); 304 } 305 306 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 307 stream.defaultReadObject(); 308 309 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 310 modulus.toByteArray(), 311 publicExponent == null ? null : publicExponent.toByteArray(), 312 privateExponent.toByteArray(), 313 primeP == null ? null : primeP.toByteArray(), 314 primeQ == null ? null : primeQ.toByteArray(), 315 primeExponentP == null ? null : primeExponentP.toByteArray(), 316 primeExponentQ == null ? null : primeExponentQ.toByteArray(), 317 crtCoefficient == null ? null : crtCoefficient.toByteArray())); 318 fetchedParams = true; 319 } 320 321 private void writeObject(ObjectOutputStream stream) throws IOException { 322 if (getOpenSSLKey().isEngineBased()) { 323 throw new NotSerializableException("engine-based keys can not be serialized"); 324 } 325 326 ensureReadParams(); 327 stream.defaultWriteObject(); 328 } 329} 330