使用Keystore保护Android中的秘密密钥

在某个时间点,我们所有人都希望确保我们的数据不受黑客入侵/反向工程的影响。 基本的安全机制如下:

a. ProGuard, ShrinkResources & minifyEnabled b。 隐藏在清单中 C。 隐藏在Build.Gradle中 d。 在MySQL DB / Room DB / SharedPreference中存储 e。 隐藏在Strings.xml中。

All these methods fail to provide maximum security. The most common and known logic of securing the key can be bypassed either by reversing and taking it from dex->jar file or by rooting the device and accessing the device storage. 但是,还有另一种方法可以击败所有人。 应用程序通常使用该机制来存储非常敏感的数据,例如信用卡详细信息,银行帐户等。

密钥库与硬件安全性绑定,后者通常用于存储加密密钥。 由于密钥库对于每个应用程序都是非常特定的,因此黑客很难访问它。 完成更多介绍后,让我们现在跳至代码-

声明一些变量Cryptor.java

私有静态最终字符串转型=“ AES / GCM / NoPadding”; 私有静态最终字符串ANDROID_KEY_STORE=“ AndroidKeyStore”; 专用字节[]iv; 私人密钥库密钥库; 私有静态最终字符串SAMPLE_ALIAS=“ MYALIAS”;

一种。 TRANSFORMATION用于设置将用于编码的算法。 b。 iv被称为初始化向量,它是与加密密钥一起使用的任意数字。 (它可以存储在公共存储中,例如SharedPreference,Room DB或MySQL DB)。 C。 SAMPLE_ALIAS用于​​访问存储在密钥库中的实体。

ENCRYPTING DATA

为了使用Keystore加密值,我们可以通过以下方式实现:

一种。 创建一个Cryptor类的对象。 b。 使用setIv方法使用Cryptor类中的秘密密钥来初始化密码。 C。 使用Cryptor类中定义的加密功能对文本进行加密。 d。 将IV和加密的文本(IV可以公开并且不会引起任何问题)存储在SharedPreference或Room Database中。

在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. setIv()方法:

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. cryptoText(String 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. cryptoData(String 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);
}

说明:我们使用带有特定算法和ALIAS的keyStore生成一个秘密密钥。 生成的密钥用于初始化密码并获得IV。 加密文本功能使用文本和iv对密钥库中的文本进行加密,并提供可以存储在任何常规存储介质中的加密文本。

DECRYPTING DATA

要使用Keystore解密值,我们可以通过以下方式实现: 一种。 创建一个Cryptor类的对象。 b。 初始化KeyStore实例。 C。 通过传递加密的文本和iv(存储在SharedPreference或Room Database中)来使用解密功能。

在HomeScreen.java

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.initKeyStore():

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

2.cryptoText(字符串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,字节[]四):

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以及Cipher的init和doFinal方法解密文本。

CONCLUSION:

因此,通过上述实现,密钥库中的秘密现在是安全的。 为什么它可能是最好的方法,是因为KeyStore特定于应用程序。 无法检索它,因此没有它就无法解密文本。 许多存储用户信用卡和其他敏感数据的应用程序都使用这种加密方法来确保安全。 对于整个代码,您可以查看我的GitHub存储库。 在解释代码时,我定义了诸如Cryptor.java,RegistrationActivity.java和HomeScreen.java之类的文件。 我还使用了Room Database(由Google在I / O 2018中推出)来提供比SQLLite(如果设备已植根则可以访问)更高级别的安全性来存储用户名和密码来验证注册用户。

Https://github.com/varundwarkani/KeystoreEncryption-Android

from: https://dev.to//varundwarkani10/securing-secret-key-in-android-using-keystore-1kj6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值