blob: d46fede772a5bc1eb270eb30a8d26ddc6c80cffe [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.crypto.provider;
27
28import java.io.*;
29import java.math.BigInteger;
30import java.security.KeyRep;
31import java.security.InvalidKeyException;
32import java.security.InvalidAlgorithmParameterException;
33import java.security.ProviderException;
34import java.security.PublicKey;
35import javax.crypto.*;
36import javax.crypto.spec.DHParameterSpec;
37import sun.security.util.*;
38
39
40/**
41 * A public key in X.509 format for the Diffie-Hellman key agreement algorithm.
42 *
43 * @author Jan Luehe
44 *
45 *
46 * @see DHPrivateKey
47 * @see java.security.KeyAgreement
48 */
49final class DHPublicKey implements PublicKey,
50javax.crypto.interfaces.DHPublicKey, Serializable {
51
52 static final long serialVersionUID = 7647557958927458271L;
53
54 // the public key
55 private BigInteger y;
56
57 // the key bytes, without the algorithm information
58 private byte[] key;
59
60 // the encoded key
61 private byte[] encodedKey;
62
63 // the prime modulus
64 private BigInteger p;
65
66 // the base generator
67 private BigInteger g;
68
69 // the private-value length
70 private int l;
71
72 private int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
73
74 /**
75 * Make a DH public key out of a public value <code>y</code>, a prime
76 * modulus <code>p</code>, and a base generator <code>g</code>.
77 *
78 * @param y the public value
79 * @param p the prime modulus
80 * @param g the base generator
81 *
82 * @exception InvalidKeyException if the key cannot be encoded
83 */
84 DHPublicKey(BigInteger y, BigInteger p, BigInteger g)
85 throws InvalidKeyException {
86 this(y, p, g, 0);
87 }
88
89 /**
90 * Make a DH public key out of a public value <code>y</code>, a prime
91 * modulus <code>p</code>, a base generator <code>g</code>, and a
92 * private-value length <code>l</code>.
93 *
94 * @param y the public value
95 * @param p the prime modulus
96 * @param g the base generator
97 * @param l the private-value length
98 *
99 * @exception ProviderException if the key cannot be encoded
100 */
101 DHPublicKey(BigInteger y, BigInteger p, BigInteger g, int l) {
102 this.y = y;
103 this.p = p;
104 this.g = g;
105 this.l = l;
106 try {
107 this.key = new DerValue(DerValue.tag_Integer,
108 this.y.toByteArray()).toByteArray();
109 this.encodedKey = getEncoded();
110 } catch (IOException e) {
111 throw new ProviderException("Cannot produce ASN.1 encoding", e);
112 }
113 }
114
115 /**
116 * Make a DH public key from its DER encoding (X.509).
117 *
118 * @param encodedKey the encoded key
119 *
120 * @exception InvalidKeyException if the encoded key does not represent
121 * a Diffie-Hellman public key
122 */
123 DHPublicKey(byte[] encodedKey) throws InvalidKeyException {
124 InputStream inStream = new ByteArrayInputStream(encodedKey);
125 try {
126 DerValue derKeyVal = new DerValue(inStream);
127 if (derKeyVal.tag != DerValue.tag_Sequence) {
128 throw new InvalidKeyException ("Invalid key format");
129 }
130
131 /*
132 * Parse the algorithm identifier
133 */
134 DerValue algid = derKeyVal.data.getDerValue();
135 if (algid.tag != DerValue.tag_Sequence) {
136 throw new InvalidKeyException("AlgId is not a SEQUENCE");
137 }
138 DerInputStream derInStream = algid.toDerInputStream();
139 ObjectIdentifier oid = derInStream.getOID();
140 if (oid == null) {
141 throw new InvalidKeyException("Null OID");
142 }
143 if (derInStream.available() == 0) {
144 throw new InvalidKeyException("Parameters missing");
145 }
146
147 /*
148 * Parse the parameters
149 */
150 DerValue params = derInStream.getDerValue();
151 if (params.tag == DerValue.tag_Null) {
152 throw new InvalidKeyException("Null parameters");
153 }
154 if (params.tag != DerValue.tag_Sequence) {
155 throw new InvalidKeyException("Parameters not a SEQUENCE");
156 }
157 params.data.reset();
158 this.p = params.data.getBigInteger();
159 this.g = params.data.getBigInteger();
160 // Private-value length is OPTIONAL
161 if (params.data.available() != 0) {
162 this.l = params.data.getInteger();
163 }
164 if (params.data.available() != 0) {
165 throw new InvalidKeyException("Extra parameter data");
166 }
167
168 /*
169 * Parse the key
170 */
171 this.key = derKeyVal.data.getBitString();
172 parseKeyBits();
173 if (derKeyVal.data.available() != 0) {
174 throw new InvalidKeyException("Excess key data");
175 }
176
177 this.encodedKey = (byte[])encodedKey.clone();
178
179 } catch (NumberFormatException e) {
180 throw new InvalidKeyException("Private-value length too big");
181
182 } catch (IOException e) {
183 throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
184 }
185 }
186
187 /**
188 * Returns the encoding format of this key: "X.509"
189 */
190 public String getFormat() {
191 return "X.509";
192 }
193
194 /**
195 * Returns the name of the algorithm associated with this key: "DH"
196 */
197 public String getAlgorithm() {
198 return "DH";
199 }
200
201 /**
202 * Get the encoding of the key.
203 */
204 public synchronized byte[] getEncoded() {
205 if (this.encodedKey == null) {
206 try {
207 DerOutputStream algid = new DerOutputStream();
208
209 // store oid in algid
210 algid.putOID(new ObjectIdentifier(DH_data));
211
212 // encode parameters
213 DerOutputStream params = new DerOutputStream();
214 params.putInteger(this.p);
215 params.putInteger(this.g);
216 if (this.l != 0)
217 params.putInteger(this.l);
218 // wrap parameters into SEQUENCE
219 DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
220 params.toByteArray());
221 // store parameter SEQUENCE in algid
222 algid.putDerValue(paramSequence);
223
224 // wrap algid into SEQUENCE, and store it in key encoding
225 DerOutputStream tmpDerKey = new DerOutputStream();
226 tmpDerKey.write(DerValue.tag_Sequence, algid);
227
228 // store key data
229 tmpDerKey.putBitString(this.key);
230
231 // wrap algid and key into SEQUENCE
232 DerOutputStream derKey = new DerOutputStream();
233 derKey.write(DerValue.tag_Sequence, tmpDerKey);
234 this.encodedKey = derKey.toByteArray();
235 } catch (IOException e) {
236 return null;
237 }
238 }
239 return (byte[])this.encodedKey.clone();
240 }
241
242 /**
243 * Returns the public value, <code>y</code>.
244 *
245 * @return the public value, <code>y</code>
246 */
247 public BigInteger getY() {
248 return this.y;
249 }
250
251 /**
252 * Returns the key parameters.
253 *
254 * @return the key parameters
255 */
256 public DHParameterSpec getParams() {
257 if (this.l != 0)
258 return new DHParameterSpec(this.p, this.g, this.l);
259 else
260 return new DHParameterSpec(this.p, this.g);
261 }
262
263 public String toString() {
264 String LINE_SEP = System.getProperty("line.separator");
265
266 StringBuffer strbuf
267 = new StringBuffer("SunJCE Diffie-Hellman Public Key:"
268 + LINE_SEP + "y:" + LINE_SEP
269 + Debug.toHexString(this.y)
270 + LINE_SEP + "p:" + LINE_SEP
271 + Debug.toHexString(this.p)
272 + LINE_SEP + "g:" + LINE_SEP
273 + Debug.toHexString(this.g));
274 if (this.l != 0)
275 strbuf.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);
276 return strbuf.toString();
277 }
278
279 private void parseKeyBits() throws InvalidKeyException {
280 try {
281 DerInputStream in = new DerInputStream(this.key);
282 this.y = in.getBigInteger();
283 } catch (IOException e) {
284 throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
285 }
286 }
287
288 /**
289 * Calculates a hash code value for the object.
290 * Objects that are equal will also have the same hashcode.
291 */
292 public int hashCode() {
293 int retval = 0;
294 byte[] enc = getEncoded();
295
296 for (int i = 1; i < enc.length; i++) {
297 retval += enc[i] * i;
298 }
299 return(retval);
300 }
301
302 public boolean equals(Object obj) {
303 if (this == obj)
304 return true;
305
306 if (!(obj instanceof PublicKey))
307 return false;
308
309 byte[] thisEncoded = this.getEncoded();
310 byte[] thatEncoded = ((PublicKey)obj).getEncoded();
311
312 return java.util.Arrays.equals(thisEncoded, thatEncoded);
313 }
314
315 /**
316 * Replace the DH public key to be serialized.
317 *
318 * @return the standard KeyRep object to be serialized
319 *
320 * @throws java.io.ObjectStreamException if a new object representing
321 * this DH public key could not be created
322 */
323 private Object writeReplace() throws java.io.ObjectStreamException {
324 return new KeyRep(KeyRep.Type.PUBLIC,
325 getAlgorithm(),
326 getFormat(),
327 getEncoded());
328 }
329}