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

Commit 70bb9a64 authored by Bram Bonné's avatar Bram Bonné
Browse files

Ports encryption/storage from gmscore to AOSP.

A few additional changes (apart from style and usual dependencies) were needed:
- BackupEncryptionDbHelper now extends SQLiteOpenHelper directly,
implementing relevant methods.
- Dependencies on Guava are replaced by their Java equivalents.

Bug: 111386661
Test: atest RunFrameworksServicesRoboTests
Change-Id: I4566980fc81d6cff5e7012184502e028980512ae
parent 9347978d
Loading
Loading
Loading
Loading
+59 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.backup.encryption.storage;

import android.content.Context;

/**
 * Backup encryption SQLite database. All instances are threadsafe.
 *
 * <p>The database is automatically opened when accessing one of the tables. After the caller is
 * done they must call {@link #close()}.
 */
public class BackupEncryptionDb {
    private final BackupEncryptionDbHelper mHelper;

    /** A new instance, using the storage defined by {@code context}. */
    public static BackupEncryptionDb newInstance(Context context) {
        BackupEncryptionDbHelper helper = new BackupEncryptionDbHelper(context);
        helper.setWriteAheadLoggingEnabled(true);
        return new BackupEncryptionDb(helper);
    }

    private BackupEncryptionDb(BackupEncryptionDbHelper helper) {
        mHelper = helper;
    }

    public TertiaryKeysTable getTertiaryKeysTable() {
        return new TertiaryKeysTable(mHelper);
    }

    /** Deletes the database. */
    public void clear() throws EncryptionDbException {
        mHelper.resetDatabase();
    }

    /**
     * Closes the database if it is open.
     *
     * <p>After calling this, the caller may access one of the tables again which will automatically
     * reopen the database.
     */
    public void close() {
        mHelper.close();
    }
}
+41 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.backup.encryption.storage;

import android.provider.BaseColumns;

/** Contract for the backup encryption database. Describes tables present. */
class BackupEncryptionDbContract {
    /**
     * Table containing tertiary keys belonging to the user. Tertiary keys are wrapped by a
     * secondary key, which never leaves {@code AndroidKeyStore} (a provider for {@link
     * java.security.KeyStore}). Each application has a tertiary key, which is used to encrypt the
     * backup data.
     */
    static class TertiaryKeysEntry implements BaseColumns {
        static final String TABLE_NAME = "tertiary_keys";

        /** Alias of the secondary key used to wrap the tertiary key. */
        static final String COLUMN_NAME_SECONDARY_KEY_ALIAS = "secondary_key_alias";

        /** Name of the package to which the tertiary key belongs. */
        static final String COLUMN_NAME_PACKAGE_NAME = "package_name";

        /** Encrypted bytes of the tertiary key. */
        static final String COLUMN_NAME_WRAPPED_KEY_BYTES = "wrapped_key_bytes";
    }
}
+102 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.backup.encryption.storage;

import static com.android.server.backup.encryption.storage.BackupEncryptionDbContract.TertiaryKeysEntry;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

/** Helper for creating an instance of the backup encryption database. */
class BackupEncryptionDbHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 1;
    static final String DATABASE_NAME = "backupencryption.db";

    private static final String SQL_CREATE_TERTIARY_KEYS_ENTRY =
            "CREATE TABLE "
                    + TertiaryKeysEntry.TABLE_NAME
                    + " ( "
                    + TertiaryKeysEntry._ID
                    + " INTEGER PRIMARY KEY,"
                    + TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS
                    + " TEXT,"
                    + TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME
                    + " TEXT,"
                    + TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES
                    + " BLOB,"
                    + "UNIQUE("
                    + TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS
                    + ","
                    + TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME
                    + "))";

    private static final String SQL_DROP_TERTIARY_KEYS_ENTRY =
            "DROP TABLE IF EXISTS " + TertiaryKeysEntry.TABLE_NAME;

    BackupEncryptionDbHelper(Context context) {
        super(context, DATABASE_NAME, /*factory=*/ null, DATABASE_VERSION);
    }

    public void resetDatabase() throws EncryptionDbException {
        SQLiteDatabase db = getWritableDatabaseSafe();
        db.execSQL(SQL_DROP_TERTIARY_KEYS_ENTRY);
        onCreate(db);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_TERTIARY_KEYS_ENTRY);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(SQL_DROP_TERTIARY_KEYS_ENTRY);
        onCreate(db);
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(SQL_DROP_TERTIARY_KEYS_ENTRY);
        onCreate(db);
    }

    /**
     * Calls {@link #getWritableDatabase()}, but catches the unchecked {@link SQLiteException} and
     * rethrows {@link EncryptionDbException}.
     */
    public SQLiteDatabase getWritableDatabaseSafe() throws EncryptionDbException {
        try {
            return super.getWritableDatabase();
        } catch (SQLiteException e) {
            throw new EncryptionDbException(e);
        }
    }

    /**
     * Calls {@link #getReadableDatabase()}, but catches the unchecked {@link SQLiteException} and
     * rethrows {@link EncryptionDbException}.
     */
    public SQLiteDatabase getReadableDatabaseSafe() throws EncryptionDbException {
        try {
            return super.getReadableDatabase();
        } catch (SQLiteException e) {
            throw new EncryptionDbException(e);
        }
    }
}
+26 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.backup.encryption.storage;

import java.io.IOException;

/** Thrown when there is a problem reading or writing the encryption database. */
public class EncryptionDbException extends IOException {
    public EncryptionDbException(Throwable cause) {
        super(cause);
    }
}
+52 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.backup.encryption.storage;

/** Wrapped bytes of a tertiary key. */
public class TertiaryKey {
    private final String mSecondaryKeyAlias;
    private final String mPackageName;
    private final byte[] mWrappedKeyBytes;

    /**
     * Creates a new instance.
     *
     * @param secondaryKeyAlias Alias of the secondary used to wrap the key.
     * @param packageName The package name of the app to which the key belongs.
     * @param wrappedKeyBytes The wrapped key bytes.
     */
    public TertiaryKey(String secondaryKeyAlias, String packageName, byte[] wrappedKeyBytes) {
        mSecondaryKeyAlias = secondaryKeyAlias;
        mPackageName = packageName;
        mWrappedKeyBytes = wrappedKeyBytes;
    }

    /** Returns the alias of the secondary key used to wrap this tertiary key. */
    public String getSecondaryKeyAlias() {
        return mSecondaryKeyAlias;
    }

    /** Returns the package name of the application this key relates to. */
    public String getPackageName() {
        return mPackageName;
    }

    /** Returns the wrapped bytes of the key. */
    public byte[] getWrappedKeyBytes() {
        return mWrappedKeyBytes;
    }
}
Loading