1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage javax.crypto;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ByteArrayInputStream;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ByteArrayOutputStream;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ObjectInputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ObjectOutputStream;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.Serializable;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AlgorithmParameters;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.InvalidAlgorithmParameterException;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.InvalidKeyException;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.Key;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.NoSuchAlgorithmException;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.NoSuchProviderException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A {@code SealedObject} is a wrapper around a {@code serializable} object
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance and encrypts it using a cryptographic cipher.
3638846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes *
3738846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes * <p>Since a {@code SealedObject} instance is serializable it can
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * either be stored or transmitted over an insecure channel.
3938846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes *
4038846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes * <p>The wrapped object can later be decrypted (unsealed) using the corresponding
4138846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes * key and then be deserialized to retrieve the original object. The sealed
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * object itself keeps track of the cipher and corresponding parameters.
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class SealedObject implements Serializable {
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = 4482838265551344752L;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4938846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes     * The cipher's {@link AlgorithmParameters} in encoded format.
5038846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes     * Equivalent to {@code cipher.getParameters().getEncoded()},
5138846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes     * or null if the cipher did not use any parameters.
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] encodedParams;
5438846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private byte[] encryptedContent;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String sealAlg;
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String paramsAlg;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5938846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
6038846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        // We do unshared reads here to ensure we have our own clones of the byte[]s.
6138846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        encodedParams = (byte[]) s.readUnshared();
6238846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        encryptedContent = (byte[]) s.readUnshared();
6338846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        // These are regular shared reads because the algorithms used by a given stream are
6438846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        // almost certain to the be same for each object, and String is immutable anyway,
6538846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        // so there's no security concern about sharing.
6638846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        sealAlg = (String) s.readObject();
6738846d115b17683a800b76b93c66c24f91cf6d91Elliott Hughes        paramsAlg = (String) s.readObject();
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new {@code SealedObject} instance wrapping the specified object
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and sealing it using the specified cipher.
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The cipher must be fully initialized.
75ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param object
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the object to seal, can be {@code null}.
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param c
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the cipher to encrypt the object.
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the serialization fails.
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalBlockSizeException
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified cipher is a block cipher and the length of
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             the serialized data is not a multiple of the ciphers block
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             size.
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the cipher is {@code null}.
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public SealedObject(Serializable object, Cipher c)
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throws IOException, IllegalBlockSizeException {
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (c == null) {
9280a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new NullPointerException("c == null");
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteArrayOutputStream bos = new ByteArrayOutputStream();
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ObjectOutputStream oos = new ObjectOutputStream(bos);
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            oos.writeObject(object);
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            oos.flush();
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AlgorithmParameters ap = c.getParameters();
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.encodedParams = (ap == null) ? null : ap.getEncoded();
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.paramsAlg = (ap == null) ? null : ap.getAlgorithm();
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.sealAlg = c.getAlgorithm();
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.encryptedContent = c.doFinal(bos.toByteArray());
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (BadPaddingException e) {
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should be never thrown because the cipher
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should be initialized for encryption
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(e.toString());
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new {@code SealedObject} instance by copying the data from
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the specified object.
114ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param so
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the object to copy.
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected SealedObject(SealedObject so) {
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (so == null) {
12080a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new NullPointerException("so == null");
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.encryptedContent = so.encryptedContent;
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.encodedParams = so.encodedParams;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.sealAlg = so.sealAlg;
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.paramsAlg = so.paramsAlg;
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the algorithm this object was sealed with.
130ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the algorithm this object was sealed with.
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String getAlgorithm() {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sealAlg;
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the wrapped object, decrypting it using the specified key.
139ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the key to decrypt the data with.
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the encapsulated object.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws ClassNotFoundException
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NoSuchAlgorithmException
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the algorithm to decrypt the data is not available.
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws InvalidKeyException
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified key cannot be used to decrypt the data.
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getObject(Key key)
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throws IOException, ClassNotFoundException,
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                       NoSuchAlgorithmException, InvalidKeyException {
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (key == null) {
15680a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new InvalidKeyException("key == null");
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Cipher cipher = Cipher.getInstance(sealAlg);
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((paramsAlg != null) && (paramsAlg.length() != 0)) {
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AlgorithmParameters params =
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    AlgorithmParameters.getInstance(paramsAlg);
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                params.init(encodedParams);
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cipher.init(Cipher.DECRYPT_MODE, key, params);
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cipher.init(Cipher.DECRYPT_MODE, key);
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] serialized = cipher.doFinal(encryptedContent);
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ObjectInputStream ois =
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new ObjectInputStream(
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            new ByteArrayInputStream(serialized));
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ois.readObject();
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NoSuchPaddingException e)  {
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because cipher text was made
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // with existing padding
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (InvalidAlgorithmParameterException e) {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because cipher text was made
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // with correct algorithm parameters
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalBlockSizeException e) {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because the cipher text
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // was correctly made
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (BadPaddingException e) {
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because the cipher text
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // was correctly made
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalStateException  e) {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should never be thrown because cipher is initialized
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the wrapped object, decrypting it using the specified
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * cipher.
198ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param c
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the cipher to decrypt the data.
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the encapsulated object.
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws ClassNotFoundException
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalBlockSizeException
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified cipher is a block cipher and the length of
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             the serialized data is not a multiple of the ciphers block
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             size.
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws BadPaddingException
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the padding of the data does not match the padding scheme.
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getObject(Cipher c)
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throws IOException, ClassNotFoundException,
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                       IllegalBlockSizeException, BadPaddingException {
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (c == null) {
21780a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new NullPointerException("c == null");
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] serialized = c.doFinal(encryptedContent);
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ObjectInputStream ois =
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                new ObjectInputStream(
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        new ByteArrayInputStream(serialized));
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ois.readObject();
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the wrapped object, decrypting it using the specified key. The
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified provider is used to retrieve the cipher algorithm.
229ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param key
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the key to decrypt the data.
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param provider
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the provider that provides the cipher algorithm.
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the encapsulated object.
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws ClassNotFoundException
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if deserialization fails.
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NoSuchAlgorithmException
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the algorithm used to decrypt the data is not available.
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NoSuchProviderException
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified provider is not available.
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws InvalidKeyException
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified key cannot be used to decrypt the data.
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getObject(Key key, String provider)
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throws IOException, ClassNotFoundException,
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                       NoSuchAlgorithmException, NoSuchProviderException,
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                       InvalidKeyException {
25080a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes        if (provider == null || provider.isEmpty()) {
25180a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("provider name empty or null");
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Cipher cipher = Cipher.getInstance(sealAlg, provider);
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((paramsAlg != null) && (paramsAlg.length() != 0)) {
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AlgorithmParameters params =
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    AlgorithmParameters.getInstance(paramsAlg);
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                params.init(encodedParams);
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cipher.init(Cipher.DECRYPT_MODE, key, params);
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                cipher.init(Cipher.DECRYPT_MODE, key);
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] serialized = cipher.doFinal(encryptedContent);
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ObjectInputStream ois =
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    new ObjectInputStream(
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            new ByteArrayInputStream(serialized));
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ois.readObject();
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NoSuchPaddingException e)  {
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because cipher text was made
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // with existing padding
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (InvalidAlgorithmParameterException e) {
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because cipher text was made
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // with correct algorithm parameters
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalBlockSizeException e) {
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because the cipher text
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // was correctly made
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (BadPaddingException e) {
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should not be thrown because the cipher text
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // was correctly made
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalStateException  e) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // should never be thrown because cipher is initialized
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NoSuchAlgorithmException(e.toString());
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
290