1 /* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
2 Copyright (C) 2006, 2010 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 = Configuration.DEBUG ?
71 Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName()) : null;
73 private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
75 // implicit 0-arguments constructor
77 public int getFormatID()
83 * @throws InvalidParameterException ALWAYS.
85 public byte[] encodePublicKey(PublicKey key)
87 throw new InvalidParameterException("Wrong format for public keys");
91 * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
92 * private key. The ASN.1 specification is as follows:
95 * PrivateKeyInfo ::= SEQUENCE {
96 * version INTEGER, -- MUST be 0
97 * privateKeyAlgorithm AlgorithmIdentifier,
98 * privateKey OCTET STRING
101 * AlgorithmIdentifier ::= SEQUENCE {
102 * algorithm OBJECT IDENTIFIER,
103 * parameters ANY DEFINED BY algorithm OPTIONAL
106 * DssParams ::= SEQUENCE {
113 * @return the DER encoded form of the ASN.1 representation of the
114 * <i>PrivateKeyInfo</i> field in an X.509 certificate.
115 * @throw InvalidParameterException if an error occurs during the marshalling
118 public byte[] encodePrivateKey(PrivateKey key)
120 if (! (key instanceof DSSPrivateKey))
121 throw new InvalidParameterException("Wrong key type");
123 DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
125 DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
127 DSSPrivateKey pk = (DSSPrivateKey) key;
128 BigInteger p = pk.getParams().getP();
129 BigInteger q = pk.getParams().getQ();
130 BigInteger g = pk.getParams().getG();
131 BigInteger x = pk.getX();
133 ArrayList params = new ArrayList(3);
134 params.add(new DERValue(DER.INTEGER, p));
135 params.add(new DERValue(DER.INTEGER, q));
136 params.add(new DERValue(DER.INTEGER, g));
137 DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
139 ArrayList algorithmID = new ArrayList(2);
140 algorithmID.add(derOID);
141 algorithmID.add(derParams);
142 DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
145 // The OCTET STRING is the DER encoding of an INTEGER.
146 DERValue derX = new DERValue(DER.INTEGER, x);
147 DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
149 ArrayList pki = new ArrayList(3);
151 pki.add(derAlgorithmID);
152 pki.add(derPrivateKey);
153 DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
156 ByteArrayOutputStream baos = new ByteArrayOutputStream();
159 DERWriter.write(baos, derPKI);
160 result = baos.toByteArray();
162 catch (IOException e)
164 InvalidParameterException y = new InvalidParameterException(e.getMessage());
172 * @throws InvalidParameterException ALWAYS.
174 public PublicKey decodePublicKey(byte[] input)
176 throw new InvalidParameterException("Wrong format for public keys");
180 * @param input the byte array to unmarshall into a valid DSS
181 * {@link PrivateKey} instance. MUST NOT be null.
182 * @return a new instance of a {@link DSSPrivateKey} decoded from the
183 * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
184 * @throw InvalidParameterException if an exception occurs during the
185 * unmarshalling process.
187 public PrivateKey decodePrivateKey(byte[] input)
189 if (Configuration.DEBUG)
190 log.entering(this.getClass().getName(), "decodePrivateKey");
192 throw new InvalidParameterException("Input bytes MUST NOT be null");
194 BigInteger version, p, q, g, x;
195 DERReader der = new DERReader(input);
198 DERValue derPKI = der.read();
199 DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
201 DERValue derVersion = der.read();
202 if (! (derVersion.getValue() instanceof BigInteger))
203 throw new InvalidParameterException("Wrong Version field");
205 version = (BigInteger) derVersion.getValue();
206 if (version.compareTo(BigInteger.ZERO) != 0)
207 throw new InvalidParameterException("Unexpected Version: " + version);
209 DERValue derAlgoritmID = der.read();
210 DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
212 DERValue derOID = der.read();
213 OID algOID = (OID) derOID.getValue();
214 if (! algOID.equals(DSA_ALG_OID))
215 throw new InvalidParameterException("Unexpected OID: " + algOID);
217 DERValue derParams = der.read();
218 DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
220 DERValue val = der.read();
221 DerUtil.checkIsBigInteger(val, "Wrong P field");
222 p = (BigInteger) val.getValue();
224 DerUtil.checkIsBigInteger(val, "Wrong Q field");
225 q = (BigInteger) val.getValue();
227 DerUtil.checkIsBigInteger(val, "Wrong G field");
228 g = (BigInteger) val.getValue();
231 if (Configuration.DEBUG)
232 log.fine("val = " + val);
233 byte[] xBytes = (byte[]) val.getValue();
234 if (Configuration.DEBUG)
235 log.fine(Util.dumpString(xBytes, "xBytes: "));
236 DERReader der2 = new DERReader(xBytes);
238 DerUtil.checkIsBigInteger(val, "Wrong X field");
239 x = (BigInteger) val.getValue();
241 catch (IOException e)
243 InvalidParameterException y = new InvalidParameterException(e.getMessage());
247 if (Configuration.DEBUG)
248 log.exiting(this.getClass().getName(), "decodePrivateKey");
249 return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);