Source for gnu.java.security.jce.sig.EncodedKeyFactory

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