Home | History | Annotate | Download | only in conscrypt
      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 
     39     OpenSSLRSAPublicKey(OpenSSLKey key) {
     40         this.key = key;
     41     }
     42 
     43     @Override
     44     public OpenSSLKey getOpenSSLKey() {
     45         return key;
     46     }
     47 
     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 
     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
     81     public String getAlgorithm() {
     82         return "RSA";
     83     }
     84 
     85     @Override
     86     public String getFormat() {
     87         return "X.509";
     88     }
     89 
     90     @Override
     91     public byte[] getEncoded() {
     92         return NativeCrypto.i2d_PUBKEY(key.getPkeyContext());
     93     }
     94 
     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
    108     public BigInteger getModulus() {
    109         ensureReadParams();
    110         return modulus;
    111     }
    112 
    113     @Override
    114     public BigInteger getPublicExponent() {
    115         ensureReadParams();
    116         return publicExponent;
    117     }
    118 
    119     @Override
    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
    149     public int hashCode() {
    150         ensureReadParams();
    151 
    152         return modulus.hashCode() ^ publicExponent.hashCode();
    153     }
    154 
    155     @Override
    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 
    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 
    185     private void writeObject(ObjectOutputStream stream) throws IOException {
    186         ensureReadParams();
    187         stream.defaultWriteObject();
    188     }
    189 }
    190