PHP Java AES CBC加密不同的结果 [英] PHP Java AES CBC Encryption Different Results

查看:196
本文介绍了PHP Java AES CBC加密不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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功能


Java Function

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相同的结果吗?非常感谢。

Please note that we are not allowed to change the PHP code. Could somebody please help us get the same results in Java? Many thanks.

推荐答案

如果你不是简单地吞咽,你会有更好的了解发生了什么您的 encrypt()例程中的异常如果您的函数返回 null ,那么显然有一个异常发生,您需要知道是什么。

You'd have had a better idea of what was going on if you didn't simply swallow up possible Exceptions inside your encrypt() routine. If your function is returning null then clearly an exception happened and you need to know what it was.

事实上,例外情况是:

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个字节。

And sure enough, your plaintext is only 11 Java characters long which, in your default encoding, will be 11 bytes.

您需要检查PHP mcrypt_encrypt 功能实际上是什么。由于它的工作原理,它显然是使用一些填充方案。你需要找出它是哪一个,并在你的Java代码中使用它。

You need to check what the PHP mcrypt_encrypt function actually does. Since it works, it is clearly using some padding scheme. You need to find out which one it is and use it in your Java code.

Ok - 我查找了 mcrypt_encrypt 。它说:

Ok -- I looked up the man page for mcrypt_encrypt. It says:


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

The data that will be encrypted with the given cipher and mode. If the size of the data is not n * blocksize, the data will be padded with \0.

所以你需要在Java中复制它。这是一种方法:

So you need to replicate that in Java. Here's one way:

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程序所得到的。

which is what your PHP program got.

更新2016年6月)
从Java 8开始,JavaSE终于提供了一个记录的base64编解码器。所以代替

Update (12 June 2016): As of Java 8, JavaSE finally ships with a documented base64 codec. So instead of

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

你应该做一些像

return Base64.Encoder.encodeToString(encrypted);

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

Alternatively, use a 3rd-party library (such as commons-codec) for base64 encoding/decoding rather than using an undocumented internal method.

这篇关于PHP Java AES CBC加密不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