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

Commit 8e39736f authored by Paul Lawrence's avatar Paul Lawrence
Browse files

Support default, pattern, pin and password encryption types

Java plumbing to expose methods to get/set encryption type in
IMountService, and hooking up of those methods to the Settings app
so the type is set correctly.

Needs matching vold changes from
 https://googleplex-android-review.googlesource.com/#/c/412649/

Bug: 8769627
Change-Id: I70c0ed72d11f5ab6f0958a7f9c101b6822b13baa
parent f6475c72
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -642,12 +642,13 @@ public interface IMountService extends IInterface {
                return _result;
            }

            public int changeEncryptionPassword(String password) throws RemoteException {
            public int changeEncryptionPassword(int type, String password) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(type);
                    _data.writeString(password);
                    mRemote.transact(Stub.TRANSACTION_changeEncryptionPassword, _data, _reply, 0);
                    _reply.readException();
@@ -677,6 +678,22 @@ public interface IMountService extends IInterface {
                return _result;
            }

            public int getPasswordType() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPasswordType, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            public StorageVolume[] getVolumeList() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
@@ -829,6 +846,8 @@ public interface IMountService extends IInterface {

        static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34;

        static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 36;

        /**
         * Cast an IBinder object into an IMountService interface, generating a
         * proxy if needed.
@@ -1130,8 +1149,9 @@ public interface IMountService extends IInterface {
                }
                case TRANSACTION_changeEncryptionPassword: {
                    data.enforceInterface(DESCRIPTOR);
                    int type = data.readInt();
                    String password = data.readString();
                    int result = changeEncryptionPassword(password);
                    int result = changeEncryptionPassword(type, password);
                    reply.writeNoException();
                    reply.writeInt(result);
                    return true;
@@ -1181,6 +1201,13 @@ public interface IMountService extends IInterface {
                    reply.writeInt(result);
                    return true;
                }
                case TRANSACTION_getPasswordType: {
                    data.enforceInterface(DESCRIPTOR);
                    int result = getPasswordType();
                    reply.writeNoException();
                    reply.writeInt(result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
@@ -1375,7 +1402,8 @@ public interface IMountService extends IInterface {
    /**
     * Changes the encryption password.
     */
    public int changeEncryptionPassword(String password) throws RemoteException;
    public int changeEncryptionPassword(int type, String password)
        throws RemoteException;

    /**
     * Verify the encryption password against the stored volume.  This method
@@ -1412,4 +1440,10 @@ public interface IMountService extends IInterface {
     * external storage data or OBB directory belonging to calling app.
     */
    public int mkdirs(String callingPkg, String path) throws RemoteException;

    /**
     * Determines the type of the encryption password
     * @return PasswordType
     */
    public int getPasswordType() throws RemoteException;
}
+10 −0
Original line number Diff line number Diff line
@@ -645,4 +645,14 @@ public class StorageManager {
        return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
                DEFAULT_FULL_THRESHOLD_BYTES);
    }

    /// Consts to match the password types in cryptfs.h
    /** @hide */
    public static final int CRYPT_TYPE_PASSWORD = 0;
    /** @hide */
    public static final int CRYPT_TYPE_DEFAULT = 1;
    /** @hide */
    public static final int CRYPT_TYPE_PATTERN = 2;
    /** @hide */
    public static final int CRYPT_TYPE_PIN = 3;
}
+22 −6
Original line number Diff line number Diff line
@@ -30,10 +30,12 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.view.IWindowManager;
import android.view.View;
import android.widget.Button;
@@ -498,6 +500,13 @@ public class LockPatternUtils {
            getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
            DevicePolicyManager dpm = getDevicePolicyManager();
            if (pattern != null) {

                int userHandle = getCurrentOrCallingUserId();
                if (userHandle == UserHandle.USER_OWNER) {
                    String stringPattern = patternToString(pattern);
                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
                }

                setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
                if (!isFallback) {
                    deleteGallery();
@@ -565,7 +574,7 @@ public class LockPatternUtils {
    }

    /** Update the encryption password if it is enabled **/
    private void updateEncryptionPassword(String password) {
    private void updateEncryptionPassword(int type, String password) {
        DevicePolicyManager dpm = getDevicePolicyManager();
        if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
                != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
@@ -580,7 +589,7 @@ public class LockPatternUtils {

        IMountService mountService = IMountService.Stub.asInterface(service);
        try {
            mountService.changeEncryptionPassword(password);
            mountService.changeEncryptionPassword(type, password);
        } catch (RemoteException e) {
            Log.e(TAG, "Error changing encryption password", e);
        }
@@ -623,12 +632,15 @@ public class LockPatternUtils {
            getLockSettings().setLockPassword(password, userHandle);
            DevicePolicyManager dpm = getDevicePolicyManager();
            if (password != null) {
                int computedQuality = computePasswordQuality(password);

                if (userHandle == UserHandle.USER_OWNER) {
                    // Update the encryption password.
                    updateEncryptionPassword(password);
                    int type = computedQuality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
                        ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD;
                    updateEncryptionPassword(type, password);
                }

                int computedQuality = computePasswordQuality(password);
                if (!isFallback) {
                    deleteGallery();
                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
@@ -675,8 +687,7 @@ public class LockPatternUtils {
                            0, 0, 0, 0, 0, 0, 0, userHandle);
                }
                // Add the password to the password history. We assume all
                // password
                // hashes have the same length for simplicity of implementation.
                // password hashes have the same length for simplicity of implementation.
                String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
                if (passwordHistory == null) {
                    passwordHistory = new String();
@@ -695,6 +706,11 @@ public class LockPatternUtils {
                }
                setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
            } else {
                if (userHandle == UserHandle.USER_OWNER) {
                    // Update the encryption password.
                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, password);
                }

                dpm.setActivePasswordState(
                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
                        userHandle);
+51 −9
Original line number Diff line number Diff line
@@ -73,13 +73,16 @@ import com.android.server.pm.UserManagerService;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;

import org.apache.commons.codec.binary.Hex;
import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
@@ -189,6 +192,12 @@ class MountService extends IMountService.Stub
        public static final int FstrimCompleted                = 700;
    }

    /** List of crypto types.
      * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
      * corresponding commands in CommandListener.cpp */
    public static final String[] CRYPTO_TYPES
        = { "password", "default", "pattern", "pin" };

    private Context mContext;
    private NativeDaemonConnector mConnector;

@@ -2036,6 +2045,14 @@ class MountService extends IMountService.Stub
        }
    }

    private String toHex(String password) {
        if (password == null) {
            return null;
        }
        byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
        return new String(Hex.encodeHex(bytes));
    }

    @Override
    public int decryptStorage(String password) {
        if (TextUtils.isEmpty(password)) {
@@ -2053,7 +2070,7 @@ class MountService extends IMountService.Stub

        final NativeDaemonEvent event;
        try {
            event = mConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
            event = mConnector.execute("cryptfs", "checkpw", new SensitiveArg(toHex(password)));

            final int code = Integer.parseInt(event.getMessage());
            if (code == 0) {
@@ -2092,7 +2109,8 @@ class MountService extends IMountService.Stub
        }

        try {
            mConnector.execute("cryptfs", "enablecrypto", "inplace", new SensitiveArg(password));
            mConnector.execute("cryptfs", "enablecrypto", "inplace",
                               new SensitiveArg(toHex(password)));
        } catch (NativeDaemonConnectorException e) {
            // Encryption failed
            return e.getCode();
@@ -2101,11 +2119,11 @@ class MountService extends IMountService.Stub
        return 0;
    }

    public int changeEncryptionPassword(String password) {
        if (TextUtils.isEmpty(password)) {
            throw new IllegalArgumentException("password cannot be empty");
        }

    /** Set the password for encrypting the master key.
     *  @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
     *  @param password The password to set.
     */
    public int changeEncryptionPassword(int type, String password) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
            "no permission to access the crypt keeper");

@@ -2117,7 +2135,8 @@ class MountService extends IMountService.Stub

        final NativeDaemonEvent event;
        try {
            event = mConnector.execute("cryptfs", "changepw", new SensitiveArg(password));
            event = mConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
                                       new SensitiveArg(toHex(password)));
            return Integer.parseInt(event.getMessage());
        } catch (NativeDaemonConnectorException e) {
            // Encryption failed
@@ -2150,7 +2169,7 @@ class MountService extends IMountService.Stub

        final NativeDaemonEvent event;
        try {
            event = mConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
            event = mConnector.execute("cryptfs", "verifypw", new SensitiveArg(toHex(password)));
            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
            return Integer.parseInt(event.getMessage());
        } catch (NativeDaemonConnectorException e) {
@@ -2159,6 +2178,29 @@ class MountService extends IMountService.Stub
        }
    }

    /**
     * Get the type of encryption used to encrypt the master key.
     * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
     */
    @Override
    public int getPasswordType() throws RemoteException {

        waitForReady();

        final NativeDaemonEvent event;
        try {
            event = mConnector.execute("cryptfs", "getpwtype");
            for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
                if (CRYPTO_TYPES[i].equals(event.getMessage()))
                    return i;
            }

            throw new IllegalStateException("unexpected return from cryptfs");
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public int mkdirs(String callingPkg, String appPath) {
        final int userId = UserHandle.getUserId(Binder.getCallingUid());