Рубрики
Без рубрики

Защита секретного ключа в Android с помощью хранилища ключей

В какой-то момент времени мы все хотели обезопасить ваши данные от взлома / обратного проектирования. Th… С тегами android, безопасность, криптография, java.

В какой-то момент времени мы все хотели обезопасить ваши данные от взлома/обратного проектирования. Основные механизмы безопасности, такие как,

a. Защита, Сокращение ресурсов и минификация b. Скрывается в манифесте c. Скрывается в сборке. Степень d. Хранение в базе данных MySQL/корневой базе данных/SharedPreference e. Прячась в Strings.xml .

Все эти методы не обеспечивают максимальной безопасности. Наиболее распространенную и известную логику защиты ключа можно обойти либо путем изменения и извлечения его из файла dex->jar, либо путем укоренения устройства и доступа к хранилищу устройства. Но есть еще один метод, который превосходит их все. Механизм, который обычно используется приложениями для хранения очень конфиденциальных данных, таких как данные кредитной карты, банковский счет и тому подобное.

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

Объявить несколько переменных в Cryptor.java

частная статическая конечная строка ПРЕОБРАЗОВАНИЕ ; частная статическая конечная строка ANDROID_KEY_STORE ; закрытый байт[] iv ; частное хранилище ключей Хранилище ключей ; частная статическая конечная строка SAMPLE_ALIAS ;

a. ПРЕОБРАЗОВАНИЕ используется для настройки алгоритма, который будет использоваться для кодирования. b. iv известен как вектор инициализации, который представляет собой произвольное число, используемое вместе с секретным ключом для шифрования. (Он может храниться в общедоступном хранилище, таком как SharedPreference, Room DB или MySQL DB). c. SAMPLE_ALIAS используется для доступа к сущности, хранящейся внутри хранилища ключей.

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

a. Создайте объект класса Cryptor. b. Используйте метод set для инициализации шифрования с использованием секретного ключа в классе Crypto. c. Зашифруйте текст с помощью функции шифрования, определенной в классе Cryptor. d. Сохраните Iv и зашифрованный текст (Iv может быть общедоступным, и это не вызывает никаких проблем) в базе данных SharedPreference или Room.

В RegistrationActivity.java

Cryptor cryptor = new Cryptor();
try {
    cryptor.setIv();
    prefs.edit().putString("encryptedKey", cryptor.encryptText("text_to_be_encrypted")).apply();
    prefs.edit().putString("keyIv", cryptor.getIv_string()).apply();
    Intent intent = new Intent(RegistrationActivity.this, HomeScreen.class);
    startActivity(intent);
    finish();
} catch (NoSuchPaddingException e) {
    unexpectedError();
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    unexpectedError();
    e.printStackTrace();
} catch (NoSuchProviderException e) {
    unexpectedError();
    e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
    unexpectedError();
    e.printStackTrace();
} catch (InvalidKeyException e) {
    unexpectedError();
    e.printStackTrace();
}

В Cryptor.java , мы определяем следующие функции

1. метод set():

public void setIv() throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException {
    Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey_en());
    iv = cipher.getIV();
}

2. Метод getSecretKey_en():

@NonNull
private SecretKey getSecretKey_en() throws NoSuchAlgorithmException,
        NoSuchProviderException, InvalidAlgorithmParameterException {
    final KeyGenerator keyGenerator;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
        keyGenerator.init(new KeyGenParameterSpec.Builder(Cryptor.SAMPLE_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build());
        return keyGenerator.generateKey();
    } else {
        keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
        keyGenerator.init(new KeyGenParameterSpec.Builder(Cryptor.SAMPLE_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build());
        return keyGenerator.generateKey();
    }
}

3. Зашифрованный текст(строка string_to_encrypt):

public String encryptText(String string_to_encrypt) {
    try {
        final byte[] encryptedText = encryptData(string_to_encrypt);
        return Base64.encodeToString(encryptedText, Base64.DEFAULT);
    } catch (NoSuchAlgorithmException | NoSuchProviderException |
            NoSuchPaddingException | InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException |
            IllegalBlockSizeException | BadPaddingException e) {
        e.printStackTrace();
    }
    return "";
}

4. Encryptdata(Строка text_to_encrypt):

private byte[] encryptData(final String textToEncrypt)
        throws NoSuchAlgorithmException,
        NoSuchProviderException, NoSuchPaddingException, InvalidKeyException,
        InvalidAlgorithmParameterException, BadPaddingException,
        IllegalBlockSizeException {
    final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey_en());
    iv = cipher.getIV();
    return (cipher.doFinal(textToEncrypt.getBytes(StandardCharsets.UTF_8)));
}

