Шифрование Realm с помощью ключа, хранящегося в KeyStore

Я пытаюсь настроить зашифрованный экземпляр области по умолчанию в своем приложении. Идея состоит в том, чтобы сгенерировать ключ с помощью KeyPairGenerator с заданным псевдонимом, сохранить его в AndroidKeyStore и использовать указанный ключ каждый раз, когда он необходим.

ЧТО Я ДЕЛАЮ

Вот как я генерирую ключ:

  KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
        ks.load(null);

        if (!ks.containsAlias(KEY_ALIAS)) {

            Calendar start = Calendar.getInstance();
            Calendar end = Calendar.getInstance();
            end.add(Calendar.YEAR, 99);

            KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
                    .setAlias(KEY_ALIAS)
                    .setSubject(new X500Principal("CN=Example, O=ExampleOrg"))
                    .setSerialNumber(BigInteger.ONE)
                    .setStartDate(start.getTime())
                    .setEndDate(end.getTime())
                    .build();

            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
            generator.initialize(spec);

            KeyPair keyPair = generator.generateKeyPair();
        }

Я использую KeyPairGenerator, так как мне нужно поддерживать API версии 18 и выше.

Вот как я настраиваю свой экземпляр области по умолчанию в своем приложении:

 RealmConfiguration config = null;
    try {
        config = new RealmConfiguration
                .Builder(this)
                .encryptionKey(ks.getKey(KEY_ALIAS, null).getEncoded())
                .name("dealmatrix.realm")
                .schemaVersion(1)
                .build();

где ks — это экземпляр хранилища ключей, полученный следующим образом:

Keystore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);

ЧТО ИДУТ НЕ ТАК

Моя проблема в том, что это выражение:

ks.getKey(KEY_ALIAS, null).getEncoded()

возвращает null, что по понятным причинам приводит к исключению.

Я читал в Интернете, что это предполагаемое поведение системы KeyStore.

Если я действительно не могу получить массив байтов сохраненного ключа шифрования, как я должен зашифровать свою область с помощью указанного ключа?

Существуют ли какие-либо другие способы безопасного хранения ключа шифрования, чтобы я мог использовать его в своей конфигурации области?


person Rakatan    schedule 08.04.2016    source источник
comment
Вы нашли какое-нибудь решение, я также столкнулся с этой проблемой   -  person Bala Saikrupa Puram    schedule 13.02.2018


Ответы (3)


В ветке feature/example/store_password репозитория Realm есть пример проекта WIP, который использует хранилище ключей Android.

https://github.com/realm/realm-java/tree/feature/example/store_password/examples/StoreEncryptionPassword

Основная логика написана в Store.java

Нам нужны дополнительные работы (очистка, добавление комментариев, поддержка старых устройств) перед выпуском этого примера проекта. Но я думаю, что этот проект поможет вам.

person zaki50    schedule 01.05.2016

Ключи хранилища ключей Android, возвращающие null из getEncoded, работают по назначению. Предполагается, что getEncoded возвращает материал ключа закрытого ключа (обычно в формате PKCS#8 с кодировкой DER) или null, если экспорт материала ключа не поддерживается. Android Keystore по своему дизайну не раскрывает и не экспортирует ключевой материал закрытых или секретных ключей, поэтому getEncoded возвращает значение null. См. https://developer.android.com/training/articles/keystore.html#SecurityFeatures.

Вы по-прежнему можете использовать эти ключи с абстракциями Signature и Cipher.

person Alex Klyubin    schedule 10.04.2016
comment
Хорошо я понял. То, что вы говорите, имеет смысл, но на самом деле это не отвечает на мой вопрос. Как я могу безопасно хранить ключ шифрования для моей конфигурации Realm? - person Rakatan; 11.04.2016
comment
Что такое Царство? Как правило, вы можете зашифровать материал с помощью примитива Cipher, который вы инициализируете экземпляром ключа. В этом случае вы можете получить экземпляр ключа из хранилища ключей Android. - person Alex Klyubin; 11.04.2016
comment
realm.io . Это база данных. Я знаю, как работает хранилище ключей, но метод шифрования базы данных принимает только массив байтов. - person Rakatan; 11.04.2016
comment
В этом случае кажется, что realm.io несовместим с криптографией, которая не пропускает ключевой материал в процесс, в котором работает realm.io, например криптографию Android Keystore. - person Alex Klyubin; 12.04.2016

Android Keystore запрещает извлекать из него приватные ключи. Таким образом, дизайн будет заключаться в создании ключа Realm за пределами хранилища ключей Android, чтобы вы могли использовать его для шифрования/дешифрования базы данных Realm.

Но для безопасного хранения этого ключа Realm вы должны использовать возможности хранилища ключей Android, зашифровав ключ Realm с помощью хранилища ключей Android, а затем сохранив его локально (например, общие настройки). Позже вы сможете прочитать этот зашифрованный ключ Realm, расшифровать его с помощью хранилища ключей Android и снова использовать для разблокировки базы данных Realm.

person Stefan Arn    schedule 01.03.2019