Source for gnu.java.security.key.KeyPairCodecFactory

   1: /* KeyPairCodecFactory.java --
   2:    Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a 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 of the License, or (at
   9: your option) 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; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: 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.key;
  40: 
  41: import gnu.java.security.Registry;
  42: import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
  43: import gnu.java.security.key.dss.DSSKeyPairRawCodec;
  44: import gnu.java.security.key.dss.DSSKeyPairX509Codec;
  45: import gnu.java.security.key.dss.DSSPrivateKey;
  46: import gnu.java.security.key.dss.DSSPublicKey;
  47: import gnu.java.security.key.rsa.GnuRSAPrivateKey;
  48: import gnu.java.security.key.rsa.GnuRSAPublicKey;
  49: import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
  50: import gnu.java.security.key.rsa.RSAKeyPairRawCodec;
  51: import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
  52: import gnu.java.security.util.FormatUtil;
  53: 
  54: import java.lang.reflect.Constructor;
  55: import java.security.Key;
  56: import java.util.Collections;
  57: import java.util.HashSet;
  58: import java.util.Set;
  59: 
  60: /**
  61:  * A <i>Factory</i> class to instantiate key encoder/decoder instances.
  62:  */
  63: public class KeyPairCodecFactory
  64: {
  65:   private static Set names;
  66: 
  67:   /** Trivial constructor to enforce Singleton pattern. */
  68:   private KeyPairCodecFactory()
  69:   {
  70:     super();
  71:   }
  72: 
  73:   /**
  74:    * Returns the appropriate codec given a composed key-pair generator algorithm
  75:    * and an encoding format. A composed name is formed by the concatenation of
  76:    * the canonical key-pair algorithm name, the forward slash character
  77:    * <code>/</code> and the canonical name of the encoding format.
  78:    * <p>
  79:    * <b>IMPORTANT</b>: For backward compatibility, when the encoding format
  80:    * name is missing, the Raw encoding format is assumed. When this is the case
  81:    * the trailing forward slash is discarded from the name.
  82:    *
  83:    * @param name the case-insensitive key codec name.
  84:    * @return an instance of the keypair codec, or <code>null</code> if none
  85:    *         found.
  86:    */
  87:   public static IKeyPairCodec getInstance(String name)
  88:   {
  89:     if (name == null)
  90:       return null;
  91: 
  92:     name = name.trim();
  93:     if (name.length() == 0)
  94:       return null;
  95: 
  96:     if (name.startsWith("/"))
  97:       return null;
  98: 
  99:     if (name.endsWith("/"))
 100:       return getInstance(name.substring(0, name.length() - 1),
 101:                          Registry.RAW_ENCODING_ID);
 102: 
 103:     int i = name.indexOf("/");
 104:     if (i == -1)
 105:       return getInstance(name, Registry.RAW_ENCODING_ID);
 106: 
 107:     String kpgName = name.substring(0, i);
 108:     String formatName = name.substring(i + 1);
 109:     return getInstance(kpgName, formatName);
 110:   }
 111: 
 112:   /**
 113:    * Returns an instance of a keypair codec given the canonical name of the
 114:    * key-pair algorithm, and the name of the encoding format to use when
 115:    * externalizing the keys.
 116:    *
 117:    * @param name the case-insensitive key-pair algorithm name.
 118:    * @param format the name of the encoding format to use when externalizing the
 119:    *          keys generated by the key-pair algorithm.
 120:    * @return an instance of the key-pair codec, or <code>null</code> if none
 121:    *         found.
 122:    */
 123:   public static IKeyPairCodec getInstance(String name, String format)
 124:   {
 125:     int formatID = FormatUtil.getFormatID(format);
 126:     if (formatID == 0)
 127:       return null;
 128: 
 129:     return getInstance(name, formatID);
 130:   }
 131: 
 132:   /**
 133:    * Returns an instance of a keypair codec given the canonical name of the
 134:    * key-pair algorithm, and the identifier of the format to use when
 135:    * externalizing the keys.
 136:    *
 137:    * @param name the case-insensitive key-pair algorithm name.
 138:    * @param formatID the identifier of the format to use when externalizing the
 139:    *          keys generated by the key-pair algorithm.
 140:    * @return an instance of the key-pair codec, or <code>null</code> if none
 141:    *         found.
 142:    */
 143:   public static IKeyPairCodec getInstance(String name, int formatID)
 144:   {
 145:     if (name == null)
 146:       return null;
 147: 
 148:     name = name.trim();
 149:     switch (formatID)
 150:       {
 151:       case Registry.RAW_ENCODING_ID:
 152:         return getRawCodec(name);
 153:       case Registry.X509_ENCODING_ID:
 154:         return getX509Codec(name);
 155:       case Registry.PKCS8_ENCODING_ID:
 156:         return getPKCS8Codec(name);
 157:       }
 158: 
 159:     return null;
 160:   }
 161: 
 162:   /**
 163:    * Returns an instance of a keypair codec given a key.
 164:    *
 165:    * @param key the key to encode.
 166:    * @return an instance of the keypair codec, or <code>null</code> if none
 167:    *         found.
 168:    */
 169:   public static IKeyPairCodec getInstance(Key key)
 170:   {
 171:     if (key == null)
 172:       return null;
 173: 
 174:     String format = key.getFormat();
 175:     int formatID = FormatUtil.getFormatID(format);
 176:     if (formatID == 0)
 177:       return null;
 178: 
 179:     switch (formatID)
 180:       {
 181:       case Registry.RAW_ENCODING_ID:
 182:         return getRawCodec(key);
 183:       case Registry.X509_ENCODING_ID:
 184:         return getX509Codec(key);
 185:       case Registry.PKCS8_ENCODING_ID:
 186:         return getPKCS8Codec(key);
 187:       }
 188: 
 189:     return null;
 190:   }
 191: 
 192:   /**
 193:    * Returns a {@link Set} of supported key-pair codec names.
 194:    *
 195:    * @return a {@link Set} of the names of supported key-pair codec (Strings).
 196:    */
 197:   public static synchronized final Set getNames()
 198:   {
 199:     if (names == null)
 200:       {
 201:         HashSet hs = new HashSet();
 202:         hs.add(Registry.DSS_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
 203:         hs.add(Registry.DSS_KPG + "/" + Registry.X509_ENCODING_SORT_NAME);
 204:         hs.add(Registry.DSS_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME);
 205:         hs.add(Registry.RSA_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
 206:         hs.add(Registry.RSA_KPG + "/" + Registry.X509_ENCODING_SORT_NAME);
 207:         hs.add(Registry.RSA_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME);
 208:         hs.add(Registry.DH_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
 209:         hs.add(Registry.SRP_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME);
 210:         names = Collections.unmodifiableSet(hs);
 211:       }
 212:     return names;
 213:   }
 214: 
 215:   private static IKeyPairCodec makeInstance (String clazz)
 216:   {
 217:     try
 218:       {
 219:         Class c = Class.forName (clazz);
 220:         Constructor ctor = c.getConstructor (new Class[0]);
 221:         return (IKeyPairCodec) ctor.newInstance (new Object[0]);
 222:       }
 223:     catch (Exception x)
 224:       {
 225:         IllegalArgumentException iae =
 226:           new IllegalArgumentException ("strong crypto key codec not available: "
 227:                                         + clazz);
 228:         iae.initCause (x);
 229:         throw iae;
 230:       }
 231:   }
 232: 
 233:   private static boolean matches (Object o, String clazz)
 234:   {
 235:     try
 236:       {
 237:         Class c = Class.forName (clazz);
 238:         return c.isAssignableFrom (o.getClass ());
 239:       }
 240:     catch (Exception x)
 241:       {
 242:         // Can't match.
 243:         return false;
 244:       }
 245:   }
 246: 
 247:   /**
 248:    * @param name the trimmed name of a key-pair algorithm.
 249:    * @return a Raw format codec for the designated key-pair algorithm, or
 250:    *         <code>null</code> if none exists.
 251:    */
 252:   private static IKeyPairCodec getRawCodec(String name)
 253:   {
 254:     IKeyPairCodec result = null;
 255:     if (name.equalsIgnoreCase(Registry.DSA_KPG)
 256:         || name.equals(Registry.DSS_KPG))
 257:       result = new DSSKeyPairRawCodec();
 258:     else if (name.equalsIgnoreCase(Registry.RSA_KPG))
 259:       result = new RSAKeyPairRawCodec();
 260:     else if (name.equalsIgnoreCase(Registry.DH_KPG))
 261:       result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec");
 262:     else if (name.equalsIgnoreCase(Registry.SRP_KPG))
 263:       result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec");
 264: 
 265:     return result;
 266:   }
 267: 
 268:   /**
 269:    * @param name the trimmed name of a key-pair algorithm.
 270:    * @return a X.509 format codec for the designated key-pair algorithm, or
 271:    *         <code>null</code> if none exists.
 272:    */
 273:   private static IKeyPairCodec getX509Codec(String name)
 274:   {
 275:     IKeyPairCodec result = null;
 276:     if (name.equalsIgnoreCase(Registry.DSA_KPG)
 277:         || name.equals(Registry.DSS_KPG))
 278:       result = new DSSKeyPairX509Codec();
 279:     else if (name.equalsIgnoreCase(Registry.RSA_KPG))
 280:       result = new RSAKeyPairX509Codec();
 281:     else if (name.equalsIgnoreCase(Registry.DH_KPG))
 282:       result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairX509Codec");
 283: 
 284:     return result;
 285:   }
 286: 
 287:   /**
 288:    * @param name the trimmed name of a key-pair algorithm.
 289:    * @return a PKCS#8 format codec for the designated key-pair algorithm, or
 290:    *         <code>null</code> if none exists.
 291:    */
 292:   private static IKeyPairCodec getPKCS8Codec(String name)
 293:   {
 294:     IKeyPairCodec result = null;
 295:     if (name.equalsIgnoreCase(Registry.DSA_KPG)
 296:         || name.equals(Registry.DSS_KPG))
 297:       result = new DSSKeyPairPKCS8Codec();
 298:     else if (name.equalsIgnoreCase(Registry.RSA_KPG))
 299:       result = new RSAKeyPairPKCS8Codec();
 300:     else if (name.equalsIgnoreCase(Registry.DH_KPG))
 301:       result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec");
 302: 
 303:     return result;
 304:   }
 305: 
 306:   /**
 307:    * @param key a {@link Key} for which we want to return a Raw codec.
 308:    * @return the Raw codec corresponding to the key, or <code>null</code> if
 309:    *         none exists for this key.
 310:    */
 311:   private static IKeyPairCodec getRawCodec(Key key)
 312:   {
 313:     IKeyPairCodec result = null;
 314:     if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey))
 315:       result = new DSSKeyPairRawCodec();
 316:     else if ((key instanceof GnuRSAPublicKey)
 317:              || (key instanceof GnuRSAPrivateKey))
 318:       result = new RSAKeyPairRawCodec();
 319:     else if (matches(key, "gnu.javax.crypto.key.dh.GnuDHPublicKey")
 320:              || matches(key, "gnu.javax.crypto.key.dh.GnuDHPrivateKey"))
 321:       result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec");
 322:     else if (matches(key, "gnu.javax.crypto.key.srp6.SRPPublicKey")
 323:              || matches(key, "gnu.javax.crypto.key.srp6.SRPPrivateKey"))
 324:       result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec");
 325: 
 326:     return result;
 327:   }
 328: 
 329:   /**
 330:    * @param key a {@link Key} for which we want to return an X.509 codec.
 331:    * @return the X.509 codec corresponding to the key, or <code>null</code> if
 332:    *         none exists for this key.
 333:    */
 334:   private static IKeyPairCodec getX509Codec(Key key)
 335:   {
 336:     IKeyPairCodec result = null;
 337:     if (key instanceof DSSPublicKey)
 338:       result = new DSSKeyPairX509Codec();
 339:     else if (key instanceof GnuRSAPublicKey)
 340:       result = new RSAKeyPairX509Codec();
 341: 
 342:     return result;
 343:   }
 344: 
 345:   /**
 346:    * @param key a {@link Key} for which we want to return a PKCS#8 codec.
 347:    * @return the PKCS#8 codec corresponding to the key, or <code>null</code> if
 348:    *         none exists for this key.
 349:    */
 350:   private static IKeyPairCodec getPKCS8Codec(Key key)
 351:   {
 352:     IKeyPairCodec result = null;
 353:     if (key instanceof DSSPrivateKey)
 354:       result = new DSSKeyPairPKCS8Codec();
 355:     else if (key instanceof GnuRSAPrivateKey)
 356:       result = new RSAKeyPairPKCS8Codec();
 357: 
 358:     return result;
 359:   }
 360: }