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

   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: 
  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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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: }