Frames | No Frames |
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: }