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