Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2014 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.spec.InvalidKeySpecException;
     25 import javax.crypto.interfaces.DHPublicKey;
     26 import javax.crypto.spec.DHParameterSpec;
     27 import javax.crypto.spec.DHPublicKeySpec;
     28 
     29 public class OpenSSLDHPublicKey implements DHPublicKey, OpenSSLKeyHolder {
     30     private static final long serialVersionUID = 6123717708079837723L;
     31 
     32     private transient OpenSSLKey key;
     33 
     34     /** base prime */
     35     private transient byte[] p;
     36 
     37     /** generator */
     38     private transient byte[] g;
     39 
     40     /** public key */
     41     private transient byte[] y;
     42 
     43     private transient final Object mParamsLock = new Object();
     44 
     45     private transient boolean readParams;
     46 
     47     OpenSSLDHPublicKey(OpenSSLKey key) {
     48         this.key = key;
     49     }
     50 
     51     @Override
     52     public OpenSSLKey getOpenSSLKey() {
     53         return key;
     54     }
     55 
     56     OpenSSLDHPublicKey(DHPublicKeySpec dsaKeySpec) throws InvalidKeySpecException {
     57         try {
     58             key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
     59                     dsaKeySpec.getP().toByteArray(),
     60                     dsaKeySpec.getG().toByteArray(),
     61                     dsaKeySpec.getY().toByteArray(),
     62                     null));
     63         } catch (Exception e) {
     64             throw new InvalidKeySpecException(e);
     65         }
     66     }
     67 
     68     private void ensureReadParams() {
     69         synchronized (mParamsLock) {
     70             if (readParams) {
     71                 return;
     72             }
     73 
     74             byte[][] params = NativeCrypto.get_DH_params(key.getPkeyContext());
     75 
     76             p = params[0];
     77             g = params[1];
     78             y = params[2];
     79 
     80             readParams = true;
     81         }
     82     }
     83 
     84     static OpenSSLKey getInstance(DHPublicKey DHPublicKey) throws InvalidKeyException {
     85         try {
     86             final DHParameterSpec dhParams = DHPublicKey.getParams();
     87             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
     88                     dhParams.getP().toByteArray(),
     89                     dhParams.getG().toByteArray(),
     90                     DHPublicKey.getY().toByteArray(),
     91                     null));
     92         } catch (Exception e) {
     93             throw new InvalidKeyException(e);
     94         }
     95     }
     96 
     97     @Override
     98     public DHParameterSpec getParams() {
     99         ensureReadParams();
    100         return new DHParameterSpec(new BigInteger(p), new BigInteger(g));
    101     }
    102 
    103     @Override
    104     public String getAlgorithm() {
    105         return "DH";
    106     }
    107 
    108     @Override
    109     public String getFormat() {
    110         return "X.509";
    111     }
    112 
    113     @Override
    114     public byte[] getEncoded() {
    115         return NativeCrypto.i2d_PUBKEY(key.getPkeyContext());
    116     }
    117 
    118     @Override
    119     public BigInteger getY() {
    120         ensureReadParams();
    121         return new BigInteger(y);
    122     }
    123 
    124     @Override
    125     public boolean equals(Object o) {
    126         if (o == this) {
    127             return true;
    128         }
    129 
    130         if (o instanceof OpenSSLDHPublicKey) {
    131             OpenSSLDHPublicKey other = (OpenSSLDHPublicKey) o;
    132 
    133             /*
    134              * We can shortcut the true case, but it still may be equivalent but
    135              * different copies.
    136              */
    137             if (key.equals(other.getOpenSSLKey())) {
    138                 return true;
    139             }
    140         }
    141 
    142         if (!(o instanceof DHPublicKey)) {
    143             return false;
    144         }
    145 
    146         ensureReadParams();
    147 
    148         final DHPublicKey other = (DHPublicKey) o;
    149         if (!y.equals(other.getY())) {
    150             return false;
    151         }
    152 
    153         DHParameterSpec spec = other.getParams();
    154         return g.equals(spec.getG()) && p.equals(spec.getP());
    155     }
    156 
    157     @Override
    158     public int hashCode() {
    159         ensureReadParams();
    160         int hash = 1;
    161         hash = hash * 3 + y.hashCode();
    162         hash = hash * 7 + p.hashCode();
    163         hash = hash * 13 + g.hashCode();
    164         return hash;
    165     }
    166 
    167 
    168     @Override
    169     public String toString() {
    170         ensureReadParams();
    171 
    172         final StringBuilder sb = new StringBuilder("OpenSSLDHPublicKey{");
    173         sb.append("Y=");
    174         sb.append(new BigInteger(y).toString(16));
    175         sb.append(',');
    176         sb.append("P=");
    177         sb.append(new BigInteger(p).toString(16));
    178         sb.append(',');
    179         sb.append("G=");
    180         sb.append(new BigInteger(g).toString(16));
    181         sb.append('}');
    182 
    183         return sb.toString();
    184     }
    185 
    186     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    187         stream.defaultReadObject();
    188 
    189         final BigInteger g = (BigInteger) stream.readObject();
    190         final BigInteger p = (BigInteger) stream.readObject();
    191         final BigInteger y = (BigInteger) stream.readObject();
    192 
    193         key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
    194                 p.toByteArray(),
    195                 g.toByteArray(),
    196                 y.toByteArray(),
    197                 null));
    198     }
    199 
    200     private void writeObject(ObjectOutputStream stream) throws IOException {
    201         stream.defaultWriteObject();
    202 
    203         ensureReadParams();
    204         stream.writeObject(new BigInteger(g));
    205         stream.writeObject(new BigInteger(p));
    206         stream.writeObject(new BigInteger(y));
    207     }
    208 }
    209