Java 部分解密无意义

Java 部分解密无意义,java,android,encryption,aes,Java,Android,Encryption,Aes,我在安卓上聊天,这里我使用下一种方法生成密钥,加密和解密消息。问题是,当我在另一边发送一条消息时,例如hola,我得到Holgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa。你能帮我修一下吗 private byte[] K; public void setK(){ KeyGenerator Key

我在安卓上聊天,这里我使用下一种方法生成密钥,加密和解密消息。问题是,当我在另一边发送一条消息时,例如hola,我得到Holgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa。你能帮我修一下吗

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

假设调用方成功地从密码文本中对公共字符串decryptbyte[]输入方法中输入的参数Base64进行解码,因为加密返回Base64编码的密码字符串,则代码正常。但是,在decrypt方法中,您是通过方法创建一个字节数组明文。这使得明文成为AES块大小16倍的数组。对于您的情况,明文是一个16字节的数组。因此,在解密并移除密文中的填充后,明文包含解密文本中的一些零,这些零随后被编码到AAA…As。 所以使用

而不是

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

现在再次打印明文,希望这能奏效

如果调用方成功地从密码文本中对公共字符串decryptbyte[]输入方法中输入的参数Base64进行解码,则代码正常,因为加密返回Base64编码的密码字符串。但是,在decrypt方法中,您是通过方法创建一个字节数组明文。这使得明文成为AES块大小16倍的数组。对于您的情况,明文是一个16字节的数组。因此,在解密并移除密文中的填充后,明文包含解密文本中的一些零,这些零随后被编码到AAA…As。 所以使用

而不是

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

现在再次打印明文,希望这能奏效

您的代码存在多个问题:

解密函数的输入和输出类型是相反的。如果加密一个字节[],则在解密它时应取出一个。如果您的密文是Base64字符串,那么解密方法应该采用这样的字符串,而不是字节[]

您正在将单个明文和密文传递到各自的方法中,但随后使用cipher.update和cipher.doFinal。这是没有必要的。您应该使用单个cipher.doFinal调用,而不使用以前的缓冲区。加密示例:

cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plaintext);
由于Hola应该是用户输入的内容,因此从Base 64解码没有任何意义。并非有人键入的所有字符串都是有效的base64编码,以便对其进行解码。您不应该对输入进行解码,而是直接将其传递到encrypt函数中

使用StringgetBytes是不安全的,因为它使用系统的默认字符集。在接收系统上使用不同的默认字符集时,解密可能不会成功。您应该自己指定字符集,并在解密后从字节[]获取字符串:

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

安全问题:

您正在使用ECB模式。别这样!它在语义上不安全。对随机IV至少使用CBC模式。IV不必隐藏,因此您可以简单地将其前置到密文。 你不是在验证密文。您的系统可能容易受到oracle攻击。您应该对强MAC(如HMAC-SHA256)使用先加密后MAC的方法,或者对AES(如GCM或EAX)使用经过身份验证的操作模式。
例如,使用与Android兼容的。它支持使用HMAC-SHA256进行随机IV和密文身份验证的AES-CBC。

您的代码存在多个问题:

解密函数的输入和输出类型是相反的。如果加密一个字节[],则在解密它时应取出一个。如果您的密文是Base64字符串,那么解密方法应该采用这样的字符串,而不是字节[]

您正在将单个明文和密文传递到各自的方法中,但随后使用cipher.update和cipher.doFinal。这是没有必要的。您应该使用单个cipher.doFinal调用,而不使用以前的缓冲区。加密示例:

cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plaintext);
由于Hola应该是用户输入的内容,因此从Base 64解码没有任何意义。并非有人键入的所有字符串都是有效的base64编码,以便对其进行解码。您不应该对输入进行解码,而是直接将其传递到encrypt函数中

使用StringgetBytes是不安全的,因为它使用系统的默认字符集。在接收系统上使用不同的默认字符集时,解密可能不会成功。您应该自己指定字符集,并在解密后从字节[]获取字符串:

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

安全问题:

您正在使用ECB模式。别生气 哦,这个!它在语义上不安全。对随机IV至少使用CBC模式。IV不必隐藏,因此您可以简单地将其前置到密文。 你不是在验证密文。您的系统可能容易受到oracle攻击。您应该对强MAC(如HMAC-SHA256)使用先加密后MAC的方法,或者对AES(如GCM或EAX)使用经过身份验证的操作模式。

例如,使用与Android兼容的。它支持AES-CBC和HMAC-SHA256的随机IV和密文身份验证。

@ArtjomB。根据OP的代码成功删除填充。OP输出纯文本时出错。@ArtjomB。根据OP的代码成功删除填充。OP在输出纯文本时出错。你部分是对的,但还有其他原因,因为在解密过程中,密文从未被Base64解码。此外,编码hola应该产生aG9sYQ==。。。不是霍尔格…@ArtjomB。decryptbyte[]输入方法将参数输入作为字节数组。所以我假设调用者负责正确的解码。我更新了我的答案。ty.@rakeb.void当我试图发送hi时,我在另一边得到hg==@Juan。调用方如何调用加密和解密方法?你能发布你的呼叫者代码吗?这是个问题,但不是问题所在。在解密过程中,您应该使用ctLength来确定输出大小,这是正确的。getOutputSize仅估计解密后的输出大小;来自JavaDoc:下一次更新或doFinal调用的实际输出长度可能小于此方法返回的长度。您部分是对的,但还有一些其他原因,因为在解密过程中,密文从未被Base64解码。此外,编码hola应该产生aG9sYQ==。。。不是霍尔格…@ArtjomB。decryptbyte[]输入方法将参数输入作为字节数组。所以我假设调用者负责正确的解码。我更新了我的答案。ty.@rakeb.void当我试图发送hi时,我在另一边得到hg==@Juan。调用方如何调用加密和解密方法?你能发布你的呼叫者代码吗?这是个问题,但不是问题所在。在解密过程中,您应该使用ctLength来确定输出大小,这是正确的。getOutputSize仅估计解密后的输出大小;来自JavaDoc:下一次更新或doFinal调用的实际输出长度可能小于此方法返回的长度。根据第一点,加密和解密如下encryptBase64.decodemessageText.getBytes,Base64.DEFAULT;并解密Base64.decodemessage.getBody,Base64.DEFAULT;如果Hola应该是您想要加密的人类可读字符串,那么从Base64解码它就没有任何意义,因为它不是。并非所有人类可读文本都是有效的Base64编码。什么是可读人类编码,我如何更改代码以实现人类可读?据我所知,您希望加密某人编写的文本消息。这些应该是加密函数的直接输入,而不是其解码版本。根据第一点,加密和解密按照encryptBase64.decodemessageText.getBytes,Base64.DEFAULT进行;并解密Base64.decodemessage.getBody,Base64.DEFAULT;如果Hola应该是您想要加密的人类可读字符串,那么从Base64解码它就没有任何意义,因为它不是。并非所有人类可读文本都是有效的Base64编码。什么是可读人类编码,我如何更改代码以实现人类可读?据我所知,您希望加密某人编写的文本消息。这些应该是加密函数的直接输入,而不是其解码版本。