Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/253.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP Java AES CBC加密不同的结果_Java_Php_Encryption_Aes - Fatal编程技术网

PHP Java AES CBC加密不同的结果

PHP Java AES CBC加密不同的结果,java,php,encryption,aes,Java,Php,Encryption,Aes,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==

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函数

public static String encrypt() throws Exception{
try{
    String data = "Test string";
    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.ENCRYPT_MODE, keyspec, ivspec);
    byte[] encrypted = cipher.doFinal(data.getBytes());

    return new sun.misc.BASE64Encoder().encode(encrypted);

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

返回null


请注意,我们不允许更改PHP代码。有人能帮我们在Java中得到同样的结果吗?非常感谢。

如果您不简单地在
encrypt()
例程中吞下可能出现的
异常,您会对发生的情况有更好的了解。如果您的函数返回
null
,那么显然发生了异常,您需要知道它是什么

事实上,例外情况是:

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at Encryption.encrypt(Encryption.java:20)
    at Encryption.main(Encryption.java:6)
果然,您的纯文本只有11个Java字符长,在您的默认编码中,将是11字节

您需要检查PHP
mcrypt\u encrypt
函数的实际功能。因为它可以工作,所以它显然使用了一些填充方案。您需要找出它是哪一个,并在Java代码中使用它

好的--我在手册页上查找了
mcrypt\u encrypt
。它说:

将使用给定的密码和模式加密的数据。如果数据大小不是
n*blocksize
,则数据将填充
\0

所以您需要在Java中复制它。这里有一个方法:

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

public class Encryption
{
    public static void main(String args[]) throws Exception {
        System.out.println(encrypt());
    }

    public static String encrypt() throws Exception {
        try {
            String data = "Test string";
            String key = "1234567812345678";
            String iv = "1234567812345678";

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();

            // We need to pad with zeros to a multiple of the cipher block size,
            // so first figure out what the size of the plaintext needs to be.
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            int remainder = plaintextLength % blockSize;
            if (remainder != 0) {
                plaintextLength += (blockSize - remainder);
            }

            // In java, primitive arrays of integer types have all elements
            // initialized to zero, so no need to explicitly zero any part of
            // the array.
            byte[] plaintext = new byte[plaintextLength];

            // Copy our actual data into the beginning of the array.  The
            // rest of the array is implicitly zero-filled, as desired.
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

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

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return new sun.misc.BASE64Encoder().encode(encrypted);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
当我跑步时,我得到:

iz1qFlQJfs6Ycp+gcc2z4w==
这就是你的PHP程序得到的


更新(2016年6月12日): 从Java8开始,JavaSE最终附带了一个有文档记录的base64编解码器。所以不是

return new sun.misc.BASE64Encoder().encode(encrypted);
你应该这样做

return Base64.Encoder.encodeToString(encrypted);

或者,使用第三方库(例如
commons codec
)进行base64编码/解码,而不是使用未记录的内部方法。

如果不简单地将
encrypt()
例程中可能出现的
异常
吞掉,您会对发生的情况有更好的了解。如果您的函数返回
null
,那么显然发生了异常,您需要知道它是什么

事实上,例外情况是:

javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at Encryption.encrypt(Encryption.java:20)
    at Encryption.main(Encryption.java:6)
果然,您的纯文本只有11个Java字符长,在您的默认编码中,将是11字节

您需要检查PHP
mcrypt\u encrypt
函数的实际功能。因为它可以工作,所以它显然使用了一些填充方案。您需要找出它是哪一个,并在Java代码中使用它

好的--我在手册页上查找了
mcrypt\u encrypt
。它说:

将使用给定的密码和模式加密的数据。如果数据大小不是
n*blocksize
,则数据将填充
\0

所以您需要在Java中复制它。这里有一个方法:

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

public class Encryption
{
    public static void main(String args[]) throws Exception {
        System.out.println(encrypt());
    }

    public static String encrypt() throws Exception {
        try {
            String data = "Test string";
            String key = "1234567812345678";
            String iv = "1234567812345678";

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();

            // We need to pad with zeros to a multiple of the cipher block size,
            // so first figure out what the size of the plaintext needs to be.
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            int remainder = plaintextLength % blockSize;
            if (remainder != 0) {
                plaintextLength += (blockSize - remainder);
            }

            // In java, primitive arrays of integer types have all elements
            // initialized to zero, so no need to explicitly zero any part of
            // the array.
            byte[] plaintext = new byte[plaintextLength];

            // Copy our actual data into the beginning of the array.  The
            // rest of the array is implicitly zero-filled, as desired.
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

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

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return new sun.misc.BASE64Encoder().encode(encrypted);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
当我跑步时,我得到:

iz1qFlQJfs6Ycp+gcc2z4w==
这就是你的PHP程序得到的


更新(2016年6月12日): 从Java8开始,JavaSE最终附带了一个有文档记录的base64编解码器。所以不是

return new sun.misc.BASE64Encoder().encode(encrypted);
你应该这样做

return Base64.Encoder.encodeToString(encrypted);

或者,使用第三方库(如
commons codec
)进行base64编码/解码,而不是使用未记录的内部方法。

非常感谢,QuantumMechanical。解释得很好。请注意,通常不使用基于零的填充,因为您无法区分数据末尾的零值字节和填充。您应该改用PKCS#7填充(
“PKCS5Padding”
在Java中)。还要注意,使用sun.*功能无法满足所有Java兼容性准则。非常感谢,QuantumMechanical。解释得很好。请注意,通常不使用基于零的填充,因为您无法区分数据末尾的零值字节和填充。您应该改用PKCS#7填充(
“PKCS5Padding”
在Java中)。还要注意,使用sun.*功能无法满足所有Java兼容性准则。