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