Home | History | Annotate | Download | only in dh
      1 package org.bouncycastle.jcajce.provider.asymmetric.dh;
      2 
      3 import java.io.IOException;
      4 import java.io.ObjectInputStream;
      5 import java.io.ObjectOutputStream;
      6 import java.math.BigInteger;
      7 
      8 import javax.crypto.interfaces.DHPublicKey;
      9 import javax.crypto.spec.DHParameterSpec;
     10 import javax.crypto.spec.DHPublicKeySpec;
     11 
     12 import org.bouncycastle.asn1.ASN1Integer;
     13 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     14 import org.bouncycastle.asn1.ASN1Sequence;
     15 import org.bouncycastle.asn1.pkcs.DHParameter;
     16 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     17 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     18 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     19 import org.bouncycastle.asn1.x9.DHDomainParameters;
     20 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     21 import org.bouncycastle.crypto.params.DHPublicKeyParameters;
     22 import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
     23 
     24 public class BCDHPublicKey
     25     implements DHPublicKey
     26 {
     27     static final long serialVersionUID = -216691575254424324L;
     28 
     29     private BigInteger              y;
     30 
     31     private transient DHParameterSpec         dhSpec;
     32     private transient SubjectPublicKeyInfo    info;
     33 
     34     BCDHPublicKey(
     35         DHPublicKeySpec spec)
     36     {
     37         this.y = spec.getY();
     38         this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
     39     }
     40 
     41     BCDHPublicKey(
     42         DHPublicKey key)
     43     {
     44         this.y = key.getY();
     45         this.dhSpec = key.getParams();
     46     }
     47 
     48     BCDHPublicKey(
     49         DHPublicKeyParameters params)
     50     {
     51         this.y = params.getY();
     52         this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
     53     }
     54 
     55     BCDHPublicKey(
     56         BigInteger y,
     57         DHParameterSpec dhSpec)
     58     {
     59         this.y = y;
     60         this.dhSpec = dhSpec;
     61     }
     62 
     63     public BCDHPublicKey(
     64         SubjectPublicKeyInfo info)
     65     {
     66         this.info = info;
     67 
     68         ASN1Integer              derY;
     69         try
     70         {
     71             derY = (ASN1Integer)info.parsePublicKey();
     72         }
     73         catch (IOException e)
     74         {
     75             throw new IllegalArgumentException("invalid info structure in DH public key");
     76         }
     77 
     78         this.y = derY.getValue();
     79 
     80         ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters());
     81         ASN1ObjectIdentifier id = info.getAlgorithm().getAlgorithm();
     82 
     83         // we need the PKCS check to handle older keys marked with the X9 oid.
     84         if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
     85         {
     86             DHParameter             params = DHParameter.getInstance(seq);
     87 
     88             if (params.getL() != null)
     89             {
     90                 this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
     91             }
     92             else
     93             {
     94                 this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
     95             }
     96         }
     97         else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
     98         {
     99             DHDomainParameters params = DHDomainParameters.getInstance(seq);
    100 
    101             this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
    102         }
    103         else
    104         {
    105             throw new IllegalArgumentException("unknown algorithm type: " + id);
    106         }
    107     }
    108 
    109     public String getAlgorithm()
    110     {
    111         return "DH";
    112     }
    113 
    114     public String getFormat()
    115     {
    116         return "X.509";
    117     }
    118 
    119     public byte[] getEncoded()
    120     {
    121         if (info != null)
    122         {
    123             return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
    124         }
    125 
    126         return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y));
    127     }
    128 
    129     public DHParameterSpec getParams()
    130     {
    131         return dhSpec;
    132     }
    133 
    134     public BigInteger getY()
    135     {
    136         return y;
    137     }
    138 
    139     private boolean isPKCSParam(ASN1Sequence seq)
    140     {
    141         if (seq.size() == 2)
    142         {
    143             return true;
    144         }
    145 
    146         if (seq.size() > 3)
    147         {
    148             return false;
    149         }
    150 
    151         ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
    152         ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
    153 
    154         if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
    155         {
    156             return false;
    157         }
    158 
    159         return true;
    160     }
    161 
    162     public int hashCode()
    163     {
    164         return this.getY().hashCode() ^ this.getParams().getG().hashCode()
    165                 ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
    166     }
    167 
    168     public boolean equals(
    169         Object o)
    170     {
    171         if (!(o instanceof DHPublicKey))
    172         {
    173             return false;
    174         }
    175 
    176         DHPublicKey other = (DHPublicKey)o;
    177 
    178         return this.getY().equals(other.getY())
    179             && this.getParams().getG().equals(other.getParams().getG())
    180             && this.getParams().getP().equals(other.getParams().getP())
    181             && this.getParams().getL() == other.getParams().getL();
    182     }
    183 
    184     private void readObject(
    185         ObjectInputStream   in)
    186         throws IOException, ClassNotFoundException
    187     {
    188         in.defaultReadObject();
    189 
    190         this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
    191         this.info = null;
    192     }
    193 
    194     private void writeObject(
    195         ObjectOutputStream  out)
    196         throws IOException
    197     {
    198         out.defaultWriteObject();
    199 
    200         out.writeObject(dhSpec.getP());
    201         out.writeObject(dhSpec.getG());
    202         out.writeInt(dhSpec.getL());
    203     }
    204 }
    205