| /* |
| * 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.ContentValues; |
| import android.database.Cursor; |
| import android.database.sqlite.SQLiteDatabase; |
| import android.util.ArrayMap; |
| |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.Optional; |
| |
| /** Database table for storing and retrieving tertiary keys. */ |
| public class TertiaryKeysTable { |
| private final BackupEncryptionDbHelper mHelper; |
| |
| TertiaryKeysTable(BackupEncryptionDbHelper helper) { |
| mHelper = helper; |
| } |
| |
| /** |
| * Adds the {@code tertiaryKey} to the database. |
| * |
| * @return The primary key of the inserted row if successful, -1 otherwise. |
| */ |
| public long addKey(TertiaryKey tertiaryKey) throws EncryptionDbException { |
| SQLiteDatabase db = mHelper.getWritableDatabaseSafe(); |
| ContentValues values = new ContentValues(); |
| values.put( |
| TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS, |
| tertiaryKey.getSecondaryKeyAlias()); |
| values.put(TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME, tertiaryKey.getPackageName()); |
| values.put( |
| TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES, tertiaryKey.getWrappedKeyBytes()); |
| return db.replace(TertiaryKeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values); |
| } |
| |
| /** Gets the key wrapped by {@code secondaryKeyAlias} for app with {@code packageName}. */ |
| public Optional<TertiaryKey> getKey(String secondaryKeyAlias, String packageName) |
| throws EncryptionDbException { |
| SQLiteDatabase db = mHelper.getReadableDatabaseSafe(); |
| String[] projection = { |
| TertiaryKeysEntry._ID, |
| TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS, |
| TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME, |
| TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES |
| }; |
| String selection = |
| TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS |
| + " = ? AND " |
| + TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME |
| + " = ?"; |
| String[] selectionArguments = {secondaryKeyAlias, packageName}; |
| |
| try (Cursor cursor = |
| db.query( |
| TertiaryKeysEntry.TABLE_NAME, |
| projection, |
| selection, |
| selectionArguments, |
| /*groupBy=*/ null, |
| /*having=*/ null, |
| /*orderBy=*/ null)) { |
| int count = cursor.getCount(); |
| if (count == 0) { |
| return Optional.empty(); |
| } |
| |
| cursor.moveToFirst(); |
| byte[] wrappedKeyBytes = |
| cursor.getBlob( |
| cursor.getColumnIndexOrThrow( |
| TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES)); |
| return Optional.of(new TertiaryKey(secondaryKeyAlias, packageName, wrappedKeyBytes)); |
| } |
| } |
| |
| /** Returns all keys wrapped with {@code tertiaryKeyAlias} as an unmodifiable map. */ |
| public Map<String, TertiaryKey> getAllKeys(String secondaryKeyAlias) |
| throws EncryptionDbException { |
| SQLiteDatabase db = mHelper.getReadableDatabaseSafe(); |
| String[] projection = { |
| TertiaryKeysEntry._ID, |
| TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS, |
| TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME, |
| TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES |
| }; |
| String selection = TertiaryKeysEntry.COLUMN_NAME_SECONDARY_KEY_ALIAS + " = ?"; |
| String[] selectionArguments = {secondaryKeyAlias}; |
| |
| Map<String, TertiaryKey> keysByPackageName = new ArrayMap<>(); |
| try (Cursor cursor = |
| db.query( |
| TertiaryKeysEntry.TABLE_NAME, |
| projection, |
| selection, |
| selectionArguments, |
| /*groupBy=*/ null, |
| /*having=*/ null, |
| /*orderBy=*/ null)) { |
| while (cursor.moveToNext()) { |
| String packageName = |
| cursor.getString( |
| cursor.getColumnIndexOrThrow( |
| TertiaryKeysEntry.COLUMN_NAME_PACKAGE_NAME)); |
| byte[] wrappedKeyBytes = |
| cursor.getBlob( |
| cursor.getColumnIndexOrThrow( |
| TertiaryKeysEntry.COLUMN_NAME_WRAPPED_KEY_BYTES)); |
| keysByPackageName.put( |
| packageName, |
| new TertiaryKey(secondaryKeyAlias, packageName, wrappedKeyBytes)); |
| } |
| } |
| return Collections.unmodifiableMap(keysByPackageName); |
| } |
| } |