1 /*
2  * Copyright (C) 2021 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 
17 package com.android.cts.devicepolicy;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.util.Log;
22 
23 import java.security.KeyFactory;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.PrivateKey;
26 import java.security.spec.InvalidKeySpecException;
27 import java.security.spec.PKCS8EncodedKeySpec;
28 
29 import javax.security.auth.DestroyFailedException;
30 
31 /**
32  * A {@link PrivateKey} that can be transmitted as a {@link Parcelable}.
33  *
34  * <p>TODO(b/191150645): it's needed because the {@code PrivateKey} returned by {@code KeyFactory}
35  * does not properly implements {@code Serializable}.
36  */
37 public final class ParcelablePrivateKey implements PrivateKey, Parcelable {
38 
39     private static final long serialVersionUID = 1L;
40 
41     private static final String TAG = ParcelablePrivateKey.class.getSimpleName();
42 
43     private final String mAlgorithm;
44     private final byte[] mEncodedKey;
45     private final PrivateKey mPrivateKey;
46 
47     /**
48      * Default constructor.
49      */
ParcelablePrivateKey(String algorithm, byte[] encodedKey)50     public ParcelablePrivateKey(String algorithm, byte[] encodedKey)
51             throws NoSuchAlgorithmException, InvalidKeySpecException {
52         mAlgorithm = algorithm;
53         mEncodedKey = encodedKey;
54         mPrivateKey = KeyFactory.getInstance(algorithm).generatePrivate(
55                 new PKCS8EncodedKeySpec(encodedKey));
56         Log.d(TAG, "ParcelablePrivateKey(): algorithm=" + algorithm
57                 + ", encodedKey.length=" + encodedKey.length
58                 + " pk.format=" + mPrivateKey.getFormat()
59                 + " pk.length=" + mPrivateKey.getEncoded().length);
60     }
61 
62     @Override
getAlgorithm()63     public String getAlgorithm() {
64         return mPrivateKey.getAlgorithm();
65     }
66 
67     @Override
getFormat()68     public String getFormat() {
69         return mPrivateKey.getFormat();
70     }
71 
72     @Override
getEncoded()73     public byte[] getEncoded() {
74         return mPrivateKey.getEncoded();
75     }
76 
77     @Override
destroy()78     public void destroy() throws DestroyFailedException {
79         mPrivateKey.destroy();
80     }
81 
82     @Override
isDestroyed()83     public boolean isDestroyed() {
84         return mPrivateKey.isDestroyed();
85     }
86 
87     @Override
describeContents()88     public int describeContents() {
89         return 0;
90     }
91 
92     @Override
writeToParcel(Parcel dest, int flags)93     public void writeToParcel(Parcel dest, int flags) {
94         dest.writeString(mAlgorithm);
95         dest.writeInt(mEncodedKey.length);
96         dest.writeByteArray(mEncodedKey);
97     }
98 
99     @Override
toString()100     public String toString() {
101         return "ParcelablePrivateKey[algorithm=" + mAlgorithm
102                 + ", length=" + mEncodedKey.length + ']';
103     }
104 
105     public static final Parcelable.Creator<ParcelablePrivateKey> CREATOR =
106             new Parcelable.Creator<ParcelablePrivateKey>() {
107 
108         public ParcelablePrivateKey createFromParcel(Parcel in) {
109             String algorithm = in.readString();
110             int arrayLength = in.readInt();
111             byte[] key = new byte[arrayLength];
112             in.readByteArray(key);
113             try {
114                 return new ParcelablePrivateKey(algorithm, key);
115             } catch (Exception e) {
116                 throw new IllegalArgumentException("could not parse key: algorithm=" + algorithm
117                         + ", key_size=" + arrayLength, e);
118             }
119         }
120 
121         public ParcelablePrivateKey[] newArray(int size) {
122             return new ParcelablePrivateKey[size];
123         }
124     };
125 
126 }
127