部分解密废话

Part of Decrypt non-sense

我正在 android 聊天,这里我使用下一个方法生成密钥、加密和解密消息。问题是,当我在另一端发送消息时,例如 "hola",我收到 "holgAAAAAAAAAAAAAAA"。你能帮忙解决这个问题吗?

private byte[] K;
public void setK(){
    KeyGenerator KeyGen=KeyGenerator.getInstance("AES");
    KeyGen.init(128);
    SecretKey key=KeyGen.generateKey();
    K = key.getEncoded();
}
public String encrypt(byte[] input){
    try {
        IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
        SecretKeySpec key = new SecretKeySpec(K, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
        int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
        ctLength += cipher.doFinal(cipherText, ctLength);
        return Base64.encodeToString(cipherText, Base64.DEFAULT);
    } catch (Exception e) {
        Log.e(JUAN, "failed to encrypt ", e);
    }
    return null;
}

public String decrypt(byte[] input){
    try {
        IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
        SecretKeySpec key = new SecretKeySpec(K, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] plainText = new byte[cipher.getOutputSize(input.length)];
        int ctLength = cipher.update(input, 0, input.length, plainText, 0);
        ctLength += cipher.doFinal(plainText, ctLength);
        return Base64.encodeToString(plainText, Base64.DEFAULT);
    } catch (Exception e) {
        Log.e(JUAN, "failed to decrypt ", e);
    }
    return null;
}

编辑 这是我的要求,例如加密 "Hola".

encrypt(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
decrypt(Base64.decode(ciphertext, Base64.DEFAULT));

假设您的 public String decrypt(byte[] input) 方法中的参数 input 已成功由调用方从密文中进行 Base64 解码(因为您的加密 returns Base64 编码密码字符串).但是,在 decrypt() 方法中,您通过 getOutputSize() 方法创建了一个 byte 数组 plainText。这使得 plainText 成为一个大小为 AES 块大小 (16) 倍数的数组。对于您的情况,plainText 是一个 16 byte 数组。因此,在解密并从密文中删除填充后,plainText 包含带有一些零的解密文本,然后将这些零编码为 AAA...As。 所以使用

return Base64.encodeToString(plainText, 0, ctLength, Base64.DEFAULT);

而不是

return Base64.encodeToString(plainText, Base64.DEFAULT);

注意:您使用的是ECB模式,所以您的IvParameterSpec没有用。请改用 CBC 模式。

版次:你的电话有问题。试试这个

//Encryption side
String text = "hola, hi, anything u want";
byte[] plainText = text.getBytes("UTF-8");
String base64 = encrypt(plainText);

// Decryption side
byte[] cipherText = Base64.decode(base64, Base64.DEFAULT);
String plainEncodedText = decrypt(cipherText);
byte[] plainTextAsByte = Base64.decode(plainEncodedText, Base64.DEFAULT);
String plainTextAgain = new String(plainTextAsByte , "UTF-8");

现在打印 plainTextAgain 并希望这会起作用!

您的代码存在多个问题:

  1. 你的解密函数输入输出类型颠倒了。如果你加密了一个byte[],你解密的时候应该会得到一个。如果您的密文是 Base64 String 那么解密方法应该采用这样的 String 而不是 byte[].

    String encrypt(byte[] plaintext) {
        ...
        return Base64.encodeToString(cipher.doFinal(plaintext), Base64.DEFAULT);
    }
    
    byte[] encrypt(String ciphertext) {
        ...
        return cipher.doFinal(Base64.decode(ciphertext.getBytes("UTF-8"), Base64.DEFAULT));
    }
    
  2. 您将单个明文和密文传递到它们各自的方法中,但随后使用 cipher.update() cipher.doFinal()。这是没有必要的。您应该使用没有先前缓冲区的单个 cipher.doFinal() 调用。加密示例:

    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherText = cipher.doFinal(plaintext);
    
  3. 因为 "Hola" 应该是用户输入的内容,所以从 Base 64 解码 没有任何意义。不是某人输入的所有字符串都是有效的 Base 64 编码,因此可以对其进行解码。您根本不应该解码输入,而是将其直接传递给 encrypt() 函数。

  4. 使用String#getBytes()是不安全的,因为它使用了系统默认的Charset。当在接收系统上使用不同的默认字符集时,解密可能不会成功。自己指定Charset,解密后从byte[]中获取String:

    String ciphertext = encrypt(plaintext.getBytes("UTF-8"));
    String recoveredPlaintext = new String(decrypt(ciphertext), "UTF-8");
    
  5. 您没有使用静态 IV。


安全问题:

  1. 您正在使用 ECB 模式。不要这样做!它在语义上不安全。至少使用带有随机 IV 的 CBC 模式。 IV 不必隐藏,因此您可以简单地将其添加到密文中。
  2. 您没有验证密文。您的系统可能容易受到 padding oracle 攻击。您应该使用像 HMAC-SHA256 这样具有强 MAC 的加密然后 MAC 方法,或者使用像 GCM 或 EAX 这样的 AES 认证操作模式。

使用例如 this library by Isaac Potoczny-Jones 与 Android 兼容。它支持具有随机 IV 和 HMAC-SHA256.

的密文身份验证的 AES-CBC