javax.crypto.IllegalBlockSizeException:解密中的最后一个块未完成

javax.crypto.IllegalBlockSizeException:解密中的最后一个块未完成,java,android,encryption,cryptography,aes,Java,Android,Encryption,Cryptography,Aes,我正在从事一个android项目,在这个项目中,我必须在PHP服务器中解密文件中的字符串,加密是使用PHP完成的。(AES 128算法) 加密代码: function aes128Encrypt($key, $data) { $key = md5($key); return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16)); } 从UR

我正在从事一个android项目,在这个项目中,我必须在PHP服务器中解密文件中的字符串,加密是使用PHP完成的。(AES 128算法)

加密代码:

 function aes128Encrypt($key, $data) {
      $key = md5($key);
      return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16));
    }
从URL获取字符串的我的代码:

String myUri = "http://www.example.com/lib2.php";
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(myUri);

HttpResponse response = httpClient.execute(get);

String bodyHtml = "";
String xmlFile = "";
bodyHtml = EntityUtils.toString(response.getEntity());
System.out.println(bodyHtml);
xmlFile = decrypt(bodyHtml);
System.out.println(xmlFile);
decrypt()方法:

在generateKey()中:

Logcat显示以下异常:

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
在第
c.doFinal()行


我注释掉的代码也是我用来检查的代码。这个代码怎么了?。任何帮助都将不胜感激。

您的芯片制造商期望填充“/CBC/PKCS7Padding”。这与消息的编码(BASE64)无关。要么在java端更改预期的chipher,要么在php端使用填充进行加密

芯片是指定的
算法/模式/填充
算法
,有关详细信息,请参阅

您正在指定带填充的Chipper,但实际上在php端执行零填充

摘录自:


问题可能在于如何将来自PHP服务器的值作为Java
字符串处理。PHP
mcrypt\u encrypt
函数返回一个二进制字符串,其中每个字节可以有任何值。PHP
mcrypt\u encrypt
不使用任何字符编码。因此,使用
EntityUtils.toString()
已经是一个错误,而使用
String.getBytes()
而不指定编码通常也是一个错误


您只需要使用或来获取二进制密文的密码。如果你选择第一个选项,你可以在它周围绕一圈。使用
“AES/CBC/NoPadding”
密码初始化它,您可以直接解密纯文本字符串。请注意,您可能需要从结果中删除一定数量的
00
值字节,以获得纯文本。

我通过避免重复使用密码解决了我的问题。每次我都会再次初始化它。仅仅初始化就足够了

 try {
            SecretKeyFactory factory = SecretKeyFactory
                    .getInstance(SECRET_KEY_ALGORITHM);
            KeySpec spec = new PBEKeySpec(ps, salt, ITERATIONS, KEY_LENGTH);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);

            // Build encryptor and get IV
            ecipher = Cipher.getInstance(TRANSFORMATION);
            ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));

            // Build decryptor
            dcipher = Cipher.getInstance(TRANSFORMATION);
            dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        } catch (Exception e) {
            e.printStackTrace();
        }

我不能在PHP方面更改任何东西,我应该在java代码中更改什么,填充?由于我使用了相同的AES算法,所以在PHP中使用了CBC模式。请尝试使用“AES/CBC/NoPadding”谢谢。我尝试使用NoPadding,但它给出了
javax.crypto.IllegalBlockSizeException:错误:060606508A:数字信封例程:EVP\u DecryptFinal\u ex:数据不是块长度的倍数
。这意味着与读取的数据有关吗?@NitinMisra是的,请检查我已接受的答案。请不要使用
MD5
进行键强化。如果密钥已经具有很强的加密能力,那么用md5对其进行哈希运算几乎是在浪费处理器周期。如果密钥加密不强,请使用适当的算法,如
Scrypt
Bcrypt
PBKDF#2
,以便于密钥增强。@CPUTerminator当然,但这不会解决此问题,对吗?而且我没有权限更改PHP中的任何代码。那么有什么办法解决这个问题吗?不,它解决不了你的问题。但是由Max Power发布的解决方案将。如果未指定填充机制,则默认情况下,如果消息不是块大小的倍数,php将消息填充为\0(我认为)。因此,使用AES/CBC/NoPadding应该会生成正确的消息,但可能会在末尾有额外的空格。由于消息已由php预先填充到适当的大小。我应该如何修剪并获得准确的字符串?我现在得到的消息就像一个已损坏的字符串。已损坏的明文表示加密/解密或编码/解码之间仍然存在不匹配。请注意,在没有填充的情况下,只有当流不包含完整数量的块时,解密才会失败。如果密钥或密文被更改,它只会返回垃圾。。。如图所示,仅需要对结尾处的
00
字节进行修剪。但明文未完全损坏加密前的文本是相同的,但其顺序不正确,从文本结尾处开始打印,然后从开头再次打印。I'v的用法如下
byte[]encData=新字节[1600];字符串add=“”
while((dummy=cis.read(encData))!=-1{System.out.println(新字符串(encData,“UTF-8”).trim());add=add+(新字符串(encData,“UTF-8”).trim();}
我不能将整个纯文本存储到一个字符串中,它只存储一部分。看看这个:@KarthikSivam看起来你已经回答了你的问题。顺便说一下,不需要修剪()每个字符串,您只需要删除(或:不解码)整个解密明文的最后一个值为
00
的字节。为每个块调用
trim()
,将删除明文中的空白(包括空格等)。
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
# creates a cipher text compatible with AES (Rijndael block size = 128)
# to keep the text confidential 
# only suitable for encoded input that never ends with value 00h
# (because of default zero padding)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                             $plaintext, MCRYPT_MODE_CBC, $iv);
 try {
            SecretKeyFactory factory = SecretKeyFactory
                    .getInstance(SECRET_KEY_ALGORITHM);
            KeySpec spec = new PBEKeySpec(ps, salt, ITERATIONS, KEY_LENGTH);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);

            // Build encryptor and get IV
            ecipher = Cipher.getInstance(TRANSFORMATION);
            ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));

            // Build decryptor
            dcipher = Cipher.getInstance(TRANSFORMATION);
            dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        } catch (Exception e) {
            e.printStackTrace();
        }