Source for javax.crypto.SealedObject

   1: /* SealedObject.java -- An encrypted Serializable object.
   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 java.io.ByteArrayInputStream;
  42: import java.io.ByteArrayOutputStream;
  43: import java.io.IOException;
  44: import java.io.ObjectInputStream;
  45: import java.io.ObjectOutputStream;
  46: import java.io.Serializable;
  47: 
  48: import java.security.AlgorithmParameters;
  49: import java.security.InvalidAlgorithmParameterException;
  50: import java.security.InvalidKeyException;
  51: import java.security.Key;
  52: import java.security.NoSuchAlgorithmException;
  53: import java.security.NoSuchProviderException;
  54: 
  55: /**
  56:  * This class allows any {@link java.io.Serializable} object to be
  57:  * stored in an encrypted form.
  58:  *
  59:  * <p>When the sealed object is ready to be unsealed (and deserialized)
  60:  * the caller may use either
  61:  *
  62:  * <ol>
  63:  * <li>{@link #getObject(javax.crypto.Cipher)}, which uses an
  64:  * already-initialized {@link javax.crypto.Cipher}.<br>
  65:  * <br>
  66:  * or,</li>
  67:  *
  68:  * <li>{@link #getObject(java.security.Key)} or {@link
  69:  * #getObject(java.security.Key,java.lang.String)}, which will
  70:  * initialize a new cipher instance with the {@link #encodedParams} that
  71:  * were stored with this sealed object (this is so parameters, such as
  72:  * the IV, don't need to be known by the one unsealing the object).</li>
  73:  * </ol>
  74:  *
  75:  * @author Casey Marshall (csm@gnu.org)
  76:  * @since 1.4
  77:  */
  78: public class SealedObject implements Serializable
  79: {
  80: 
  81:   // Constants and fields.
  82:   // ------------------------------------------------------------------------
  83: 
  84:   /** The encoded algorithm parameters. */
  85:   protected byte[] encodedParams;
  86: 
  87:   /** The serialized, encrypted object. */
  88:   private byte[] encryptedContent;
  89: 
  90:   /** The algorithm used to seal the object. */
  91:   private String sealAlg;
  92: 
  93:   /** The parameter type. */
  94:   private String paramsAlg;
  95: 
  96:   /** The cipher that decrypts when this object is unsealed. */
  97:   private transient Cipher sealCipher;
  98: 
  99:   /** Compatible with JDK1.4. */
 100:   private static final long serialVersionUID = 4482838265551344752L;
 101: 
 102:   // Constructors.
 103:   // ------------------------------------------------------------------------
 104: 
 105:   /**
 106:    * Create a new sealed object from a {@link java.io.Serializable}
 107:    * object and a cipher.
 108:    *
 109:    * @param object The object to seal.
 110:    * @param cipher The cipher to encrypt with.
 111:    * @throws java.io.IOException If serializing the object fails.
 112:    * @throws javax.crypto.IllegalBlockSizeException If the cipher has no
 113:    *         padding and the size of the serialized representation of the
 114:    *         object is not a multiple of the cipher's block size.
 115:    */
 116:   public SealedObject(Serializable object, Cipher cipher)
 117:     throws IOException, IllegalBlockSizeException
 118:   {
 119:     ByteArrayOutputStream baos = new ByteArrayOutputStream();
 120:     ObjectOutputStream oos = new ObjectOutputStream(baos);
 121:     oos.writeObject(object);
 122:     oos.flush();
 123:     try
 124:       {
 125:         encryptedContent = cipher.doFinal(baos.toByteArray());
 126:       }
 127:     catch (IllegalStateException ise)
 128:       {
 129:         throw new IOException("cipher not in proper state");
 130:       }
 131:     catch (BadPaddingException bpe)
 132:       {
 133:         throw new IOException(
 134:           "encrypting but got javax.crypto.BadPaddingException");
 135:       }
 136:     sealAlg = cipher.getAlgorithm();
 137:     encodedParams = cipher.getParameters().getEncoded();
 138:     paramsAlg = cipher.getParameters().getAlgorithm();
 139:   }
 140: 
 141:   /**
 142:    * Create a new sealed object from another sealed object.
 143:    *
 144:    * @param so The other sealed object.
 145:    */
 146:   protected SealedObject(SealedObject so)
 147:   {
 148:     this.encodedParams = (byte[]) so.encodedParams.clone();
 149:     this.encryptedContent = (byte[]) so.encryptedContent.clone();
 150:     this.sealAlg = so.sealAlg;
 151:     this.paramsAlg = so.paramsAlg;
 152:   }
 153: 
 154:   // Instance methods.
 155:   // ------------------------------------------------------------------------
 156: 
 157:   /**
 158:    * Get the name of the algorithm used to seal this object.
 159:    *
 160:    * @return The algorithm's name.
 161:    */
 162:   public final String getAlgorithm()
 163:   {
 164:     return sealAlg;
 165:   }
 166: 
 167:   /**
 168:    * Unseal and deserialize this sealed object with a specified (already
 169:    * initialized) cipher.
 170:    *
 171:    * @param cipher The cipher to decrypt with.
 172:    * @return The original object.
 173:    * @throws java.io.IOException If reading fails.
 174:    * @throws java.lang.ClassNotFoundException If deserialization fails.
 175:    * @throws javax.crypto.IllegalBlockSizeException If the cipher has no
 176:    *         padding and the encrypted data is not a multiple of the
 177:    *         cipher's block size.
 178:    * @throws javax.crypto.BadPaddingException If the padding bytes are
 179:    *         incorrect.
 180:    */
 181:   public final Object getObject(Cipher cipher)
 182:     throws IOException, ClassNotFoundException, IllegalBlockSizeException,
 183:            BadPaddingException
 184:   {
 185:     sealCipher = cipher;
 186:     return unseal();
 187:   }
 188: 
 189:   /**
 190:    * Unseal and deserialize this sealed object with the specified key.
 191:    *
 192:    * @param key The key to decrypt with.
 193:    * @return The original object.
 194:    * @throws java.io.IOException If reading fails.
 195:    * @throws java.lang.ClassNotFoundException If deserialization fails.
 196:    * @throws java.security.InvalidKeyException If the supplied key
 197:    *         cannot be used to unseal this object.
 198:    * @throws java.security.NoSuchAlgorithmException If the algorithm
 199:    *         used to originally seal this object is not available.
 200:    */
 201:   public final Object getObject(Key key)
 202:     throws IOException, ClassNotFoundException, InvalidKeyException,
 203:            NoSuchAlgorithmException
 204:   {
 205:     try
 206:       {
 207:         if (sealCipher == null)
 208:           sealCipher = Cipher.getInstance(sealAlg);
 209:       }
 210:     catch (NoSuchPaddingException nspe)
 211:       {
 212:         throw new NoSuchAlgorithmException(nspe.getMessage());
 213:       }
 214:     AlgorithmParameters params = null;
 215:     if (encodedParams != null)
 216:       {
 217:         params = AlgorithmParameters.getInstance(paramsAlg);
 218:         params.init(encodedParams);
 219:       }
 220:     try
 221:       {
 222:         sealCipher.init(Cipher.DECRYPT_MODE, key, params);
 223:         return unseal();
 224:       }
 225:     catch (InvalidAlgorithmParameterException iape)
 226:       {
 227:         throw new IOException("bad parameters");
 228:       }
 229:     catch (IllegalBlockSizeException ibse)
 230:       {
 231:         throw new IOException("illegal block size");
 232:       }
 233:     catch (BadPaddingException bpe)
 234:       {
 235:         throw new IOException("bad padding");
 236:       }
 237:   }
 238: 
 239:   /**
 240:    * Unseal and deserialize this sealed object with the specified key,
 241:    * using a cipher from the named provider.
 242:    *
 243:    * @param key      The key to decrypt with.
 244:    * @param provider The name of the provider to use.
 245:    * @return The original object.
 246:    * @throws java.io.IOException If reading fails.
 247:    * @throws java.lang.ClassNotFoundException If deserialization fails.
 248:    * @throws java.security.InvalidKeyException If the supplied key
 249:    *         cannot be used to unseal this object.
 250:    * @throws java.security.NoSuchAlgorithmException If the algorithm
 251:    *         used to originally seal this object is not available from
 252:    *         the named provider.
 253:    * @throws java.security.NoSuchProviderException If the named provider
 254:    *         does not exist.
 255:    */
 256:   public final Object getObject(Key key, String provider)
 257:     throws IOException, ClassNotFoundException, InvalidKeyException,
 258:            NoSuchAlgorithmException, NoSuchProviderException
 259:   {
 260:     try
 261:       {
 262:         sealCipher = Cipher.getInstance(sealAlg, provider);
 263:       }
 264:     catch (NoSuchPaddingException nspe)
 265:       {
 266:         throw new NoSuchAlgorithmException(nspe.getMessage());
 267:       }
 268:     AlgorithmParameters params = null;
 269:     if (encodedParams != null)
 270:       {
 271:         params = AlgorithmParameters.getInstance(paramsAlg, provider);
 272:         params.init(encodedParams);
 273:       }
 274:     try
 275:       {
 276:         sealCipher.init(Cipher.DECRYPT_MODE, key, params);
 277:         return unseal();
 278:       }
 279:     catch (InvalidAlgorithmParameterException iape)
 280:       {
 281:         throw new IOException("bad parameters");
 282:       }
 283:     catch (IllegalBlockSizeException ibse)
 284:       {
 285:         throw new IOException("illegal block size");
 286:       }
 287:     catch (BadPaddingException bpe)
 288:       {
 289:         throw new IOException("bad padding");
 290:       }
 291:   }
 292: 
 293:   // Own methods.
 294:   // ------------------------------------------------------------------------
 295: 
 296:   /**
 297:    * Deserialize this object.
 298:    *
 299:    * @param ois The input stream.
 300:    * @throws java.io.IOException If reading fails.
 301:    * @throws java.lang.ClassNotFoundException If reading fails.
 302:    */
 303:   private void readObject(ObjectInputStream ois)
 304:     throws IOException, ClassNotFoundException
 305:   {
 306:     encodedParams = (byte[]) ois.readObject();
 307:     encryptedContent = (byte[]) ois.readObject();
 308:     sealAlg = (String) ois.readObject();
 309:     paramsAlg = (String) ois.readObject();
 310:   }
 311: 
 312:   /**
 313:    * Serialize this object.
 314:    *
 315:    * @param oos The output stream.
 316:    * @throws java.io.IOException If writing fails.
 317:    */
 318:   private void writeObject(ObjectOutputStream oos)
 319:     throws IOException
 320:   {
 321:     oos.writeObject(encodedParams);
 322:     oos.writeObject(encryptedContent);
 323:     oos.writeObject(sealAlg);
 324:     oos.writeObject(paramsAlg);
 325:   }
 326: 
 327:   /**
 328:    * Unseal this object, returning it.
 329:    *
 330:    * @return The unsealed, deserialized Object.
 331:    * @throws java.io.IOException If reading fails.
 332:    * @throws java.io.ClassNotFoundException If reading fails.
 333:    * @throws javax.crypto.IllegalBlockSizeException If the cipher has no
 334:    *         padding and the encrypted data is not a multiple of the
 335:    *         cipher's block size.
 336:    * @throws javax.crypto.BadPaddingException If the padding bytes are
 337:    *         incorrect.
 338:    */
 339:   private Object unseal()
 340:     throws IOException, ClassNotFoundException, IllegalBlockSizeException,
 341:            BadPaddingException
 342:   {
 343:     ByteArrayInputStream bais = null;
 344:     try
 345:       {
 346:         bais = new ByteArrayInputStream(sealCipher.doFinal(encryptedContent));
 347:       }
 348:     catch (IllegalStateException ise)
 349:       {
 350:         throw new IOException("cipher not initialized");
 351:       }
 352:     ObjectInputStream ois = new ObjectInputStream(bais);
 353:     return ois.readObject();
 354:   }
 355: }