java - 部分解密废话

标签 java android encryption aes

我在 android 中进行聊天,这里我使用下一个方法生成 key 、加密和解密消息。问题是,当我在另一端发送消息(例如“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));

最佳答案

您的代码存在多个问题:

  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,解密后从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 攻击。您应该使用具有强 MAC(如 HMAC-SHA256)的先加密后 MAC 方法,或者使用经过身份验证的 AES 操作模式(如 GCM 或 EAX)。

使用例如this library通过 Isaac Potoczny-Jones其中与 Android 兼容。它支持具有随机 IV 和 HMAC-SHA256 密文身份验证的 AES-CBC。

关于java - 部分解密废话,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30447979/

相关文章:

java - 非法参数异常 : the error message does not make sense

java - 是否可以在 Java 中使用类似结构的构造?

java - 使用 XPath 解析损坏的 HTML 站点

android - 我可以将 Android 支持库从 27.1.1 更新到 AndroidX 1.0.0 吗?

c - 实现 openssl evp 加密

java - 像encodeAsBase64方法一样,Grails提供加密/解密方法吗?

java - VERP 与 JavaMail 和 Postfix,如何操作?

android - 制作静态背景图片

Android LinearLayout 选择器背景色

java - 如何创建随机 AES 128 PrivateKey 和 IV 作为字符串?