001 /* KeyAgreement.java -- Engine for key agreement methods. 002 Copyright (C) 2004 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.crypto; 040 041 import gnu.java.security.Engine; 042 043 import java.lang.reflect.InvocationTargetException; 044 import java.security.InvalidAlgorithmParameterException; 045 import java.security.InvalidKeyException; 046 import java.security.Key; 047 import java.security.NoSuchAlgorithmException; 048 import java.security.NoSuchProviderException; 049 import java.security.Provider; 050 import java.security.SecureRandom; 051 import java.security.Security; 052 import java.security.spec.AlgorithmParameterSpec; 053 054 /** 055 * Key agreement is a method in which two or more parties may agree on a 056 * secret key for symmetric cryptography or message authentication 057 * without transmitting any secrets in the clear. Key agreement 058 * algorithms typically use a public/private <i>key pair</i>, and the 059 * public key (along with some additional information) is sent across 060 * untrusted networks. 061 * 062 * <p>The most common form of key agreement used today is the 063 * <i>Diffie-Hellman key exchange algorithm</i>, described in <a 064 * href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/">PKCS #3 - 065 * Diffie Hellman Key Agreement Standard</a>. 066 * 067 * @author Casey Marshall (csm@gnu.org) 068 * @since 1.4 069 * @see KeyGenerator 070 * @see SecretKey 071 */ 072 public class KeyAgreement 073 { 074 075 // Fields. 076 // ------------------------------------------------------------------------ 077 078 private static final String SERVICE = "KeyAgreement"; 079 080 /** The underlying key agreement implementation. */ 081 private KeyAgreementSpi kaSpi; 082 083 /** The provider of this implementation. */ 084 private Provider provider; 085 086 /** The name of this instance's algorithm. */ 087 private String algorithm; 088 089 /** Singnals whether or not this instance has been initialized. */ 090 private boolean virgin; 091 092 // Constructor. 093 // ------------------------------------------------------------------------ 094 095 protected KeyAgreement(KeyAgreementSpi kaSpi, Provider provider, 096 String algorithm) 097 { 098 this.kaSpi = kaSpi; 099 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 }