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