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 17 package android.content.pm; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.text.TextUtils; 22 import android.util.Slog; 23 24 import java.security.InvalidAlgorithmParameterException; 25 import java.security.spec.AlgorithmParameterSpec; 26 import java.util.Arrays; 27 28 import javax.crypto.SecretKey; 29 import javax.crypto.spec.IvParameterSpec; 30 31 /** 32 * Represents encryption parameters used to read a container. 33 * 34 * @hide 35 */ 36 public 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 long mAuthenticatedDataStart; 74 75 /** Offset into file where encrypted data begins. */ 76 private final long 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 long 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 macTag message authentication code (MAC) tag for the authenticated 103 * data 104 * @param authenticatedDataStart offset of start of authenticated data in 105 * stream 106 * @param encryptedDataStart offset of start of encrypted data in stream 107 * @param dataEnd offset of the end of both the authenticated and encrypted 108 * data 109 * @throws InvalidAlgorithmParameterException 110 */ 111 public ContainerEncryptionParams(String encryptionAlgorithm, 112 AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm, 113 AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag, 114 long authenticatedDataStart, long encryptedDataStart, long dataEnd) 115 throws InvalidAlgorithmParameterException { 116 if (TextUtils.isEmpty(encryptionAlgorithm)) { 117 throw new NullPointerException("algorithm == null"); 118 } else if (encryptionSpec == null) { 119 throw new NullPointerException("encryptionSpec == null"); 120 } else if (encryptionKey == null) { 121 throw new NullPointerException("encryptionKey == null"); 122 } 123 124 if (!TextUtils.isEmpty(macAlgorithm)) { 125 if (macKey == null) { 126 throw new NullPointerException("macKey == null"); 127 } 128 } 129 130 if (!(encryptionSpec instanceof IvParameterSpec)) { 131 throw new InvalidAlgorithmParameterException( 132 "Unknown parameter spec class; must be IvParameters"); 133 } 134 135 mEncryptionAlgorithm = encryptionAlgorithm; 136 mEncryptionSpec = (IvParameterSpec) encryptionSpec; 137 mEncryptionKey = encryptionKey; 138 139 mMacAlgorithm = macAlgorithm; 140 mMacSpec = macSpec; 141 mMacKey = macKey; 142 mMacTag = macTag; 143 144 mAuthenticatedDataStart = authenticatedDataStart; 145 mEncryptedDataStart = encryptedDataStart; 146 mDataEnd = dataEnd; 147 } 148 149 public String getEncryptionAlgorithm() { 150 return mEncryptionAlgorithm; 151 } 152 153 public AlgorithmParameterSpec getEncryptionSpec() { 154 return mEncryptionSpec; 155 } 156 157 public SecretKey getEncryptionKey() { 158 return mEncryptionKey; 159 } 160 161 public String getMacAlgorithm() { 162 return mMacAlgorithm; 163 } 164 165 public AlgorithmParameterSpec getMacSpec() { 166 return mMacSpec; 167 } 168 169 public SecretKey getMacKey() { 170 return mMacKey; 171 } 172 173 public byte[] getMacTag() { 174 return mMacTag; 175 } 176 177 public long getAuthenticatedDataStart() { 178 return mAuthenticatedDataStart; 179 } 180 181 public long getEncryptedDataStart() { 182 return mEncryptedDataStart; 183 } 184 185 public long getDataEnd() { 186 return mDataEnd; 187 } 188 189 @Override 190 public int describeContents() { 191 return 0; 192 } 193 194 @Override 195 public boolean equals(Object o) { 196 if (this == o) { 197 return true; 198 } 199 200 if (!(o instanceof ContainerEncryptionParams)) { 201 return false; 202 } 203 204 final ContainerEncryptionParams other = (ContainerEncryptionParams) o; 205 206 // Primitive comparison 207 if ((mAuthenticatedDataStart != other.mAuthenticatedDataStart) 208 || (mEncryptedDataStart != other.mEncryptedDataStart) 209 || (mDataEnd != other.mDataEnd)) { 210 return false; 211 } 212 213 // String comparison 214 if (!mEncryptionAlgorithm.equals(other.mEncryptionAlgorithm) 215 || !mMacAlgorithm.equals(other.mMacAlgorithm)) { 216 return false; 217 } 218 219 // Object comparison 220 if (!isSecretKeyEqual(mEncryptionKey, other.mEncryptionKey) 221 || !isSecretKeyEqual(mMacKey, other.mMacKey)) { 222 return false; 223 } 224 225 if (!Arrays.equals(mEncryptionSpec.getIV(), other.mEncryptionSpec.getIV()) 226 || !Arrays.equals(mMacTag, other.mMacTag) || (mMacSpec != other.mMacSpec)) { 227 return false; 228 } 229 230 return true; 231 } 232 233 private static final boolean isSecretKeyEqual(SecretKey key1, SecretKey key2) { 234 final String keyFormat = key1.getFormat(); 235 final String otherKeyFormat = key2.getFormat(); 236 237 if (keyFormat == null) { 238 if (keyFormat != otherKeyFormat) { 239 return false; 240 } 241 242 if (key1.getEncoded() != key2.getEncoded()) { 243 return false; 244 } 245 } else { 246 if (!keyFormat.equals(key2.getFormat())) { 247 return false; 248 } 249 250 if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) { 251 return false; 252 } 253 } 254 255 return true; 256 } 257 258 @Override 259 public int hashCode() { 260 int hash = 3; 261 262 hash += 5 * mEncryptionAlgorithm.hashCode(); 263 hash += 7 * Arrays.hashCode(mEncryptionSpec.getIV()); 264 hash += 11 * mEncryptionKey.hashCode(); 265 hash += 13 * mMacAlgorithm.hashCode(); 266 hash += 17 * mMacKey.hashCode(); 267 hash += 19 * Arrays.hashCode(mMacTag); 268 hash += 23 * mAuthenticatedDataStart; 269 hash += 29 * mEncryptedDataStart; 270 hash += 31 * mDataEnd; 271 272 return hash; 273 } 274 275 @Override 276 public String toString() { 277 final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX); 278 279 sb.append("mEncryptionAlgorithm=\""); 280 sb.append(mEncryptionAlgorithm); 281 sb.append("\","); 282 sb.append("mEncryptionSpec="); 283 sb.append(mEncryptionSpec.toString()); 284 sb.append("mEncryptionKey="); 285 sb.append(mEncryptionKey.toString()); 286 287 sb.append("mMacAlgorithm=\""); 288 sb.append(mMacAlgorithm); 289 sb.append("\","); 290 sb.append("mMacSpec="); 291 sb.append(mMacSpec.toString()); 292 sb.append("mMacKey="); 293 sb.append(mMacKey.toString()); 294 295 sb.append(",mAuthenticatedDataStart="); 296 sb.append(mAuthenticatedDataStart); 297 sb.append(",mEncryptedDataStart="); 298 sb.append(mEncryptedDataStart); 299 sb.append(",mDataEnd="); 300 sb.append(mDataEnd); 301 sb.append('}'); 302 303 return sb.toString(); 304 } 305 306 @Override 307 public void writeToParcel(Parcel dest, int flags) { 308 dest.writeString(mEncryptionAlgorithm); 309 dest.writeInt(ENC_PARAMS_IV_PARAMETERS); 310 dest.writeByteArray(mEncryptionSpec.getIV()); 311 dest.writeSerializable(mEncryptionKey); 312 313 dest.writeString(mMacAlgorithm); 314 dest.writeInt(MAC_PARAMS_NONE); 315 dest.writeByteArray(new byte[0]); 316 dest.writeSerializable(mMacKey); 317 318 dest.writeByteArray(mMacTag); 319 320 dest.writeLong(mAuthenticatedDataStart); 321 dest.writeLong(mEncryptedDataStart); 322 dest.writeLong(mDataEnd); 323 } 324 325 private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException { 326 mEncryptionAlgorithm = source.readString(); 327 final int encParamType = source.readInt(); 328 final byte[] encParamsEncoded = source.createByteArray(); 329 mEncryptionKey = (SecretKey) source.readSerializable(); 330 331 mMacAlgorithm = source.readString(); 332 final int macParamType = source.readInt(); 333 source.createByteArray(); // byte[] macParamsEncoded 334 mMacKey = (SecretKey) source.readSerializable(); 335 336 mMacTag = source.createByteArray(); 337 338 mAuthenticatedDataStart = source.readLong(); 339 mEncryptedDataStart = source.readLong(); 340 mDataEnd = source.readLong(); 341 342 switch (encParamType) { 343 case ENC_PARAMS_IV_PARAMETERS: 344 mEncryptionSpec = new IvParameterSpec(encParamsEncoded); 345 break; 346 default: 347 throw new InvalidAlgorithmParameterException("Unknown parameter type " 348 + encParamType); 349 } 350 351 switch (macParamType) { 352 case MAC_PARAMS_NONE: 353 mMacSpec = null; 354 break; 355 default: 356 throw new InvalidAlgorithmParameterException("Unknown parameter type " 357 + macParamType); 358 } 359 360 if (mEncryptionKey == null) { 361 throw new NullPointerException("encryptionKey == null"); 362 } 363 } 364 365 public static final Parcelable.Creator<ContainerEncryptionParams> CREATOR = 366 new Parcelable.Creator<ContainerEncryptionParams>() { 367 public ContainerEncryptionParams createFromParcel(Parcel source) { 368 try { 369 return new ContainerEncryptionParams(source); 370 } catch (InvalidAlgorithmParameterException e) { 371 Slog.e(TAG, "Invalid algorithm parameters specified", e); 372 return null; 373 } 374 } 375 376 public ContainerEncryptionParams[] newArray(int size) { 377 return new ContainerEncryptionParams[size]; 378 } 379 }; 380 }