5. getIv_string():

public String getIv_string() {
    return Base64.encodeToString(iv, Base64.DEFAULT);
}

Пояснение: Мы генерируем секретный ключ, используя хранилище ключей с определенными алгоритмами и ПСЕВДОНИМОМ. сгенерированный секретный ключ используется для инициализации шифрования и получения IV. Функция шифрования текста использует текст и iv для шифрования текста в хранилище ключей и выдает зашифрованный текст, который может быть сохранен на любом общем носителе данных.

Для расшифровки значения с помощью хранилища ключей мы можем сделать это с помощью: a. Создайте объект класса Cryptor. b. Инициализируйте экземпляр хранилища ключей. c. Используйте функцию расшифровки, передав зашифрованный текст и iv (сохраненный в базе данных SharedPreference или Room).

В В

String iv = prefs.getString("keyIv", "null");
String encrypted = prefs.getString("encryptedKey", "");
try {
    Cryptor cryptor = new Cryptor();
    cryptor.initKeyStore();
    String decrypted = cryptor.decryptText(encrypted, iv);
} catch (KeyStoreException e) {
    e.printStackTrace();
} catch (CertificateException e) {
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

В Cryptor.java , добавьте следующие функции

1.инициализировать хранилище ключей():

public void initKeyStore() throws KeyStoreException, CertificateException,
        NoSuchAlgorithmException, IOException {
    keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
    keyStore.load(null);
}

2. Расшифровываемый текст(Строка encrypted_string, Строка iv):

public String decryptText(String encrypted, String iv) {
    try {
        return decryptData(encrypted, Base64.decode(iv,Base64.DEFAULT));
    } catch (UnrecoverableEntryException | NoSuchAlgorithmException |
            KeyStoreException | NoSuchPaddingException | InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return "";
}

3. Расшифровать данные(Строка encrypted_string, байт[] Iv):

private String decryptData(String encrypted, final byte[] encryptionIv)
        throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
        NoSuchPaddingException, InvalidKeyException,
        BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
    final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv);
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey_de(), spec);
    byte[] encryptedData = Base64.decode(encrypted,Base64.DEFAULT);
    return new String(cipher.doFinal(encryptedData), StandardCharsets.UTF_8);
}

Пояснение: При расшифровке мы получаем сохраненный Iv и зашифрованный текст, хранящиеся на нашем одном из носителей данных. Мы инициализируем хранилище ключей с помощью ANDROID_KEY_STORE и расшифровываем текст с помощью Iv и методом init и doFinal Шифра.

Итак, благодаря вышеупомянутой реализации секреты теперь находятся в безопасности в хранилище ключей. Почему это, вероятно, лучший метод, заключается в том, что хранилище ключей очень специфично для приложения. Он не может быть извлечен, и, следовательно, текст не может быть расшифрован без него. Многие приложения, в которых хранятся кредитные карты и другие конфиденциальные данные пользователей, используют этот метод шифрования для обеспечения их безопасности. Для получения полного кода вы можете заглянуть в мой репозиторий GitHub. Объясняя код, я определил такие файлы, как — Cryptor.java , RegistrationActivity.java и HomeScreen.java . Я также использовал базу данных Room Database (запущенную Google в 2018 году), которая обеспечивает более высокий уровень безопасности, чем SQLLite (доступ к ней возможен, если устройство укоренено), для хранения имени пользователя и пароля для аутентификации зарегистрированных пользователей.

Я также использовал базу данных Room Database (запущенную Google в 2018 году), которая обеспечивает более высокий уровень безопасности, чем SQLLite (доступ к ней возможен, если устройство укоренено), для хранения имени пользователя и пароля для аутентификации зарегистрированных пользователей.

Оригинал: “https://dev.to/varundwarkani10/securing-secret-key-in-android-using-keystore-1kj6”