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}