Android 字符串 Encryption/Decryption
Android String Encryption/Decryption
我想使用 AndroidKeyStore
从 EditText
加密和解密 String
。我的问题是在解密过程中得到 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));
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;
}
这一行有误:
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 或十六进制。要解密字符串,您必须先将其解码为字节,然后再解密。
示例:
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);
我想使用 AndroidKeyStore
从 EditText
加密和解密 String
。我的问题是在解密过程中得到 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));
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;
}
这一行有误:
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 或十六进制。要解密字符串,您必须先将其解码为字节,然后再解密。
示例:
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);