Java AES CBC 解密

8

PHP加密函数

$privateKey = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv);

echo(base64_encode($encrypted));

Result: iz1qFlQJfs6Ycp+gcc2z4w==

当我尝试使用下面的函数在Java中解密此结果时,我只得到了ì�š@ÔBKxnfÈ~¯Ô'M,而我期望得到"Test string"。您有什么想法错在哪里吗?谢谢。
public static String decrypt() throws Exception{
    try{
        String Base64EncodedText = "iz1qFlQJfs6Ycp+gcc2z4w==";
        String decodedText = com.sun.xml.internal.messaging.saaj.util.Base64.base64Decode(Base64EncodedText);
        String key = "1234567812345678";
        String iv = "1234567812345678";

        javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key.getBytes(), "AES");
        javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv.getBytes());

        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, keyspec, ivspec);
        byte[] decrypted = cipher.doFinal(decodedText.getBytes());

        String str = new String(decrypted);

        return str;

    }catch(Exception e){
        return null;
    }   
}

可能是[PHP Java AES CBC加密结果不同]的重复问题(http://stackoverflow.com/questions/10842509/php-java-aes-cbc-encryption-different-results)。 - Maarten Bodewes
1个回答

18

编辑:从Java 8开始,Java现在包括一个可以接受的Base64类,java.util.Base64


这行文字

String decodedText = com.sun.xml.internal.messaging.saaj.util.Base64.base64Decode(Base64EncodedText);

看起来不对。相反,使用Apache Commons Codec类或Harder base64类。另外,mcrypt使用的默认填充方式--零填充,在其他语言中使用结果会变得困难。在mcrypt_encrypt网页的用户评论部分中有如何解决这个问题的示例。

这是一个使用Apache Commons类解密字符串的小示例。

import java.nio.charset.Charset;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

public class AESToy3 {

    private static final Charset ASCII = Charset.forName("US-ASCII");

    public static void main(String[] args) throws Exception {
        String base64Cipher = "iz1qFlQJfs6Ycp+gcc2z4w==";
        byte [] cipherBytes = Base64.decodeBase64(base64Cipher);
        byte [] iv = "1234567812345678".getBytes(ASCII);
        byte [] keyBytes = "1234567812345678".getBytes(ASCII);

        SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
        cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));

        byte[] result = cipher.doFinal(cipherBytes);
        System.out.println(Hex.encodeHexString(result));
    }

}

这将产生以下输出:

5465737420737472696e670000000000

将其解码为ASCII并删除尾随的零后得到Test string


在关闭之前,请先投票支持一下 :) - Maarten Bodewes
非常感谢GregS,解释得非常好。 - user812120
谢谢。但是密钥和初始化向量是不同的东西 - 克隆它们只会让读者感到困惑。 - Pavel Vlasov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接