1 /* EncodedKeyFactory.java -- JCE Encoded key factory Adapter
2    Copyright (C) 2006, 2010  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.java.security.jce.sig;
40 
41 import gnu.java.security.Configuration;
42 import gnu.java.security.Registry;
43 import gnu.java.security.key.dss.DSSPrivateKey;
44 import gnu.java.security.key.dss.DSSPublicKey;
45 import gnu.java.security.key.rsa.GnuRSAPrivateKey;
46 import gnu.java.security.key.rsa.GnuRSAPublicKey;
47 
48 import java.lang.reflect.Constructor;
49 import java.lang.reflect.InvocationTargetException;
50 import java.lang.reflect.Method;
51 import java.math.BigInteger;
52 import java.security.InvalidKeyException;
53 import java.security.InvalidParameterException;
54 import java.security.Key;
55 import java.security.KeyFactorySpi;
56 import java.security.PrivateKey;
57 import java.security.PublicKey;
58 import java.security.spec.DSAPrivateKeySpec;
59 import java.security.spec.DSAPublicKeySpec;
60 import java.security.spec.InvalidKeySpecException;
61 import java.security.spec.KeySpec;
62 import java.security.spec.PKCS8EncodedKeySpec;
63 import java.security.spec.RSAPrivateCrtKeySpec;
64 import java.security.spec.RSAPublicKeySpec;
65 import java.security.spec.X509EncodedKeySpec;
66 import java.util.logging.Level;
67 import java.util.logging.Logger;
68 
69 import javax.crypto.interfaces.DHPrivateKey;
70 import javax.crypto.interfaces.DHPublicKey;
71 import javax.crypto.spec.DHPrivateKeySpec;
72 import javax.crypto.spec.DHPublicKeySpec;
73 
74 /**
75  * A factory for keys encoded in either the X.509 format (for public keys) or
76  * the PKCS#8 format (for private keys).
77  */
78 public class EncodedKeyFactory
79     extends KeyFactorySpi
80 {
81   private static final Logger log = Configuration.DEBUG ?
82                 Logger.getLogger(EncodedKeyFactory.class.getName()) : null;
83 
invokeConstructor(String className, Object[] params)84   private static Object invokeConstructor(String className, Object[] params)
85       throws InvalidKeySpecException
86   {
87     Class clazz = getConcreteClass(className);
88     try
89       {
90         Constructor ctor = getConcreteCtor(clazz);
91         Object result = ctor.newInstance(params);
92         return result;
93       }
94     catch (InstantiationException x)
95       {
96         throw new InvalidKeySpecException(x.getMessage(), x);
97       }
98     catch (IllegalAccessException x)
99       {
100         throw new InvalidKeySpecException(x.getMessage(), x);
101       }
102     catch (InvocationTargetException x)
103       {
104         throw new InvalidKeySpecException(x.getMessage(), x);
105       }
106   }
107 
getConcreteClass(String className)108   private static Class getConcreteClass(String className)
109       throws InvalidKeySpecException
110   {
111     try
112       {
113         Class result = Class.forName(className);
114         return result;
115       }
116     catch (ClassNotFoundException x)
117       {
118         throw new InvalidKeySpecException(x.getMessage(), x);
119       }
120   }
121 
getConcreteCtor(Class clazz)122   private static Constructor getConcreteCtor(Class clazz)
123       throws InvalidKeySpecException
124   {
125     try
126       {
127         Constructor result = clazz.getConstructor(new Class[] {int.class,
128                                                                BigInteger.class,
129                                                                BigInteger.class,
130                                                                BigInteger.class,
131                                                                BigInteger.class});
132         return result;
133       }
134     catch (NoSuchMethodException x)
135       {
136         throw new InvalidKeySpecException(x.getMessage(), x);
137       }
138   }
139 
invokeValueOf(String className, byte[] encoded)140   private static Object invokeValueOf(String className, byte[] encoded)
141       throws InvalidKeySpecException
142   {
143     Class clazz = getConcreteClass(className);
144     try
145       {
146         Method valueOf = getValueOfMethod(clazz);
147         Object result = valueOf.invoke(null, new Object[] { encoded });
148         return result;
149       }
150     catch (IllegalAccessException x)
151       {
152         throw new InvalidKeySpecException(x.getMessage(), x);
153       }
154     catch (InvocationTargetException x)
155       {
156         throw new InvalidKeySpecException(x.getMessage(), x);
157       }
158   }
159 
getValueOfMethod(Class clazz)160   private static Method getValueOfMethod(Class clazz)
161       throws InvalidKeySpecException
162   {
163     try
164       {
165         Method result = clazz.getMethod("valueOf", new Class[] {byte[].class});
166         return result;
167       }
168     catch (NoSuchMethodException x)
169       {
170         throw new InvalidKeySpecException(x.getMessage(), x);
171       }
172   }
173 
engineGeneratePublic(KeySpec keySpec)174   protected PublicKey engineGeneratePublic(KeySpec keySpec)
175       throws InvalidKeySpecException
176   {
177     if (Configuration.DEBUG)
178       log.entering(this.getClass().getName(), "engineGeneratePublic()", keySpec);
179     PublicKey result = null;
180     if (keySpec instanceof DSAPublicKeySpec)
181       result = decodeDSSPublicKey((DSAPublicKeySpec) keySpec);
182     else if (keySpec instanceof RSAPublicKeySpec)
183       result = decodeRSAPublicKey((RSAPublicKeySpec) keySpec);
184     else if (keySpec instanceof DHPublicKeySpec)
185       result = decodeDHPublicKey((DHPublicKeySpec) keySpec);
186     else
187       {
188         if (! (keySpec instanceof X509EncodedKeySpec))
189           throw new InvalidKeySpecException("Unsupported key specification");
190 
191         byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded();
192         boolean ok = false;
193         // try DSS
194         try
195           {
196             result = DSSPublicKey.valueOf(input);
197             ok = true;
198           }
199         catch (InvalidParameterException ignored)
200           {
201             if (Configuration.DEBUG)
202               log.log(Level.FINE, "Exception in DSSPublicKey.valueOf(). Ignore",
203                       ignored);
204           }
205         if (! ok) // try RSA
206           try
207             {
208               result = GnuRSAPublicKey.valueOf(input);
209               ok = true;
210             }
211           catch (InvalidParameterException ignored)
212             {
213               if (Configuration.DEBUG)
214                 log.log(Level.FINE,
215                         "Exception in GnuRSAPublicKey.valueOf(). Ignore",
216                         ignored);
217             }
218           if (! ok) // try DH
219             result = decodeDHPublicKey(input);
220       }
221     if (Configuration.DEBUG)
222       log.exiting(this.getClass().getName(), "engineGeneratePublic()", result);
223     return result;
224   }
225 
engineGeneratePrivate(KeySpec keySpec)226   protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
227       throws InvalidKeySpecException
228   {
229     if (Configuration.DEBUG)
230       log.entering(this.getClass().getName(), "engineGeneratePrivate()", keySpec);
231     PrivateKey result = null;
232     if (keySpec instanceof DSAPrivateKeySpec)
233       result = decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec);
234     else if (keySpec instanceof RSAPrivateCrtKeySpec)
235       result = decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec);
236     else if (keySpec instanceof DHPrivateKeySpec)
237       result = decodeDHPrivateKey((DHPrivateKeySpec) keySpec);
238     else
239       {
240         if (! (keySpec instanceof PKCS8EncodedKeySpec))
241           throw new InvalidKeySpecException("Unsupported key specification");
242 
243         byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded();
244         boolean ok = false;
245         // try DSS
246         try
247           {
248             result = DSSPrivateKey.valueOf(input);
249             ok = true;
250           }
251         catch (InvalidParameterException ignored)
252           {
253             if (Configuration.DEBUG)
254               log.log(Level.FINE, "Exception in DSSPrivateKey.valueOf(). Ignore",
255                       ignored);
256           }
257         if (! ok) // try RSA
258           try
259             {
260               result = GnuRSAPrivateKey.valueOf(input);
261               ok = true;
262             }
263           catch (InvalidParameterException ignored)
264             {
265               if (Configuration.DEBUG)
266                 log.log(Level.FINE,
267                         "Exception in GnuRSAPrivateKey.valueOf(). Ignore",
268                         ignored);
269             }
270         if (! ok) // try DH
271           result = decodeDHPrivateKey(input);
272       }
273     if (Configuration.DEBUG)
274       log.exiting(this.getClass().getName(), "engineGeneratePrivate()", result);
275     return result;
276   }
277 
engineGetKeySpec(Key key, Class keySpec)278   protected KeySpec engineGetKeySpec(Key key, Class keySpec)
279       throws InvalidKeySpecException
280   {
281     if (key instanceof PublicKey
282         && Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())
283         && keySpec.isAssignableFrom(X509EncodedKeySpec.class))
284       return new X509EncodedKeySpec(key.getEncoded());
285 
286     if (key instanceof PrivateKey
287         && Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())
288         && keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
289       return new PKCS8EncodedKeySpec(key.getEncoded());
290 
291     throw new InvalidKeySpecException("Unsupported format or invalid key spec class");
292   }
293 
engineTranslateKey(Key key)294   protected Key engineTranslateKey(Key key) throws InvalidKeyException
295   {
296     throw new InvalidKeyException("Key translation not supported");
297   }
298 
299   /**
300    * @param spec an instance of {@link DSAPublicKeySpec} to decode.
301    * @return an instance of {@link DSSPublicKey} constructed from the
302    *         information in the designated key-specification.
303    */
decodeDSSPublicKey(DSAPublicKeySpec spec)304   private DSSPublicKey decodeDSSPublicKey(DSAPublicKeySpec spec)
305   {
306     BigInteger p = spec.getP();
307     BigInteger q = spec.getQ();
308     BigInteger g = spec.getG();
309     BigInteger y = spec.getY();
310     return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
311   }
312 
313   /**
314    * @param spec an instance of {@link RSAPublicKeySpec} to decode.
315    * @return an instance of {@link GnuRSAPublicKey} constructed from the
316    *         information in the designated key-specification.
317    */
decodeRSAPublicKey(RSAPublicKeySpec spec)318   private GnuRSAPublicKey decodeRSAPublicKey(RSAPublicKeySpec spec)
319   {
320     BigInteger n = spec.getModulus();
321     BigInteger e = spec.getPublicExponent();
322     return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
323   }
324 
325   /**
326    * @param spec an instance of {@link DHPublicKeySpec} to decode.
327    * @return an instance of a {@link DHPublicKey} constructed from the
328    *         information in the designated key-specification.
329    * @throws InvalidKeySpecException if no concrete implementation of the
330    *           {@link DHPublicKey} interface exists at run-time, or if an
331    *           exception occurs during its instantiation.
332    */
decodeDHPublicKey(DHPublicKeySpec spec)333   private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec)
334       throws InvalidKeySpecException
335   {
336     BigInteger p = spec.getP();
337     BigInteger g = spec.getG();
338     BigInteger y = spec.getY();
339     Object[] params = new Object[] {Integer.valueOf(Registry.X509_ENCODING_ID),
340                                     null, p, g, y};
341     Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey",
342                                    params);
343     return (DHPublicKey) obj;
344   }
345 
346   /**
347    * @param encoded the bytes to decode.
348    * @return an instance of a {@link DHPublicKey} constructed from the
349    *         information in the designated key-specification.
350    * @throws InvalidKeySpecException if no concrete implementation of the
351    *           {@link DHPublicKey} interface exists at run-time, or if an
352    *           exception occurs during its instantiation.
353    */
decodeDHPublicKey(byte[] encoded)354   private DHPublicKey decodeDHPublicKey(byte[] encoded)
355       throws InvalidKeySpecException
356   {
357     Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey",
358                                encoded);
359     return (DHPublicKey) obj;
360   }
361 
362   /**
363    * @param spec an instance of {@link DSAPrivateKeySpec} to decode.
364    * @return an instance of {@link DSSPrivateKey} constructed from the
365    *         information in the designated key-specification.
366    */
decodeDSSPrivateKey(DSAPrivateKeySpec spec)367   private PrivateKey decodeDSSPrivateKey(DSAPrivateKeySpec spec)
368   {
369     BigInteger p = spec.getP();
370     BigInteger q = spec.getQ();
371     BigInteger g = spec.getG();
372     BigInteger x = spec.getX();
373     return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
374   }
375 
376   /**
377    * @param spec an instance of {@link RSAPrivateCrtKeySpec} to decode.
378    * @return an instance of {@link GnuRSAPrivateKey} constructed from the
379    *         information in the designated key-specification.
380    */
decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec)381   private PrivateKey decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec)
382   {
383     BigInteger n = spec.getModulus();
384     BigInteger e = spec.getPublicExponent();
385     BigInteger d = spec.getPrivateExponent();
386     BigInteger p = spec.getPrimeP();
387     BigInteger q = spec.getPrimeQ();
388     BigInteger dP = spec.getPrimeExponentP();
389     BigInteger dQ = spec.getPrimeExponentQ();
390     BigInteger qInv = spec.getCrtCoefficient();
391     return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
392                                 n, e, d, p, q, dP, dQ, qInv);
393   }
394 
395   /**
396    * @param spec an instance of {@link DHPrivateKeySpec} to decode.
397    * @return an instance of a {@link DHPrivateKey} constructed from the
398    *         information in the designated key-specification.
399    * @throws InvalidKeySpecException if no concrete implementation of the
400    *           {@link DHPrivateKey} interface exists at run-time, or if an
401    *           exception occurs during its instantiation.
402    */
decodeDHPrivateKey(DHPrivateKeySpec spec)403   private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec)
404       throws InvalidKeySpecException
405   {
406     BigInteger p = spec.getP();
407     BigInteger g = spec.getG();
408     BigInteger x = spec.getX();
409     Object[] params = new Object[] {Integer.valueOf(Registry.PKCS8_ENCODING_ID),
410                                     null, p, g, x};
411     Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
412                                    params);
413     return (DHPrivateKey) obj;
414   }
415 
416   /**
417    * @param encoded the bytes to decode.
418    * @return an instance of a {@link DHPrivateKey} constructed from the
419    *         information in the designated key-specification.
420    * @throws InvalidKeySpecException if no concrete implementation of the
421    *           {@link DHPrivateKey} interface exists at run-time, or if an
422    *           exception occurs during its instantiation.
423    */
decodeDHPrivateKey(byte[] encoded)424   private DHPrivateKey decodeDHPrivateKey(byte[] encoded)
425       throws InvalidKeySpecException
426   {
427     Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
428                                encoded);
429     return (DHPrivateKey) obj;
430   }
431 }
432