Android NFC эмуляция карты с фиксированным UID – CodeRoad

Android nfc эмуляция карты с фиксированным uid
– coderoad

Одно важно знать, что UID перенесли на очень низком уровне протокола nfc. Это значит, что это делается самостоятельно прошивкой nfc а не в рамках операционной системы android. У нас была такая же проблема в нашем NFCGate проекте и мы нашли решение для чипов Broadcom BCM20793 наподобие тех, что есть в Nexus4/5 и прочих, записав UID с NFC_SetConfig прямо в прошивку чипа.

Вы можете посмотреть рабочую версию в нашем репозитории на github . Вот не тестированная версия, чтобы показать принцип:

uint8_t cfg[] = {
    CFG_TYPE_UID, // config type
    3,            // uid length
    0x0A,         // uid byte 1
    0x0B,         // uid byte 2
    0x0C          // uid byte 3
};
NFC_SetConfig(sizeof(cfg), cfg);

Наши тесты выявили, что android иногда устанавливает UID обратно в рандомный (length=0 если я правильно помню), поэтому вам нужно найти хорошее место, чтобы задать его, когда вам это нужно или сделать что-то похожее, как мы сделали и перехватить вызовы NFC_SetConfig из android, чтобы заново установить наш собственный UID.

Can i change the uid of nfc tags

No, the UID of genuine Type 1 tags (from Broadcom or, formerly, Innovision) cannot be changed. That UID is a serial number that is permanently burned-in into read-only memory during the manufacturing process.

I’m not sure for Type 1 tags, but there are certainly other NFC-A tags available (typically from Chinese suppliers) that behave similar to NXP MIFARE products and permit changing the UID using special commands.

Note that it’s a really bad idea to use the UID/anti-collision identifier (or any other freely readable data) of NFC/RFID tags for authentication purposes since that information can easily be cloned. See also:

Keychain — связка ключей

Представленный в Android 4.0 (API Level 14), Keychain API управлял ключами. В частности, это работает с объектами PrivateKey и X509Certificate и обеспечивает более безопасный контейнер, чем использование хранилища данных вашего приложения.

Связано это с тем, что разрешения закрытых ключей открывают доступ к ключам только вашему приложению и только после авторизации пользователя. Это означает, что, прежде чем, вы сможете использовать хранилище учётных данных, на устройстве должен быть настроен экран блокировки. Кроме того, объекты в связке ключей можно объединить с защитой от оборудования, если доступно.

Код установки сертификата выглядит следующим образом:

Пользователю будет предложено ввести пароль для доступа к закрытому ключу и указать имя сертификата. Для получения ключа, в следующем коде представлен пользовательский интерфейс, который позволяет пользователю выбирать ключ из списка установленных ключей.

Keystore

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

Вот где можно использовать KeyStore API. Начиная с API 1, KeyStore используется системой для хранения учётных данных WiFi и VPN. Начиная с 4.3 (API 18), вы можете работать с асимметричными ключами конкретного приложения, а в Android M (API 23) можно хранить симметричный ключ AES.

Преимущество хранения ключа в хранилище ключей заключается в том, что он позволяет работать с ключами без раскрытия секретного содержимого этого ключа; данным ключа не место в приложении. Помните, что ключи защищаются разрешениями, так что только ваше приложение может получить к ним доступ, и они могут быть дополнительно защищены аппаратным обеспечением, если устройство поддерживает это. Создаётся контейнер, который усложняет извлечение ключей с устройства.

Генерирование нового случайного ключа

В этом примере вместо генерации ключа AES из предоставленного пользователем пароля мы можем автоматически сгенерировать случайный ключ, который будет защищён в хранилище ключей KeyStore. Мы можем сделать это, создав экземпляр KeyGenerator, настроенного на поставщика “AndroidKeyStore”.

Диспетчер учётных записей

Диспетчер учётных записей (Account Manager) — это централизованный помощник для работы с учётными данными пользователя, поэтому вашему приложению, иметь дело с паролями напрямую не нужно. Часто он предоставляет токен вместо реального имени пользователя и пароля, который можно использовать для выполнения аутентифицированных запросов к службе. Например, при запросе токена OAuth2.

Иногда, вся необходимая информация уже хранится на устройстве, а иногда Account Manager придётся обращаться к серверу за новым токеном. Вы, наверное, видели раздел Учётные записи в Настройках вашего устройства для разных приложений. И вот как, мы можем получить список доступных учётных записей:

Этому коду потребуется разрешение android.permission.GET_ACCOUNTS.  Если вы ищете определённую учётную запись, вы можете найти её вот так:

Использование асимметричных ключей rsa для старых устройств

Это хорошее решение для хранения данных в версии M и выше, но что, если ваше приложение поддерживает более ранние версии? Хотя симметричные ключи AES не поддерживаются в M, поддерживаются асимметричные ключи RSA. Это означает, что для достижения того же результата, мы можем использовать RSA ключи и шифрование.

Основное отличие заключается в том, что асимметричная пара ключей содержит два ключа: закрытый и открытый ключ, где открытый ключ шифрует данные, а закрытый ключ расшифровывает их. KeyPairGeneratorSpec передаётся в KeyPairGenerator, который инициализируется с помощью KEY_ALGORITHM_RSAи поставщика AndroidKeyStore.

Для шифрования, из пары ключей мы получаем RSAPublicKey и используем его с объектом Cipher.

Расшифровка выполняется с использованием объекта RSAPrivateKey.

Кое-что об RSA — шифрование медленнее, чем в AES. Для небольших объёмов информации, например, когда вы защищаете строки общих настроек, это не страшно. Если вы обнаружите проблему с производительностью при шифровании больших объёмов данных, то вместо этого вы можете использовать данный пример для шифрования и хранения только ключа AES.

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

Чтобы получить ключ, сделайте вот так:

Довольно много кода! Для простоты примеров, я пропустил обработку исключений. Но помните, что для итогового кода не рекомендуется просто перехватывать все случаи Throwable в одном операторе catch.

Расшифровка в массив байтов

Для расшифровки применяется обратный ход. Объект Cipher инициализируется с использованием константы DECRYPT_MODE, и возвращается расшифрованный массив byte[].

Смотрим на примере

Теперь мы можем посмотреть на пример!

Шифрование данных

Теперь, когда ключ хранится в хранилище KeyStore, мы можем создать метод, который зашифрует данные с использованием объекта Cipher, учитывая SecretKey. Это вернёт HashMap, содержащий зашифрованные данные и случайный ВИ, который понадобится для расшифровки данных. Зашифрованные данные вместе с ВИ могут быть сохранены в файл или в открытых настройках.

Заключение

На этом урок по работе с учётными данными и ключами завершён. Большая часть неразберихи вокруг ключей и хранилища связана с эволюцией ОС Android, но вы можете выбрать, какое решение использовать, учитывая уровень API, поддерживаемый вашим приложением.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *