Source for javax.crypto.KeyAgreement

   1: /* KeyAgreement.java -- Engine for key agreement methods.
   2:    Copyright (C) 2004  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 javax.crypto;
  40: 
  41: import gnu.java.security.Engine;
  42: 
  43: import java.lang.reflect.InvocationTargetException;
  44: import java.security.InvalidAlgorithmParameterException;
  45: import java.security.InvalidKeyException;
  46: import java.security.Key;
  47: import java.security.NoSuchAlgorithmException;
  48: import java.security.NoSuchProviderException;
  49: import java.security.Provider;
  50: import java.security.SecureRandom;
  51: import java.security.Security;
  52: import java.security.spec.AlgorithmParameterSpec;
  53: 
  54: /**
  55:  * Key agreement is a method in which two or more parties may agree on a
  56:  * secret key for symmetric cryptography or message authentication
  57:  * without transmitting any secrets in the clear. Key agreement
  58:  * algorithms typically use a public/private <i>key pair</i>, and the
  59:  * public key (along with some additional information) is sent across
  60:  * untrusted networks.
  61:  *
  62:  * <p>The most common form of key agreement used today is the
  63:  * <i>Diffie-Hellman key exchange algorithm</i>, described in <a
  64:  * href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/">PKCS #3 -
  65:  * Diffie Hellman Key Agreement Standard</a>.
  66:  *
  67:  * @author Casey Marshall (csm@gnu.org)
  68:  * @since 1.4
  69:  * @see KeyGenerator
  70:  * @see SecretKey
  71:  */
  72: public class KeyAgreement
  73: {
  74: 
  75:   // Fields.
  76:   // ------------------------------------------------------------------------
  77: 
  78:   private static final String SERVICE = "KeyAgreement";
  79: 
  80:   /** The underlying key agreement implementation. */
  81:   private KeyAgreementSpi kaSpi;
  82: 
  83:   /** The provider of this implementation. */
  84:   private Provider provider;
  85: 
  86:   /** The name of this instance's algorithm. */
  87:   private String algorithm;
  88: 
  89:   /** Singnals whether or not this instance has been initialized. */
  90:   private boolean virgin;
  91: 
  92:   // Constructor.
  93:   // ------------------------------------------------------------------------
  94: 
  95:   protected KeyAgreement(KeyAgreementSpi kaSpi, Provider provider,
  96:                          String algorithm)
  97:   {
  98:     this.kaSpi = kaSpi;
  99:     this.provider = provider;
 100:     this.algorithm = algorithm;
 101:     virgin = true;
 102:   }
 103: 
 104:   /**
 105:    * Get an implementation of an algorithm from the first provider that
 106:    * implements it.
 107:    *
 108:    * @param algorithm The name of the algorithm to get.
 109:    * @return The proper KeyAgreement instacne, if found.
 110:    * @throws NoSuchAlgorithmException If the specified algorithm is not
 111:    *           implemented by any installed provider.
 112:    * @throws IllegalArgumentException if <code>algorithm</code> is
 113:    *           <code>null</code> or is an empty string.
 114:    */
 115:   public static final KeyAgreement getInstance(String algorithm)
 116:       throws NoSuchAlgorithmException
 117:   {
 118:     Provider[] p = Security.getProviders();
 119:     NoSuchAlgorithmException lastException = null;
 120:     for (int i = 0; i < p.length; i++)
 121:       try
 122:         {
 123:           return getInstance(algorithm, p[i]);
 124:         }
 125:       catch (NoSuchAlgorithmException x)
 126:         {
 127:           lastException = x;
 128:         }
 129:     if (lastException != null)
 130:       throw lastException;
 131:     throw new NoSuchAlgorithmException(algorithm);
 132:   }
 133: 
 134:   /**
 135:    * Return an implementation of an algorithm from a named provider.
 136:    *
 137:    * @param algorithm The name of the algorithm to create.
 138:    * @param provider The name of the provider from which to get the
 139:    *          implementation.
 140:    * @return The proper KeyAgreement instance, if found.
 141:    * @throws NoSuchAlgorithmException If the named provider does not implement
 142:    *           the algorithm.
 143:    * @throws NoSuchProviderException If the named provider does not exist.
 144:    * @throws IllegalArgumentException if either <code>algorithm</code> or
 145:    *           <code>provider</code> is <code>null</code>, or if
 146:    *           <code>algorithm</code> is an empty string.
 147:    */
 148:   public static final KeyAgreement getInstance(String algorithm, String provider)
 149:       throws NoSuchAlgorithmException, NoSuchProviderException
 150:   {
 151:     if (provider == null)
 152:       throw new IllegalArgumentException("provider MUST NOT be null");
 153:     Provider p = Security.getProvider(provider);
 154:     if (p == null)
 155:       throw new NoSuchProviderException(provider);
 156:     return getInstance(algorithm, p);
 157:   }
 158: 
 159:   /**
 160:    * Return an implementation of an algorithm from a specific provider.
 161:    *
 162:    * @param algorithm The name of the algorithm to get.
 163:    * @param provider The provider from which to get the implementation.
 164:    * @return The proper KeyAgreement instance, if found.
 165:    * @throws NoSuchAlgorithmException If this provider does not implement the
 166:    *           algorithm.
 167:    * @throws IllegalArgumentException if either <code>algorithm</code> or
 168:    *           <code>provider</code> is <code>null</code>, or if
 169:    *           <code>algorithm</code> is an empty string.
 170:    */
 171:   public static final KeyAgreement getInstance(String algorithm,
 172:                                                Provider provider)
 173:     throws NoSuchAlgorithmException
 174:   {
 175:     StringBuilder sb = new StringBuilder("KeyAgreement algorithm [")
 176:         .append(algorithm).append("] from provider[")
 177:         .append(provider).append("] could not be created");
 178:     Throwable cause;
 179:     try
 180:       {
 181:         Object spi = Engine.getInstance(SERVICE, algorithm, provider);
 182:         return new KeyAgreement((KeyAgreementSpi) spi, provider, algorithm);
 183:       }
 184:     catch (InvocationTargetException x)
 185:       {
 186:         cause = x.getCause();
 187:         if (cause instanceof NoSuchAlgorithmException)
 188:           throw (NoSuchAlgorithmException) cause;
 189:         if (cause == null)
 190:           cause = x;
 191:       }
 192:     catch (ClassCastException x)
 193:       {
 194:         cause = x;
 195:       }
 196:     NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
 197:     x.initCause(cause);
 198:     throw x;
 199:   }
 200: 
 201:   /**
 202:    * Do a phase in the key agreement. The number of times this method is
 203:    * called depends upon the algorithm and the number of parties
 204:    * involved, but must be called at least once with the
 205:    * <code>lastPhase</code> flag set to <code>true</code>.
 206:    *
 207:    * @param key       The key for this phase.
 208:    * @param lastPhase Should be <code>true</code> if this will be the
 209:    *        last phase before generating the shared secret.
 210:    * @return The intermediate result, or <code>null</code> if there is
 211:    *         no intermediate result.
 212:    * @throws java.lang.IllegalStateException If this instance has not
 213:    *         been initialized.
 214:    * @throws java.security.InvalidKeyException If the key is
 215:    *         inappropriate for this algorithm.
 216:    */
 217:   public final Key doPhase(Key key, boolean lastPhase)
 218:     throws IllegalStateException, InvalidKeyException
 219:   {
 220:     if (virgin)
 221:       {
 222:         throw new IllegalStateException("not initialized");
 223:       }
 224:     return kaSpi.engineDoPhase(key, lastPhase);
 225:   }
 226: 
 227:   /**
 228:    * Generate the shared secret in a new byte array.
 229:    *
 230:    * @return The shared secret.
 231:    * @throws java.lang.IllegalStateException If this instnace has not
 232:    *         been initialized, or if not enough calls to
 233:    *         <code>doPhase</code> have been made.
 234:    */
 235:   public final byte[] generateSecret() throws IllegalStateException
 236:   {
 237:     if (virgin)
 238:       {
 239:         throw new IllegalStateException("not initialized");
 240:       }
 241:     return kaSpi.engineGenerateSecret();
 242:   }
 243: 
 244:   /**
 245:    * Generate the shared secret and store it into the supplied array.
 246:    *
 247:    * @param sharedSecret The array in which to store the secret.
 248:    * @param offset       The index in <code>sharedSecret</code> to start
 249:    *                     storing data.
 250:    * @return The length of the shared secret, in bytes.
 251:    * @throws java.lang.IllegalStateException If this instnace has not
 252:    *         been initialized, or if not enough calls to
 253:    *         <code>doPhase</code> have been made.
 254:    * @throws javax.crypto.ShortBufferException If the supplied array is
 255:    *         not large enough to store the result.
 256:    */
 257:   public final int generateSecret(byte[] sharedSecret, int offset)
 258:   throws IllegalStateException, ShortBufferException
 259:   {
 260:     if (virgin)
 261:       {
 262:         throw new IllegalStateException("not initialized");
 263:       }
 264:     return kaSpi.engineGenerateSecret(sharedSecret, offset);
 265:   }
 266: 
 267:   /**
 268:    * Generate the shared secret and return it as an appropriate {@link
 269:    * SecretKey}.
 270:    *
 271:    * @param algorithm The secret key's algorithm.
 272:    * @return The shared secret as a secret key.
 273:    * @throws java.lang.IllegalStateException If this instnace has not
 274:    *         been initialized, or if not enough calls to
 275:    *         <code>doPhase</code> have been made.
 276:    * @throws java.security.InvalidKeyException If the shared secret
 277:    *         cannot be used to make a {@link SecretKey}.
 278:    * @throws java.security.NoSuchAlgorithmException If the specified
 279:    *         algorithm does not exist.
 280:    */
 281:   public final SecretKey generateSecret(String algorithm)
 282:   throws IllegalStateException, InvalidKeyException, NoSuchAlgorithmException
 283:   {
 284:     if (virgin)
 285:       {
 286:         throw new IllegalStateException("not initialized");
 287:       }
 288:     return kaSpi.engineGenerateSecret(algorithm);
 289:   }
 290: 
 291:   /**
 292:    * Return the name of this key-agreement algorithm.
 293:    *
 294:    * @return The algorithm name.
 295:    */
 296:   public final String getAlgorithm()
 297:   {
 298:     return algorithm;
 299:   }
 300: 
 301:   /**
 302:    * Return the provider of the underlying implementation.
 303:    *
 304:    * @return The provider.
 305:    */
 306:   public final Provider getProvider()
 307:   {
 308:     return provider;
 309:   }
 310: 
 311:   /**
 312:    * Initialize this key agreement with a key. This method will use the
 313:    * highest-priority {@link java.security.SecureRandom} as its source
 314:    * of randomness.
 315:    *
 316:    * @param key The key, usually the user's private key.
 317:    * @throws java.security.InvalidKeyException If the supplied key is
 318:    *         not appropriate.
 319:    */
 320:   public final void init(Key key) throws InvalidKeyException
 321:   {
 322:     init(key, new SecureRandom());
 323:   }
 324: 
 325:   /**
 326:    * Initialize this key agreement with a key and a source of
 327:    * randomness.
 328:    *
 329:    * @param key    The key, usually the user's private key.
 330:    * @param random The source of randomness.
 331:    * @throws java.security.InvalidKeyException If the supplied key is
 332:    *         not appropriate.
 333:    */
 334:   public final void init(Key key, SecureRandom random)
 335:     throws InvalidKeyException
 336:   {
 337:     kaSpi.engineInit(key, random);
 338:     virgin = false; // w00t!
 339:   }
 340: 
 341:   /**
 342:    * Initialize this key agreement with a key and parameters. This
 343:    * method will use the highest-priority {@link
 344:    * java.security.SecureRandom} as its source of randomness.
 345:    *
 346:    * @param key    The key, usually the user's private key.
 347:    * @param params The algorithm parameters.
 348:    * @throws java.security.InvalidAlgorithmParameterException If the
 349:    *         supplied parameters are not appropriate.
 350:    * @throws java.security.InvalidKeyException If the supplied key is
 351:    *         not appropriate.
 352:    */
 353:   public final void init(Key key, AlgorithmParameterSpec params)
 354:     throws InvalidAlgorithmParameterException, InvalidKeyException
 355:   {
 356:     init(key, params, new SecureRandom());
 357:   }
 358: 
 359:   /**
 360:    * Initialize this key agreement with a key, parameters, and source of
 361:    * randomness.
 362:    *
 363:    * @param key    The key, usually the user's private key.
 364:    * @param params The algorithm parameters.
 365:    * @param random The source of randomness.
 366:    * @throws java.security.InvalidAlgorithmParameterException If the
 367:    *         supplied parameters are not appropriate.
 368:    * @throws java.security.InvalidKeyException If the supplied key is
 369:    *         not appropriate.
 370:    */
 371:   public final void init(Key key, AlgorithmParameterSpec params,
 372:                          SecureRandom random)
 373:     throws InvalidAlgorithmParameterException, InvalidKeyException
 374:   {
 375:     kaSpi.engineInit(key, params, random);
 376:     virgin = false; // w00t!
 377:   }
 378: }