ContainerEncryptionParams.java revision ceb1b0bfaea56251796b08c07b963de7403d84eb
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.pm;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.text.TextUtils;
22import android.util.Slog;
23
24import java.security.InvalidAlgorithmParameterException;
25import java.security.spec.AlgorithmParameterSpec;
26import java.util.Arrays;
27
28import javax.crypto.SecretKey;
29import javax.crypto.spec.IvParameterSpec;
30
31/**
32 * Represents encryption parameters used to read a container.
33 *
34 * @hide
35 */
36public class ContainerEncryptionParams implements Parcelable {
37    protected static final String TAG = "ContainerEncryptionParams";
38
39    /** What we print out first when toString() is called. */
40    private static final String TO_STRING_PREFIX = "ContainerEncryptionParams{";
41
42    /**
43     * Parameter type for parceling that indicates the next parameters are
44     * IvParameters.
45     */
46    private static final int ENC_PARAMS_IV_PARAMETERS = 1;
47
48    /** Parameter type for paceling that indicates there are no MAC parameters. */
49    private static final int MAC_PARAMS_NONE = 1;
50
51    /** The encryption algorithm used. */
52    private final String mEncryptionAlgorithm;
53
54    /** The parameter spec to be used for encryption. */
55    private final IvParameterSpec mEncryptionSpec;
56
57    /** Secret key to be used for decryption. */
58    private final SecretKey mEncryptionKey;
59
60    /** Algorithm name for the MAC to be used. */
61    private final String mMacAlgorithm;
62
63    /** The parameter spec to be used for the MAC tag authentication. */
64    private final AlgorithmParameterSpec mMacSpec;
65
66    /** Secret key to be used for MAC tag authentication. */
67    private final SecretKey mMacKey;
68
69    /** MAC tag authenticating the data in the container. */
70    private final byte[] mMacTag;
71
72    /** Offset into file where authenticated (e.g., MAC protected) data begins. */
73    private final int mAuthenticatedDataStart;
74
75    /** Offset into file where encrypted data begins. */
76    private final int mEncryptedDataStart;
77
78    /**
79     * Offset into file for the end of encrypted data (and, by extension,
80     * authenticated data) in file.
81     */
82    private final int mDataEnd;
83
84    public ContainerEncryptionParams(String encryptionAlgorithm,
85            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
86            throws InvalidAlgorithmParameterException {
87        this(encryptionAlgorithm, encryptionSpec, encryptionKey, null, null, null, null, -1, -1,
88                -1);
89    }
90
91    /**
92     * Creates container encryption specifications for installing from encrypted
93     * containers.
94     *
95     * @param encryptionAlgorithm encryption algorithm to use; format matches
96     *            JCE
97     * @param encryptionSpec algorithm parameter specification
98     * @param encryptionKey key used for decryption
99     * @param macAlgorithm MAC algorithm to use; format matches JCE
100     * @param macSpec algorithm parameters specification, may be {@code null}
101     * @param macKey key used for authentication (i.e., for the MAC tag)
102     * @param authenticatedDataStart offset of start of authenticated data in
103     *            stream
104     * @param encryptedDataStart offset of start of encrypted data in stream
105     * @param dataEnd offset of the end of both the authenticated and encrypted
106     *            data
107     * @throws InvalidAlgorithmParameterException
108     */
109    public ContainerEncryptionParams(String encryptionAlgorithm,
110            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
111            AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
112            int authenticatedDataStart, int encryptedDataStart, int dataEnd)
113            throws InvalidAlgorithmParameterException {
114        if (TextUtils.isEmpty(encryptionAlgorithm)) {
115            throw new NullPointerException("algorithm == null");
116        } else if (encryptionSpec == null) {
117            throw new NullPointerException("encryptionSpec == null");
118        } else if (encryptionKey == null) {
119            throw new NullPointerException("encryptionKey == null");
120        }
121
122        if (!TextUtils.isEmpty(macAlgorithm)) {
123            if (macKey == null) {
124                throw new NullPointerException("macKey == null");
125            }
126        }
127
128        if (!(encryptionSpec instanceof IvParameterSpec)) {
129            throw new InvalidAlgorithmParameterException(
130                    "Unknown parameter spec class; must be IvParameters");
131        }
132
133        mEncryptionAlgorithm = encryptionAlgorithm;
134        mEncryptionSpec = (IvParameterSpec) encryptionSpec;
135        mEncryptionKey = encryptionKey;
136
137        mMacAlgorithm = macAlgorithm;
138        mMacSpec = macSpec;
139        mMacKey = macKey;
140        mMacTag = macTag;
141
142        mAuthenticatedDataStart = authenticatedDataStart;
143        mEncryptedDataStart = encryptedDataStart;
144        mDataEnd = dataEnd;
145    }
146
147    public String getEncryptionAlgorithm() {
148        return mEncryptionAlgorithm;
149    }
150
151    public AlgorithmParameterSpec getEncryptionSpec() {
152        return mEncryptionSpec;
153    }
154
155    public SecretKey getEncryptionKey() {
156        return mEncryptionKey;
157    }
158
159    public String getMacAlgorithm() {
160        return mMacAlgorithm;
161    }
162
163    public AlgorithmParameterSpec getMacSpec() {
164        return mMacSpec;
165    }
166
167    public SecretKey getMacKey() {
168        return mMacKey;
169    }
170
171    public byte[] getMacTag() {
172        return mMacTag;
173    }
174
175    public int getAuthenticatedDataStart() {
176        return mAuthenticatedDataStart;
177    }
178
179    public int getEncryptedDataStart() {
180        return mEncryptedDataStart;
181    }
182
183    public int getDataEnd() {
184        return mDataEnd;
185    }
186
187    @Override
188    public int describeContents() {
189        return 0;
190    }
191
192    @Override
193    public boolean equals(Object o) {
194        if (this == o) {
195            return true;
196        }
197
198        if (!(o instanceof ContainerEncryptionParams)) {
199            return false;
200        }
201
202        final ContainerEncryptionParams other = (ContainerEncryptionParams) o;
203
204        // Primitive comparison
205        if ((mAuthenticatedDataStart != other.mAuthenticatedDataStart)
206                || (mEncryptedDataStart != other.mEncryptedDataStart)
207                || (mDataEnd != other.mDataEnd)) {
208            return false;
209        }
210
211        // String comparison
212        if (!mEncryptionAlgorithm.equals(other.mEncryptionAlgorithm)
213                || !mMacAlgorithm.equals(other.mMacAlgorithm)) {
214            return false;
215        }
216
217        // Object comparison
218        if (!isSecretKeyEqual(mEncryptionKey, other.mEncryptionKey)
219                || !isSecretKeyEqual(mMacKey, other.mMacKey)) {
220            return false;
221        }
222
223        if (!Arrays.equals(mEncryptionSpec.getIV(), other.mEncryptionSpec.getIV())
224                || !Arrays.equals(mMacTag, other.mMacTag) || (mMacSpec != other.mMacSpec)) {
225            return false;
226        }
227
228        return true;
229    }
230
231    private static final boolean isSecretKeyEqual(SecretKey key1, SecretKey key2) {
232        final String keyFormat = key1.getFormat();
233        final String otherKeyFormat = key2.getFormat();
234
235        if (keyFormat == null) {
236            if (keyFormat != otherKeyFormat) {
237                return false;
238            }
239
240            if (key1.getEncoded() != key2.getEncoded()) {
241                return false;
242            }
243        } else {
244            if (!keyFormat.equals(key2.getFormat())) {
245                return false;
246            }
247
248            if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
249                return false;
250            }
251        }
252
253        return true;
254    }
255
256    @Override
257    public int hashCode() {
258        int hash = 3;
259
260        hash += 5 * mEncryptionAlgorithm.hashCode();
261        hash += 7 * Arrays.hashCode(mEncryptionSpec.getIV());
262        hash += 11 * mEncryptionKey.hashCode();
263        hash += 13 * mMacAlgorithm.hashCode();
264        hash += 17 * mMacKey.hashCode();
265        hash += 19 * Arrays.hashCode(mMacTag);
266        hash += 23 * mAuthenticatedDataStart;
267        hash += 29 * mEncryptedDataStart;
268        hash += 31 * mDataEnd;
269
270        return hash;
271    }
272
273    @Override
274    public String toString() {
275        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);
276
277        sb.append("mEncryptionAlgorithm=\"");
278        sb.append(mEncryptionAlgorithm);
279        sb.append("\",");
280        sb.append("mEncryptionSpec=");
281        sb.append(mEncryptionSpec.toString());
282        sb.append("mEncryptionKey=");
283        sb.append(mEncryptionKey.toString());
284
285        sb.append("mMacAlgorithm=\"");
286        sb.append(mMacAlgorithm);
287        sb.append("\",");
288        sb.append("mMacSpec=");
289        sb.append(mMacSpec.toString());
290        sb.append("mMacKey=");
291        sb.append(mMacKey.toString());
292
293        sb.append(",mAuthenticatedDataStart=");
294        sb.append(mAuthenticatedDataStart);
295        sb.append(",mEncryptedDataStart=");
296        sb.append(mEncryptedDataStart);
297        sb.append(",mDataEnd=");
298        sb.append(mDataEnd);
299        sb.append('}');
300
301        return sb.toString();
302    }
303
304    @Override
305    public void writeToParcel(Parcel dest, int flags) {
306        dest.writeString(mEncryptionAlgorithm);
307        dest.writeInt(ENC_PARAMS_IV_PARAMETERS);
308        dest.writeByteArray(mEncryptionSpec.getIV());
309        dest.writeSerializable(mEncryptionKey);
310
311        dest.writeString(mMacAlgorithm);
312        dest.writeInt(MAC_PARAMS_NONE);
313        dest.writeByteArray(new byte[0]);
314        dest.writeSerializable(mMacKey);
315
316        dest.writeByteArray(mMacTag);
317
318        dest.writeInt(mAuthenticatedDataStart);
319        dest.writeInt(mEncryptedDataStart);
320        dest.writeInt(mDataEnd);
321    }
322
323    private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
324        mEncryptionAlgorithm = source.readString();
325        final int encParamType = source.readInt();
326        final byte[] encParamsEncoded = source.createByteArray();
327        mEncryptionKey = (SecretKey) source.readSerializable();
328
329        mMacAlgorithm = source.readString();
330        final int macParamType = source.readInt();
331        source.createByteArray(); // byte[] macParamsEncoded
332        mMacKey = (SecretKey) source.readSerializable();
333
334        mMacTag = source.createByteArray();
335
336        mAuthenticatedDataStart = source.readInt();
337        mEncryptedDataStart = source.readInt();
338        mDataEnd = source.readInt();
339
340        switch (encParamType) {
341            case ENC_PARAMS_IV_PARAMETERS:
342                mEncryptionSpec = new IvParameterSpec(encParamsEncoded);
343                break;
344            default:
345                throw new InvalidAlgorithmParameterException("Unknown parameter type "
346                        + encParamType);
347        }
348
349        switch (macParamType) {
350            case MAC_PARAMS_NONE:
351                mMacSpec = null;
352                break;
353            default:
354                throw new InvalidAlgorithmParameterException("Unknown parameter type "
355                        + macParamType);
356        }
357
358        if (mEncryptionKey == null) {
359            throw new NullPointerException("encryptionKey == null");
360        }
361    }
362
363    public static final Parcelable.Creator<ContainerEncryptionParams> CREATOR =
364            new Parcelable.Creator<ContainerEncryptionParams>() {
365        public ContainerEncryptionParams createFromParcel(Parcel source) {
366            try {
367                return new ContainerEncryptionParams(source);
368            } catch (InvalidAlgorithmParameterException e) {
369                Slog.e(TAG, "Invalid algorithm parameters specified", e);
370                return null;
371            }
372        }
373
374        public ContainerEncryptionParams[] newArray(int size) {
375            return new ContainerEncryptionParams[size];
376        }
377    };
378}