1 /* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package gnu.java.security.key.dss;
41 import gnu.java.security.Configuration;
42 import gnu.java.security.OID;
43 import gnu.java.security.Registry;
44 import gnu.java.security.der.DER;
45 import gnu.java.security.der.DERReader;
46 import gnu.java.security.der.DERValue;
47 import gnu.java.security.der.DERWriter;
48 import gnu.java.security.key.IKeyPairCodec;
49 import gnu.java.security.util.DerUtil;
50 import gnu.java.security.util.Util;
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.math.BigInteger;
55 import java.security.InvalidParameterException;
56 import java.security.PrivateKey;
57 import java.security.PublicKey;
58 import java.util.ArrayList;
59 import java.util.logging.Logger;
62 * An implementation of an {@link IKeyPairCodec} that knows how to encode /
63 * decode PKCS#8 ASN.1 external representation of DSS private keys.
65 * @author Casey Marshall (rsdio@metastatic.org)
67 public class DSSKeyPairPKCS8Codec
68 implements IKeyPairCodec
70 private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName());
71 private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
73 // implicit 0-arguments constructor
75 public int getFormatID()
81 * @throws InvalidParameterException ALWAYS.
83 public byte[] encodePublicKey(PublicKey key)
85 throw new InvalidParameterException("Wrong format for public keys");
89 * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
90 * private key. The ASN.1 specification is as follows:
93 * PrivateKeyInfo ::= SEQUENCE {
94 * version INTEGER, -- MUST be 0
95 * privateKeyAlgorithm AlgorithmIdentifier,
96 * privateKey OCTET STRING
99 * AlgorithmIdentifier ::= SEQUENCE {
100 * algorithm OBJECT IDENTIFIER,
101 * parameters ANY DEFINED BY algorithm OPTIONAL
104 * DssParams ::= SEQUENCE {
111 * @return the DER encoded form of the ASN.1 representation of the
112 * <i>PrivateKeyInfo</i> field in an X.509 certificate.
113 * @throw InvalidParameterException if an error occurs during the marshalling
116 public byte[] encodePrivateKey(PrivateKey key)
118 if (! (key instanceof DSSPrivateKey))
119 throw new InvalidParameterException("Wrong key type");
121 DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
123 DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
125 DSSPrivateKey pk = (DSSPrivateKey) key;
126 BigInteger p = pk.getParams().getP();
127 BigInteger q = pk.getParams().getQ();
128 BigInteger g = pk.getParams().getG();
129 BigInteger x = pk.getX();
131 ArrayList params = new ArrayList(3);
132 params.add(new DERValue(DER.INTEGER, p));
133 params.add(new DERValue(DER.INTEGER, q));
134 params.add(new DERValue(DER.INTEGER, g));
135 DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
137 ArrayList algorithmID = new ArrayList(2);
138 algorithmID.add(derOID);
139 algorithmID.add(derParams);
140 DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
143 // The OCTET STRING is the DER encoding of an INTEGER.
144 DERValue derX = new DERValue(DER.INTEGER, x);
145 DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
147 ArrayList pki = new ArrayList(3);
149 pki.add(derAlgorithmID);
150 pki.add(derPrivateKey);
151 DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
154 ByteArrayOutputStream baos = new ByteArrayOutputStream();
157 DERWriter.write(baos, derPKI);
158 result = baos.toByteArray();
160 catch (IOException e)
162 InvalidParameterException y = new InvalidParameterException(e.getMessage());
170 * @throws InvalidParameterException ALWAYS.
172 public PublicKey decodePublicKey(byte[] input)
174 throw new InvalidParameterException("Wrong format for public keys");
178 * @param input the byte array to unmarshall into a valid DSS
179 * {@link PrivateKey} instance. MUST NOT be null.
180 * @return a new instance of a {@link DSSPrivateKey} decoded from the
181 * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
182 * @throw InvalidParameterException if an exception occurs during the
183 * unmarshalling process.
185 public PrivateKey decodePrivateKey(byte[] input)
187 if (Configuration.DEBUG)
188 log.entering(this.getClass().getName(), "decodePrivateKey");
190 throw new InvalidParameterException("Input bytes MUST NOT be null");
192 BigInteger version, p, q, g, x;
193 DERReader der = new DERReader(input);
196 DERValue derPKI = der.read();
197 DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
199 DERValue derVersion = der.read();
200 if (! (derVersion.getValue() instanceof BigInteger))
201 throw new InvalidParameterException("Wrong Version field");
203 version = (BigInteger) derVersion.getValue();
204 if (version.compareTo(BigInteger.ZERO) != 0)
205 throw new InvalidParameterException("Unexpected Version: " + version);
207 DERValue derAlgoritmID = der.read();
208 DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
210 DERValue derOID = der.read();
211 OID algOID = (OID) derOID.getValue();
212 if (! algOID.equals(DSA_ALG_OID))
213 throw new InvalidParameterException("Unexpected OID: " + algOID);
215 DERValue derParams = der.read();
216 DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
218 DERValue val = der.read();
219 DerUtil.checkIsBigInteger(val, "Wrong P field");
220 p = (BigInteger) val.getValue();
222 DerUtil.checkIsBigInteger(val, "Wrong Q field");
223 q = (BigInteger) val.getValue();
225 DerUtil.checkIsBigInteger(val, "Wrong G field");
226 g = (BigInteger) val.getValue();
229 if (Configuration.DEBUG)
230 log.fine("val = " + val);
231 byte[] xBytes = (byte[]) val.getValue();
232 if (Configuration.DEBUG)
233 log.fine(Util.dumpString(xBytes, "xBytes: "));
234 DERReader der2 = new DERReader(xBytes);
236 DerUtil.checkIsBigInteger(val, "Wrong X field");
237 x = (BigInteger) val.getValue();
239 catch (IOException e)
241 InvalidParameterException y = new InvalidParameterException(e.getMessage());
245 if (Configuration.DEBUG)
246 log.exiting(this.getClass().getName(), "decodePrivateKey");
247 return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);