1 /* RSAKeyPairPKCS8Codec.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
.rsa
;
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
;
49 import gnu
.java
.security
.OID
;
50 import gnu
.java
.security
.Registry
;
51 import gnu
.java
.security
.der
.DER
;
52 import gnu
.java
.security
.der
.DERReader
;
53 import gnu
.java
.security
.der
.DERValue
;
54 import gnu
.java
.security
.der
.DERWriter
;
55 import gnu
.java
.security
.key
.IKeyPairCodec
;
56 import gnu
.java
.security
.util
.DerUtil
;
59 * An implementation of an {@link IKeyPairCodec} that knows how to encode /
60 * decode PKCS#8 ASN.1 external representation of RSA private keys.
62 public class RSAKeyPairPKCS8Codec
63 implements IKeyPairCodec
65 private static final OID RSA_ALG_OID
= new OID(Registry
.RSA_OID_STRING
);
67 // implicit 0-arguments constructor
69 public int getFormatID()
75 * @throws InvalidParameterException ALWAYS.
77 public byte[] encodePublicKey(PublicKey key
)
79 throw new InvalidParameterException("Wrong format for public keys");
83 * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of an RSA
84 * private key. The ASN.1 specification is as follows:
87 * PrivateKeyInfo ::= SEQUENCE {
88 * version INTEGER, -- MUST be 0
89 * privateKeyAlgorithm AlgorithmIdentifier,
90 * privateKey OCTET STRING
93 * AlgorithmIdentifier ::= SEQUENCE {
94 * algorithm OBJECT IDENTIFIER,
95 * parameters ANY DEFINED BY algorithm OPTIONAL
99 * <p>The <i>privateKey</i> field, which is an OCTET STRING, contains the
100 * DER-encoded form of the RSA private key defined as:</p>
103 * RSAPrivateKey ::= SEQUENCE {
104 * version INTEGER, -- MUST be 0
105 * modulus INTEGER, -- n
106 * publicExponent INTEGER, -- e
107 * privateExponent INTEGER, -- d
108 * prime1 INTEGER, -- p
109 * prime2 INTEGER, -- q
110 * exponent1 INTEGER, -- d mod (p-1)
111 * exponent2 INTEGER, -- d mod (q-1)
112 * coefficient INTEGER, -- (inverse of q) mod p
116 * @return the DER encoded form of the ASN.1 representation of the
117 * <i>PrivateKeyInfo</i> field for an RSA {@link PrivateKey}..
118 * @throw InvalidParameterException if an error occurs during the marshalling
121 public byte[] encodePrivateKey(PrivateKey key
)
123 if (! (key
instanceof GnuRSAPrivateKey
))
124 throw new InvalidParameterException("Wrong key type");
126 GnuRSAPrivateKey pk
= (GnuRSAPrivateKey
) key
;
127 BigInteger n
= pk
.getN();
128 BigInteger e
= pk
.getE();
129 BigInteger d
= pk
.getPrivateExponent();
130 BigInteger p
= pk
.getPrimeP();
131 BigInteger q
= pk
.getPrimeQ();
132 BigInteger dP
= pk
.getPrimeExponentP();
133 BigInteger dQ
= pk
.getPrimeExponentQ();
134 BigInteger qInv
= pk
.getCrtCoefficient();
136 DERValue derVersion
= new DERValue(DER
.INTEGER
, BigInteger
.ZERO
);
138 DERValue derOID
= new DERValue(DER
.OBJECT_IDENTIFIER
, RSA_ALG_OID
);
140 ArrayList algorithmID
= new ArrayList(1);
141 algorithmID
.add(derOID
);
142 DERValue derAlgorithmID
= new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
145 DERValue derRSAVersion
= new DERValue(DER
.INTEGER
, BigInteger
.ZERO
);
146 DERValue derN
= new DERValue(DER
.INTEGER
, n
);
147 DERValue derE
= new DERValue(DER
.INTEGER
, e
);
148 DERValue derD
= new DERValue(DER
.INTEGER
, d
);
149 DERValue derP
= new DERValue(DER
.INTEGER
, p
);
150 DERValue derQ
= new DERValue(DER
.INTEGER
, q
);
151 DERValue derDP
= new DERValue(DER
.INTEGER
, dP
);
152 DERValue derDQ
= new DERValue(DER
.INTEGER
, dQ
);
153 DERValue derQInv
= new DERValue(DER
.INTEGER
, qInv
);
155 ArrayList rsaPrivateKey
= new ArrayList();
156 rsaPrivateKey
.add(derRSAVersion
);
157 rsaPrivateKey
.add(derN
);
158 rsaPrivateKey
.add(derE
);
159 rsaPrivateKey
.add(derD
);
160 rsaPrivateKey
.add(derP
);
161 rsaPrivateKey
.add(derQ
);
162 rsaPrivateKey
.add(derDP
);
163 rsaPrivateKey
.add(derDQ
);
164 rsaPrivateKey
.add(derQInv
);
165 DERValue derRSAPrivateKey
= new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
,
167 byte[] pkBytes
= derRSAPrivateKey
.getEncoded();
168 DERValue derPrivateKey
= new DERValue(DER
.OCTET_STRING
, pkBytes
);
170 ArrayList pki
= new ArrayList(3);
172 pki
.add(derAlgorithmID
);
173 pki
.add(derPrivateKey
);
174 DERValue derPKI
= new DERValue(DER
.CONSTRUCTED
| DER
.SEQUENCE
, pki
);
177 ByteArrayOutputStream baos
= new ByteArrayOutputStream();
180 DERWriter
.write(baos
, derPKI
);
181 result
= baos
.toByteArray();
183 catch (IOException x
)
185 InvalidParameterException y
= new InvalidParameterException();
194 * @throws InvalidParameterException ALWAYS.
196 public PublicKey
decodePublicKey(byte[] input
)
198 throw new InvalidParameterException("Wrong format for public keys");
202 * @param input the byte array to unmarshall into a valid RSA
203 * {@link PrivateKey} instance. MUST NOT be null.
204 * @return a new instance of a {@link GnuRSAPrivateKey} decoded from the
205 * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
206 * @throw InvalidParameterException if an exception occurs during the
207 * unmarshalling process.
209 public PrivateKey
decodePrivateKey(byte[] input
)
212 throw new InvalidParameterException("Input bytes MUST NOT be null");
214 BigInteger version
, n
, e
, d
, p
, q
, dP
, dQ
, qInv
;
215 DERReader der
= new DERReader(input
);
218 DERValue derPKI
= der
.read();
219 DerUtil
.checkIsConstructed(derPKI
, "Wrong PrivateKeyInfo field");
221 DERValue derVersion
= der
.read();
222 DerUtil
.checkIsBigInteger(derVersion
, "Wrong Version field");
223 version
= (BigInteger
) derVersion
.getValue();
224 if (version
.compareTo(BigInteger
.ZERO
) != 0)
225 throw new InvalidParameterException("Unexpected Version: " + version
);
227 DERValue derAlgoritmID
= der
.read();
228 DerUtil
.checkIsConstructed(derAlgoritmID
, "Wrong AlgorithmIdentifier field");
230 DERValue derOID
= der
.read();
231 OID algOID
= (OID
) derOID
.getValue();
232 if (! algOID
.equals(RSA_ALG_OID
))
233 throw new InvalidParameterException("Unexpected OID: " + algOID
);
235 DERValue val
= der
.read();
236 byte[] pkBytes
= (byte[]) val
.getValue();
238 der
= new DERReader(pkBytes
);
239 DERValue derRSAPrivateKey
= der
.read();
240 DerUtil
.checkIsConstructed(derRSAPrivateKey
, "Wrong RSAPrivateKey field");
243 DerUtil
.checkIsBigInteger(val
, "Wrong RSAPrivateKey Version field");
244 version
= (BigInteger
) val
.getValue();
245 if (version
.compareTo(BigInteger
.ZERO
) != 0)
246 throw new InvalidParameterException("Unexpected RSAPrivateKey Version: "
250 DerUtil
.checkIsBigInteger(val
, "Wrong modulus field");
251 n
= (BigInteger
) val
.getValue();
253 DerUtil
.checkIsBigInteger(val
, "Wrong publicExponent field");
254 e
= (BigInteger
) val
.getValue();
256 DerUtil
.checkIsBigInteger(val
, "Wrong privateExponent field");
257 d
= (BigInteger
) val
.getValue();
259 DerUtil
.checkIsBigInteger(val
, "Wrong prime1 field");
260 p
= (BigInteger
) val
.getValue();
262 DerUtil
.checkIsBigInteger(val
, "Wrong prime2 field");
263 q
= (BigInteger
) val
.getValue();
265 DerUtil
.checkIsBigInteger(val
, "Wrong exponent1 field");
266 dP
= (BigInteger
) val
.getValue();
268 DerUtil
.checkIsBigInteger(val
, "Wrong exponent2 field");
269 dQ
= (BigInteger
) val
.getValue();
271 DerUtil
.checkIsBigInteger(val
, "Wrong coefficient field");
272 qInv
= (BigInteger
) val
.getValue();
274 catch (IOException x
)
276 InvalidParameterException y
= new InvalidParameterException();
281 return new GnuRSAPrivateKey(Registry
.PKCS8_ENCODING_ID
, n
, e
, d
, p
, q
,