blob: 597cd3844ef9852a220f85c3f30f25a4d5e868b7 [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.PrivateKey;
32import java.security.InvalidKeyException;
33import java.security.ProviderException;
34import javax.crypto.*;
35import javax.crypto.spec.DHParameterSpec;
36import sun.security.util.*;
37
38/**
39 * A private key in PKCS#8 format for the Diffie-Hellman key agreement
40 * algorithm.
41 *
42 * @author Jan Luehe
43 *
44 *
45 * @see DHPublicKey
46 * @see java.security.KeyAgreement
47 */
48final class DHPrivateKey implements PrivateKey,
49javax.crypto.interfaces.DHPrivateKey, Serializable {
50
51 static final long serialVersionUID = 7565477590005668886L;
52
53 // only supported version of PKCS#8 PrivateKeyInfo
54 private static final BigInteger PKCS8_VERSION = BigInteger.ZERO;
55
56 // the private key
57 private BigInteger x;
58
59 // the key bytes, without the algorithm information
60 private byte[] key;
61
62 // the encoded key
63 private byte[] encodedKey;
64
65 // the prime modulus
66 private BigInteger p;
67
68 // the base generator
69 private BigInteger g;
70
71 // the private-value length
72 private int l;
73
74 private int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
75
76 /**
77 * Make a DH private key out of a private value <code>x</code>, a prime
78 * modulus <code>p</code>, and a base generator <code>g</code>.
79 *
80 * @param x the private value
81 * @param p the prime modulus
82 * @param g the base generator
83 *
84 * @exception ProviderException if the key cannot be encoded
85 */
86 DHPrivateKey(BigInteger x, BigInteger p, BigInteger g)
87 throws InvalidKeyException {
88 this(x, p, g, 0);
89 }
90
91 /**
92 * Make a DH private key out of a private value <code>x</code>, a prime
93 * modulus <code>p</code>, a base generator <code>g</code>, and a
94 * private-value length <code>l</code>.
95 *
96 * @param x the private value
97 * @param p the prime modulus
98 * @param g the base generator
99 * @param l the private-value length
100 *
101 * @exception InvalidKeyException if the key cannot be encoded
102 */
103 DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) {
104 this.x = x;
105 this.p = p;
106 this.g = g;
107 this.l = l;
108 try {
109 this.key = new DerValue(DerValue.tag_Integer,
110 this.x.toByteArray()).toByteArray();
111 this.encodedKey = getEncoded();
112 } catch (IOException e) {
113 throw new ProviderException("Cannot produce ASN.1 encoding", e);
114 }
115 }
116
117 /**
118 * Make a DH private key from its DER encoding (PKCS #8).
119 *
120 * @param encodedKey the encoded key
121 *
122 * @exception InvalidKeyException if the encoded key does not represent
123 * a Diffie-Hellman private key
124 */
125 DHPrivateKey(byte[] encodedKey) throws InvalidKeyException {
126 InputStream inStream = new ByteArrayInputStream(encodedKey);
127 try {
128 DerValue val = new DerValue(inStream);
129 if (val.tag != DerValue.tag_Sequence) {
130 throw new InvalidKeyException ("Key not a SEQUENCE");
131 }
132
133 //
134 // version
135 //
136 BigInteger parsedVersion = val.data.getBigInteger();
137 if (!parsedVersion.equals(PKCS8_VERSION)) {
138 throw new IOException("version mismatch: (supported: " +
139 PKCS8_VERSION + ", parsed: " +
140 parsedVersion);
141 }
142
143 //
144 // privateKeyAlgorithm
145 //
146 DerValue algid = val.data.getDerValue();
147 if (algid.tag != DerValue.tag_Sequence) {
148 throw new InvalidKeyException("AlgId is not a SEQUENCE");
149 }
150 DerInputStream derInStream = algid.toDerInputStream();
151 ObjectIdentifier oid = derInStream.getOID();
152 if (oid == null) {
153 throw new InvalidKeyException("Null OID");
154 }
155 if (derInStream.available() == 0) {
156 throw new InvalidKeyException("Parameters missing");
157 }
158 // parse the parameters
159 DerValue params = derInStream.getDerValue();
160 if (params.tag == DerValue.tag_Null) {
161 throw new InvalidKeyException("Null parameters");
162 }
163 if (params.tag != DerValue.tag_Sequence) {
164 throw new InvalidKeyException("Parameters not a SEQUENCE");
165 }
166 params.data.reset();
167 this.p = params.data.getBigInteger();
168 this.g = params.data.getBigInteger();
169 // Private-value length is OPTIONAL
170 if (params.data.available() != 0) {
171 this.l = params.data.getInteger();
172 }
173 if (params.data.available() != 0) {
174 throw new InvalidKeyException("Extra parameter data");
175 }
176
177 //
178 // privateKey
179 //
180 this.key = val.data.getOctetString();
181 parseKeyBits();
182
183 // ignore OPTIONAL attributes
184
185 this.encodedKey = (byte[])encodedKey.clone();
186
187 } catch (NumberFormatException e) {
188 InvalidKeyException ike = new InvalidKeyException(
189 "Private-value length too big");
190 ike.initCause(e);
191 throw ike;
192 } catch (IOException e) {
193 InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
194 ike.initCause(e);
195 throw ike;
196 }
197 }
198
199 /**
200 * Returns the encoding format of this key: "PKCS#8"
201 */
202 public String getFormat() {
203 return "PKCS#8";
204 }
205
206 /**
207 * Returns the name of the algorithm associated with this key: "DH"
208 */
209 public String getAlgorithm() {
210 return "DH";
211 }
212
213 /**
214 * Get the encoding of the key.
215 */
216 public synchronized byte[] getEncoded() {
217 if (this.encodedKey == null) {
218 try {
219 DerOutputStream tmp = new DerOutputStream();
220
221 //
222 // version
223 //
224 tmp.putInteger(PKCS8_VERSION);
225
226 //
227 // privateKeyAlgorithm
228 //
229 DerOutputStream algid = new DerOutputStream();
230
231 // store OID
232 algid.putOID(new ObjectIdentifier(DH_data));
233 // encode parameters
234 DerOutputStream params = new DerOutputStream();
235 params.putInteger(this.p);
236 params.putInteger(this.g);
237 if (this.l != 0)
238 params.putInteger(this.l);
239 // wrap parameters into SEQUENCE
240 DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
241 params.toByteArray());
242 // store parameter SEQUENCE in algid
243 algid.putDerValue(paramSequence);
244 // wrap algid into SEQUENCE
245 tmp.write(DerValue.tag_Sequence, algid);
246
247 // privateKey
248 tmp.putOctetString(this.key);
249
250 // make it a SEQUENCE
251 DerOutputStream derKey = new DerOutputStream();
252 derKey.write(DerValue.tag_Sequence, tmp);
253 this.encodedKey = derKey.toByteArray();
254 } catch (IOException e) {
255 return null;
256 }
257 }
258 return (byte[])this.encodedKey.clone();
259 }
260
261 /**
262 * Returns the private value, <code>x</code>.
263 *
264 * @return the private value, <code>x</code>
265 */
266 public BigInteger getX() {
267 return this.x;
268 }
269
270 /**
271 * Returns the key parameters.
272 *
273 * @return the key parameters
274 */
275 public DHParameterSpec getParams() {
276 if (this.l != 0)
277 return new DHParameterSpec(this.p, this.g, this.l);
278 else
279 return new DHParameterSpec(this.p, this.g);
280 }
281
282 public String toString() {
283 String LINE_SEP = System.getProperty("line.separator");
284
285 StringBuffer strbuf
286 = new StringBuffer("SunJCE Diffie-Hellman Private Key:"
287 + LINE_SEP + "x:" + LINE_SEP
288 + Debug.toHexString(this.x)
289 + LINE_SEP + "p:" + LINE_SEP
290 + Debug.toHexString(this.p)
291 + LINE_SEP + "g:" + LINE_SEP
292 + Debug.toHexString(this.g));
293 if (this.l != 0)
294 strbuf.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);
295 return strbuf.toString();
296 }
297
298 private void parseKeyBits() throws InvalidKeyException {
299 try {
300 DerInputStream in = new DerInputStream(this.key);
301 this.x = in.getBigInteger();
302 } catch (IOException e) {
303 InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
304 ike.initCause(e);
305 throw ike;
306 }
307 }
308
309 /**
310 * Calculates a hash code value for the object.
311 * Objects that are equal will also have the same hashcode.
312 */
313 public int hashCode() {
314 int retval = 0;
315 byte[] enc = getEncoded();
316
317 for (int i = 1; i < enc.length; i++) {
318 retval += enc[i] * i;
319 }
320 return(retval);
321 }
322
323 public boolean equals(Object obj) {
324 if (this == obj)
325 return true;
326
327 if (!(obj instanceof PrivateKey))
328 return false;
329
330 byte[] thisEncoded = this.getEncoded();
331 byte[] thatEncoded = ((PrivateKey)obj).getEncoded();
332
333 return java.util.Arrays.equals(thisEncoded, thatEncoded);
334 }
335
336 /**
337 * Replace the DH private key to be serialized.
338 *
339 * @return the standard KeyRep object to be serialized
340 *
341 * @throws java.io.ObjectStreamException if a new object representing
342 * this DH private key could not be created
343 */
344 private Object writeReplace() throws java.io.ObjectStreamException {
345 return new KeyRep(KeyRep.Type.PRIVATE,
346 getAlgorithm(),
347 getFormat(),
348 getEncoded());
349 }
350}