【问题标题】:Android String Encryption/DecryptionAndroid 字符串加密/解密
【发布时间】:2019-06-02 23:55:02
【问题描述】:

我想使用AndroidKeyStoreEditText 加密和解密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));

【问题讨论】:

    标签: java android encryption android-keystore


    【解决方案1】:

    此行有误:

    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);
    

    【讨论】:

      【解决方案2】:
      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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-27
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 2012-07-01
        • 2018-08-26
        • 1970-01-01
        相关资源
        最近更新 更多