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 17 package org.conscrypt; 18 19 import java.io.IOException; 20 import java.io.ObjectInputStream; 21 import java.io.ObjectOutputStream; 22 import java.math.BigInteger; 23 import java.security.InvalidKeyException; 24 import java.security.interfaces.RSAPublicKey; 25 import java.security.spec.InvalidKeySpecException; 26 import java.security.spec.RSAPublicKeySpec; 27 28 public class OpenSSLRSAPublicKey implements RSAPublicKey, OpenSSLKeyHolder { 29 private static final long serialVersionUID = 123125005824688292L; 30 31 private transient OpenSSLKey key; 32 33 private BigInteger publicExponent; 34 35 private BigInteger modulus; 36 37 private transient boolean fetchedParams; 38 OpenSSLRSAPublicKey(OpenSSLKey key)39 OpenSSLRSAPublicKey(OpenSSLKey key) { 40 this.key = key; 41 } 42 43 @Override getOpenSSLKey()44 public OpenSSLKey getOpenSSLKey() { 45 return key; 46 } 47 OpenSSLRSAPublicKey(RSAPublicKeySpec spec)48 OpenSSLRSAPublicKey(RSAPublicKeySpec spec) throws InvalidKeySpecException { 49 try { 50 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 51 spec.getModulus().toByteArray(), 52 spec.getPublicExponent().toByteArray(), 53 null, 54 null, 55 null, 56 null, 57 null, 58 null)); 59 } catch (Exception e) { 60 throw new InvalidKeySpecException(e); 61 } 62 } 63 getInstance(RSAPublicKey rsaPublicKey)64 static OpenSSLKey getInstance(RSAPublicKey rsaPublicKey) throws InvalidKeyException { 65 try { 66 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 67 rsaPublicKey.getModulus().toByteArray(), 68 rsaPublicKey.getPublicExponent().toByteArray(), 69 null, 70 null, 71 null, 72 null, 73 null, 74 null)); 75 } catch (Exception e) { 76 throw new InvalidKeyException(e); 77 } 78 } 79 80 @Override getAlgorithm()81 public String getAlgorithm() { 82 return "RSA"; 83 } 84 85 @Override getFormat()86 public String getFormat() { 87 return "X.509"; 88 } 89 90 @Override getEncoded()91 public byte[] getEncoded() { 92 return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); 93 } 94 ensureReadParams()95 private void ensureReadParams() { 96 if (fetchedParams) { 97 return; 98 } 99 100 byte[][] params = NativeCrypto.get_RSA_public_params(key.getPkeyContext()); 101 modulus = new BigInteger(params[0]); 102 publicExponent = new BigInteger(params[1]); 103 104 fetchedParams = true; 105 } 106 107 @Override getModulus()108 public BigInteger getModulus() { 109 ensureReadParams(); 110 return modulus; 111 } 112 113 @Override getPublicExponent()114 public BigInteger getPublicExponent() { 115 ensureReadParams(); 116 return publicExponent; 117 } 118 119 @Override equals(Object o)120 public boolean equals(Object o) { 121 if (o == this) { 122 return true; 123 } 124 125 if (o instanceof OpenSSLRSAPublicKey) { 126 OpenSSLRSAPublicKey other = (OpenSSLRSAPublicKey) o; 127 128 /* 129 * We can shortcut the true case, but it still may be equivalent but 130 * different copies. 131 */ 132 if (key.equals(other.getOpenSSLKey())) { 133 return true; 134 } 135 } 136 137 if (!(o instanceof RSAPublicKey)) { 138 return false; 139 } 140 141 ensureReadParams(); 142 143 RSAPublicKey other = (RSAPublicKey) o; 144 return modulus.equals(other.getModulus()) 145 && publicExponent.equals(other.getPublicExponent()); 146 } 147 148 @Override hashCode()149 public int hashCode() { 150 ensureReadParams(); 151 152 return modulus.hashCode() ^ publicExponent.hashCode(); 153 } 154 155 @Override toString()156 public String toString() { 157 ensureReadParams(); 158 159 final StringBuilder sb = new StringBuilder("OpenSSLRSAPublicKey{"); 160 sb.append("modulus="); 161 sb.append(modulus.toString(16)); 162 sb.append(','); 163 sb.append("publicExponent="); 164 sb.append(publicExponent.toString(16)); 165 sb.append('}'); 166 167 return sb.toString(); 168 } 169 readObject(ObjectInputStream stream)170 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 171 stream.defaultReadObject(); 172 173 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( 174 modulus.toByteArray(), 175 publicExponent.toByteArray(), 176 null, 177 null, 178 null, 179 null, 180 null, 181 null)); 182 fetchedParams = true; 183 } 184 writeObject(ObjectOutputStream stream)185 private void writeObject(ObjectOutputStream stream) throws IOException { 186 ensureReadParams(); 187 stream.defaultWriteObject(); 188 } 189 } 190