OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / javax / crypto / key / dh / DHKeyPairX509Codec.java
1 /* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.javax.crypto.key.dh;
40
41 import java.io.ByteArrayOutputStream;
42 import java.io.IOException;
43 import java.math.BigInteger;
44 import java.security.InvalidParameterException;
45 import java.security.PrivateKey;
46 import java.security.PublicKey;
47 import java.util.ArrayList;
48
49 import gnu.java.security.OID;
50 import gnu.java.security.Registry;
51 import gnu.java.security.der.BitString;
52 import gnu.java.security.der.DER;
53 import gnu.java.security.der.DERReader;
54 import gnu.java.security.der.DERValue;
55 import gnu.java.security.der.DERWriter;
56 import gnu.java.security.key.IKeyPairCodec;
57 import gnu.java.security.util.DerUtil;
58
59 public class DHKeyPairX509Codec
60     implements IKeyPairCodec
61 {
62   private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
63
64   // implicit 0-arguments constructor
65
66   public int getFormatID()
67   {
68     return X509_FORMAT;
69   }
70
71   /**
72    * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i>
73    * representation of a DH public key. The ASN.1 specification, as defined in
74    * RFC-3280, and RFC-2459, is as follows:
75    *
76    * <pre>
77    *   SubjectPublicKeyInfo ::= SEQUENCE {
78    *     algorithm         AlgorithmIdentifier,
79    *     subjectPublicKey  BIT STRING
80    *   }
81    *
82    *   AlgorithmIdentifier ::= SEQUENCE {
83    *     algorithm   OBJECT IDENTIFIER,
84    *     parameters  ANY DEFINED BY algorithm OPTIONAL
85    *   }
86    *
87    *   DhParams ::= SEQUENCE {
88    *     p  INTEGER, -- odd prime, p=jq +1
89    *     g  INTEGER, -- generator, g
90    *     q  INTEGER  -- factor of p-1
91    *   }
92    * </pre>
93    * 
94    * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
95    * DER-encoded form of the DH public key as an INTEGER.</p>
96    * 
97    * <pre>
98    *       DHPublicKey ::= INTEGER -- public key, y = g^x mod p
99    * </pre>
100    * <p>
101    * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec}
102    * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with
103    * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code>
104    * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
105    * parameter, hence we replace such null values with <code>0</code>, and do
106    * the reverse in the corresponding decode method.
107    * 
108    * @param key the {@link PublicKey} instance to encode. MUST be an instance of
109    *          {@link GnuDHPublicKey}.
110    * @return the DER-encoded form of the ASN.1 representation of the
111    *         <i>SubjectPublicKeyInfo</i> in an X.509 certificate.
112    * @throw InvalidParameterException if <code>key</code> is not an instance
113    *        of {@link GnuDHPublicKey} or if an exception occurs during the
114    *        marshalling process.
115    */
116   public byte[] encodePublicKey(PublicKey key)
117   {
118     if (! (key instanceof GnuDHPublicKey))
119       throw new InvalidParameterException("Wrong key type");
120
121     DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
122
123     GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
124     BigInteger p = dhKey.getParams().getP();
125     BigInteger g = dhKey.getParams().getG();
126     BigInteger q = dhKey.getQ();
127     if (q == null)
128       q = BigInteger.ZERO;
129     BigInteger y = dhKey.getY();
130
131     DERValue derP = new DERValue(DER.INTEGER, p);
132     DERValue derG = new DERValue(DER.INTEGER, g);
133     DERValue derQ = new DERValue(DER.INTEGER, q);
134
135     ArrayList params = new ArrayList(3);
136     params.add(derP);
137     params.add(derG);
138     params.add(derQ);
139     DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
140
141     ArrayList algorithmID = new ArrayList(2);
142     algorithmID.add(derOID);
143     algorithmID.add(derParams);
144     DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
145                                            algorithmID);
146
147     DERValue derDHPublicKey = new DERValue(DER.INTEGER, y);
148     byte[] yBytes = derDHPublicKey.getEncoded();
149     DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
150
151     ArrayList spki = new ArrayList(2);
152     spki.add(derAlgorithmID);
153     spki.add(derSPK);
154     DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
155
156     byte[] result;
157     ByteArrayOutputStream baos = new ByteArrayOutputStream();
158     try
159       {
160         DERWriter.write(baos, derSPKI);
161         result = baos.toByteArray();
162       }
163     catch (IOException x)
164       {
165         InvalidParameterException e = new InvalidParameterException();
166         e.initCause(x);
167         throw e;
168       }
169
170     return result;
171   }
172
173   /**
174    * @throws InvalidParameterException ALWAYS.
175    */
176   public byte[] encodePrivateKey(PrivateKey key)
177   {
178     throw new InvalidParameterException("Wrong format for private keys");
179   }
180
181   /**
182    * @param input the byte array to unmarshall into a valid DH
183    *          {@link PublicKey} instance. MUST NOT be null.
184    * @return a new instance of a {@link GnuDHPublicKey} decoded from the
185    *         <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
186    * @throw InvalidParameterException if an exception occurs during the
187    *        unmarshalling process.
188    */
189   public PublicKey decodePublicKey(byte[] input)
190   {
191     if (input == null)
192       throw new InvalidParameterException("Input bytes MUST NOT be null");
193
194     BigInteger p, g, q, y;
195     DERReader der = new DERReader(input);
196     try
197       {
198         DERValue derSPKI = der.read();
199         DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
200
201         DERValue derAlgorithmID = der.read();
202         DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
203
204         DERValue derOID = der.read();
205         if (! (derOID.getValue() instanceof OID))
206           throw new InvalidParameterException("Wrong Algorithm field");
207
208         OID algOID = (OID) derOID.getValue();
209         if (! algOID.equals(DH_ALG_OID))
210           throw new InvalidParameterException("Unexpected OID: " + algOID);
211
212         DERValue derParams = der.read();
213         DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field");
214
215         DERValue val = der.read();
216         DerUtil.checkIsBigInteger(val, "Wrong P field");
217         p = (BigInteger) val.getValue();
218         val = der.read();
219         DerUtil.checkIsBigInteger(val, "Wrong G field");
220         g = (BigInteger) val.getValue();
221         val = der.read();
222         DerUtil.checkIsBigInteger(val, "Wrong Q field");
223         q = (BigInteger) val.getValue();
224         if (q.compareTo(BigInteger.ZERO) == 0)
225           q = null;
226
227         val = der.read();
228         if (! (val.getValue() instanceof BitString))
229           throw new InvalidParameterException("Wrong SubjectPublicKey field");
230
231         byte[] yBytes = ((BitString) val.getValue()).toByteArray();
232
233         DERReader dhPub = new DERReader(yBytes);
234         val = dhPub.read();
235         DerUtil.checkIsBigInteger(val, "Wrong Y field");
236         y = (BigInteger) val.getValue();
237       }
238     catch (IOException x)
239       {
240         InvalidParameterException e = new InvalidParameterException();
241         e.initCause(x);
242         throw e;
243       }
244
245     return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y);
246   }
247
248   /**
249    * @throws InvalidParameterException ALWAYS.
250    */
251   public PrivateKey decodePrivateKey(byte[] input)
252   {
253     throw new InvalidParameterException("Wrong format for private keys");
254   }
255 }