Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29bb27ef authored by Kenny Root's avatar Kenny Root Committed by Android (Google) Code Review
Browse files

Merge "Add encryption parameters to package installation" into jb-dev

parents d57521c6 ceb1b0bf
Loading
Loading
Loading
Loading
+131 −4
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.commands.pm;

import com.android.internal.content.PackageHelper;

import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -40,17 +43,20 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;

import com.android.internal.content.PackageHelper;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.InvalidAlgorithmParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;

import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public final class Pm {
    IPackageManager mPm;

@@ -763,6 +769,15 @@ public final class Pm {
        String installerPackageName = null;

        String opt;

        String algo = null;
        byte[] iv = null;
        byte[] key = null;

        String macAlgo = null;
        byte[] macKey = null;
        byte[] tag = null;

        while ((opt=nextOption()) != null) {
            if (opt.equals("-l")) {
                installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
@@ -783,6 +798,48 @@ public final class Pm {
            } else if (opt.equals("-f")) {
                // Override if -s option is specified.
                installFlags |= PackageManager.INSTALL_INTERNAL;
            } else if (opt.equals("--algo")) {
                algo = nextOptionData();
                if (algo == null) {
                    System.err.println("Error: must supply argument for --algo");
                    showUsage();
                    return;
                }
            } else if (opt.equals("--iv")) {
                iv = hexToBytes(nextOptionData());
                if (iv == null) {
                    System.err.println("Error: must supply argument for --iv");
                    showUsage();
                    return;
                }
            } else if (opt.equals("--key")) {
                key = hexToBytes(nextOptionData());
                if (key == null) {
                    System.err.println("Error: must supply argument for --key");
                    showUsage();
                    return;
                }
            } else if (opt.equals("--macalgo")) {
                macAlgo = nextOptionData();
                if (macAlgo == null) {
                    System.err.println("Error: must supply argument for --macalgo");
                    showUsage();
                    return;
                }
            } else if (opt.equals("--mackey")) {
                macKey = hexToBytes(nextOptionData());
                if (macKey == null) {
                    System.err.println("Error: must supply argument for --mackey");
                    showUsage();
                    return;
                }
            } else if (opt.equals("--tag")) {
                tag = hexToBytes(nextOptionData());
                if (tag == null) {
                    System.err.println("Error: must supply argument for --tag");
                    showUsage();
                    return;
                }
            } else {
                System.err.println("Error: Unknown option: " + opt);
                showUsage();
@@ -790,6 +847,44 @@ public final class Pm {
            }
        }

        final ContainerEncryptionParams encryptionParams;
        if (algo != null || iv != null || key != null || macAlgo != null || macKey != null
                || tag != null) {
            if (algo == null || iv == null || key == null) {
                System.err.println("Error: all of --algo, --iv, and --key must be specified");
                showUsage();
                return;
            }

            if (macAlgo != null || macKey != null || tag != null) {
                if (macAlgo == null || macKey == null || tag == null) {
                    System.err.println("Error: all of --macalgo, --mackey, and --tag must "
                            + "be specified");
                    showUsage();
                    return;
                }
            }

            try {
                final SecretKey encKey = new SecretKeySpec(key, "RAW");

                final SecretKey macSecretKey;
                if (macKey == null || macKey.length == 0) {
                    macSecretKey = null;
                } else {
                    macSecretKey = new SecretKeySpec(macKey, "RAW");
                }

                encryptionParams = new ContainerEncryptionParams(algo, new IvParameterSpec(iv),
                        encKey, macAlgo, null, macSecretKey, tag, -1, -1, -1);
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
                return;
            }
        } else {
            encryptionParams = null;
        }

        final Uri apkURI;
        final Uri verificationURI;

@@ -816,7 +911,7 @@ public final class Pm {
        PackageInstallObserver obs = new PackageInstallObserver();
        try {
            mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName,
                    verificationURI, null);
                    verificationURI, null, encryptionParams);

            synchronized (obs) {
                while (!obs.finished) {
@@ -839,6 +934,37 @@ public final class Pm {
        }
    }

    /**
     * Convert a string containing hex-encoded bytes to a byte array.
     *
     * @param input String containing hex-encoded bytes
     * @return input as an array of bytes
     */
    private byte[] hexToBytes(String input) {
        if (input == null) {
            return null;
        }

        final int inputLength = input.length();
        if ((inputLength % 2) != 0) {
            System.err.print("Invalid length; must be multiple of 2");
            return null;
        }

        final int byteLength = inputLength / 2;
        final byte[] output = new byte[byteLength];

        int inputIndex = 0;
        int byteIndex = 0;
        while (inputIndex < inputLength) {
            output[byteIndex++] = (byte) Integer.parseInt(
                    input.substring(inputIndex, inputIndex + 2), 16);
            inputIndex += 2;
        }

        return output;
    }

    public void runCreateUser() {
        // Need to be run as root
        if (Process.myUid() != ROOT_UID) {
@@ -1236,7 +1362,8 @@ public final class Pm {
        System.err.println("       pm list libraries");
        System.err.println("       pm list users");
        System.err.println("       pm path PACKAGE");
        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>] PATH");
        System.err.println("       pm uninstall [-k] PACKAGE");
        System.err.println("       pm clear PACKAGE");
        System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
+3 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -973,10 +974,10 @@ final class ApplicationPackageManager extends PackageManager {
    @Override
    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
            int flags, String installerPackageName, Uri verificationURI,
            ManifestDigest manifestDigest) {
            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
        try {
            mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
                    verificationURI, manifestDigest);
                    verificationURI, manifestDigest, encryptionParams);
        } catch (RemoteException e) {
            // Should never happen!
        }
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;

parcelable ContainerEncryptionParams;
+378 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;

import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Slog;

import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

/**
 * Represents encryption parameters used to read a container.
 *
 * @hide
 */
public class ContainerEncryptionParams implements Parcelable {
    protected static final String TAG = "ContainerEncryptionParams";

    /** What we print out first when toString() is called. */
    private static final String TO_STRING_PREFIX = "ContainerEncryptionParams{";

    /**
     * Parameter type for parceling that indicates the next parameters are
     * IvParameters.
     */
    private static final int ENC_PARAMS_IV_PARAMETERS = 1;

    /** Parameter type for paceling that indicates there are no MAC parameters. */
    private static final int MAC_PARAMS_NONE = 1;

    /** The encryption algorithm used. */
    private final String mEncryptionAlgorithm;

    /** The parameter spec to be used for encryption. */
    private final IvParameterSpec mEncryptionSpec;

    /** Secret key to be used for decryption. */
    private final SecretKey mEncryptionKey;

    /** Algorithm name for the MAC to be used. */
    private final String mMacAlgorithm;

    /** The parameter spec to be used for the MAC tag authentication. */
    private final AlgorithmParameterSpec mMacSpec;

    /** Secret key to be used for MAC tag authentication. */
    private final SecretKey mMacKey;

    /** MAC tag authenticating the data in the container. */
    private final byte[] mMacTag;

    /** Offset into file where authenticated (e.g., MAC protected) data begins. */
    private final int mAuthenticatedDataStart;

    /** Offset into file where encrypted data begins. */
    private final int mEncryptedDataStart;

    /**
     * Offset into file for the end of encrypted data (and, by extension,
     * authenticated data) in file.
     */
    private final int mDataEnd;

    public ContainerEncryptionParams(String encryptionAlgorithm,
            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
            throws InvalidAlgorithmParameterException {
        this(encryptionAlgorithm, encryptionSpec, encryptionKey, null, null, null, null, -1, -1,
                -1);
    }

    /**
     * Creates container encryption specifications for installing from encrypted
     * containers.
     *
     * @param encryptionAlgorithm encryption algorithm to use; format matches
     *            JCE
     * @param encryptionSpec algorithm parameter specification
     * @param encryptionKey key used for decryption
     * @param macAlgorithm MAC algorithm to use; format matches JCE
     * @param macSpec algorithm parameters specification, may be {@code null}
     * @param macKey key used for authentication (i.e., for the MAC tag)
     * @param authenticatedDataStart offset of start of authenticated data in
     *            stream
     * @param encryptedDataStart offset of start of encrypted data in stream
     * @param dataEnd offset of the end of both the authenticated and encrypted
     *            data
     * @throws InvalidAlgorithmParameterException
     */
    public ContainerEncryptionParams(String encryptionAlgorithm,
            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
            AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
            int authenticatedDataStart, int encryptedDataStart, int dataEnd)
            throws InvalidAlgorithmParameterException {
        if (TextUtils.isEmpty(encryptionAlgorithm)) {
            throw new NullPointerException("algorithm == null");
        } else if (encryptionSpec == null) {
            throw new NullPointerException("encryptionSpec == null");
        } else if (encryptionKey == null) {
            throw new NullPointerException("encryptionKey == null");
        }

        if (!TextUtils.isEmpty(macAlgorithm)) {
            if (macKey == null) {
                throw new NullPointerException("macKey == null");
            }
        }

        if (!(encryptionSpec instanceof IvParameterSpec)) {
            throw new InvalidAlgorithmParameterException(
                    "Unknown parameter spec class; must be IvParameters");
        }

        mEncryptionAlgorithm = encryptionAlgorithm;
        mEncryptionSpec = (IvParameterSpec) encryptionSpec;
        mEncryptionKey = encryptionKey;

        mMacAlgorithm = macAlgorithm;
        mMacSpec = macSpec;
        mMacKey = macKey;
        mMacTag = macTag;

        mAuthenticatedDataStart = authenticatedDataStart;
        mEncryptedDataStart = encryptedDataStart;
        mDataEnd = dataEnd;
    }

    public String getEncryptionAlgorithm() {
        return mEncryptionAlgorithm;
    }

    public AlgorithmParameterSpec getEncryptionSpec() {
        return mEncryptionSpec;
    }

    public SecretKey getEncryptionKey() {
        return mEncryptionKey;
    }

    public String getMacAlgorithm() {
        return mMacAlgorithm;
    }

    public AlgorithmParameterSpec getMacSpec() {
        return mMacSpec;
    }

    public SecretKey getMacKey() {
        return mMacKey;
    }

    public byte[] getMacTag() {
        return mMacTag;
    }

    public int getAuthenticatedDataStart() {
        return mAuthenticatedDataStart;
    }

    public int getEncryptedDataStart() {
        return mEncryptedDataStart;
    }

    public int getDataEnd() {
        return mDataEnd;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof ContainerEncryptionParams)) {
            return false;
        }

        final ContainerEncryptionParams other = (ContainerEncryptionParams) o;

        // Primitive comparison
        if ((mAuthenticatedDataStart != other.mAuthenticatedDataStart)
                || (mEncryptedDataStart != other.mEncryptedDataStart)
                || (mDataEnd != other.mDataEnd)) {
            return false;
        }

        // String comparison
        if (!mEncryptionAlgorithm.equals(other.mEncryptionAlgorithm)
                || !mMacAlgorithm.equals(other.mMacAlgorithm)) {
            return false;
        }

        // Object comparison
        if (!isSecretKeyEqual(mEncryptionKey, other.mEncryptionKey)
                || !isSecretKeyEqual(mMacKey, other.mMacKey)) {
            return false;
        }

        if (!Arrays.equals(mEncryptionSpec.getIV(), other.mEncryptionSpec.getIV())
                || !Arrays.equals(mMacTag, other.mMacTag) || (mMacSpec != other.mMacSpec)) {
            return false;
        }

        return true;
    }

    private static final boolean isSecretKeyEqual(SecretKey key1, SecretKey key2) {
        final String keyFormat = key1.getFormat();
        final String otherKeyFormat = key2.getFormat();

        if (keyFormat == null) {
            if (keyFormat != otherKeyFormat) {
                return false;
            }

            if (key1.getEncoded() != key2.getEncoded()) {
                return false;
            }
        } else {
            if (!keyFormat.equals(key2.getFormat())) {
                return false;
            }

            if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
                return false;
            }
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;

        hash += 5 * mEncryptionAlgorithm.hashCode();
        hash += 7 * Arrays.hashCode(mEncryptionSpec.getIV());
        hash += 11 * mEncryptionKey.hashCode();
        hash += 13 * mMacAlgorithm.hashCode();
        hash += 17 * mMacKey.hashCode();
        hash += 19 * Arrays.hashCode(mMacTag);
        hash += 23 * mAuthenticatedDataStart;
        hash += 29 * mEncryptedDataStart;
        hash += 31 * mDataEnd;

        return hash;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);

        sb.append("mEncryptionAlgorithm=\"");
        sb.append(mEncryptionAlgorithm);
        sb.append("\",");
        sb.append("mEncryptionSpec=");
        sb.append(mEncryptionSpec.toString());
        sb.append("mEncryptionKey=");
        sb.append(mEncryptionKey.toString());

        sb.append("mMacAlgorithm=\"");
        sb.append(mMacAlgorithm);
        sb.append("\",");
        sb.append("mMacSpec=");
        sb.append(mMacSpec.toString());
        sb.append("mMacKey=");
        sb.append(mMacKey.toString());

        sb.append(",mAuthenticatedDataStart=");
        sb.append(mAuthenticatedDataStart);
        sb.append(",mEncryptedDataStart=");
        sb.append(mEncryptedDataStart);
        sb.append(",mDataEnd=");
        sb.append(mDataEnd);
        sb.append('}');

        return sb.toString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mEncryptionAlgorithm);
        dest.writeInt(ENC_PARAMS_IV_PARAMETERS);
        dest.writeByteArray(mEncryptionSpec.getIV());
        dest.writeSerializable(mEncryptionKey);

        dest.writeString(mMacAlgorithm);
        dest.writeInt(MAC_PARAMS_NONE);
        dest.writeByteArray(new byte[0]);
        dest.writeSerializable(mMacKey);

        dest.writeByteArray(mMacTag);

        dest.writeInt(mAuthenticatedDataStart);
        dest.writeInt(mEncryptedDataStart);
        dest.writeInt(mDataEnd);
    }

    private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
        mEncryptionAlgorithm = source.readString();
        final int encParamType = source.readInt();
        final byte[] encParamsEncoded = source.createByteArray();
        mEncryptionKey = (SecretKey) source.readSerializable();

        mMacAlgorithm = source.readString();
        final int macParamType = source.readInt();
        source.createByteArray(); // byte[] macParamsEncoded
        mMacKey = (SecretKey) source.readSerializable();

        mMacTag = source.createByteArray();

        mAuthenticatedDataStart = source.readInt();
        mEncryptedDataStart = source.readInt();
        mDataEnd = source.readInt();

        switch (encParamType) {
            case ENC_PARAMS_IV_PARAMETERS:
                mEncryptionSpec = new IvParameterSpec(encParamsEncoded);
                break;
            default:
                throw new InvalidAlgorithmParameterException("Unknown parameter type "
                        + encParamType);
        }

        switch (macParamType) {
            case MAC_PARAMS_NONE:
                mMacSpec = null;
                break;
            default:
                throw new InvalidAlgorithmParameterException("Unknown parameter type "
                        + macParamType);
        }

        if (mEncryptionKey == null) {
            throw new NullPointerException("encryptionKey == null");
        }
    }

    public static final Parcelable.Creator<ContainerEncryptionParams> CREATOR =
            new Parcelable.Creator<ContainerEncryptionParams>() {
        public ContainerEncryptionParams createFromParcel(Parcel source) {
            try {
                return new ContainerEncryptionParams(source);
            } catch (InvalidAlgorithmParameterException e) {
                Slog.e(TAG, "Invalid algorithm parameters specified", e);
                return null;
            }
        }

        public ContainerEncryptionParams[] newArray(int size) {
            return new ContainerEncryptionParams[size];
        }
    };
}
 No newline at end of file
+2 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -362,7 +363,7 @@ interface IPackageManager {

    void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
            int flags, in String installerPackageName, in Uri verificationURI,
            in ManifestDigest manifestDigest);
            in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);

    void verifyPendingInstall(int id, int verificationCode);

Loading