Android字符串加密/解密

时间:2019-06-02 23:55:02

标签: java android encryption android-keystore

我想使用StringEditText加密和解密AndroidKeyStore。我的问题是,在解密过程中会得到一个BadPaddingException

密钥生成器代码:

        KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");

        KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT).
                setBlockModes(KeyProperties.BLOCK_MODE_GCM).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE).build();

        keyGenerator.init(keyGenParameterSpec);
        keyGenerator.generateKey();

加密代码:

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

            KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ALIAS, null);
            SecretKey secretKey = secretKeyEntry.getSecretKey();

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            cipherIV = cipher.getIV();

            plainText.setText(new String(cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));

解密代码:

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

            final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ALIAS, null);
            final SecretKey secretKey = secretKeyEntry.getSecretKey();

            final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            final GCMParameterSpec spec = new GCMParameterSpec(128, cipherIV);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);

            byte[] decrypted = cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8));
            plainText.setText(new String(decrypted, StandardCharsets.UTF_8));

2 个答案:

答案 0 :(得分:0)

byte[] decrypted = cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8));

由于调用getBytes(StandardCharsets.UTF_8),此行可能无法正常工作。如果您的EditText是十六进制表示,请尝试将其转换为字符串,然后调用getBytes()。例如。

public static byte[] convertHexStringToByteArray(String hexString) {

    int l = hexString.length();
    byte[] data = new byte[l/2];
    for (int i = 0; i < l; i += 2) {
        data[i/2] = (byte)((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i+1), 16));
    }

    return data;
}

答案 1 :(得分:0)

此行有误:

plainText.setText(new String(cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));

如果我们将其拆开,就会有类似的东西

byte [] cipherBytes = cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8));
plainText.setText(new String(cipherBytes, StandardCharsets.UTF_8);

问题在于cipherBytes是一个任意字节序列,而不是字符串字符。 String构造函数将以其他方式静默替换无效字符,此过程会破坏数据。

如果要显示密码字节或以其他方式将其发送到面向字符的通道,则必须对其进行编码。通常,编码为base64或hex。要解密该字符串,必须先将其解码为字节,然后再解密。

示例:

byte [] cipherBytes = cipher.doFinal(plainText.getText().toString().getBytes(StandardCharsets.UTF_8));
plainText.setText(Base64.encodeToString(cipherBytes, Base64.DEFAULT));

然后解密:

byte[] cipherBytes = Base64.decode(plainText.getText().toString(), Base64.DEFAULT);
byte[] decrypted = cipher.doFinal(cipherBytes);