当前位置: 首页 > 面试题库 >

PHP Java AES CBC加密不同的结果

齐成和
2023-03-14
问题内容

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


问题答案:

如果您不只是简单地Exceptionencrypt()例程中的可能内容吞噬掉,那么您将对发生的事情有了更好的了解。如果函数正在返回,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_encrypt函数的实际作用。由于它有效,因此显然使用了一些填充方案。您需要找出它是哪一个,并在Java代码中使用它。

好的-我查找了手册页mcrypt_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日) :从Java 8开始,JavaSE最终随附了已记录的base64编解码器。所以代替

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

你应该做类似的事情

return Base64.Encoder.encodeToString(encrypted);

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



 类似资料:
  • 我正在加密字符串“AAAAAAAAAAAAAAAAAAAAAAAA”(一个16字节的UTF8字符串)使用AES 128 CBC与空白iv和密钥(16 0),并得到不同的结果 在PHP中: 第一位(粗体)与PHP相同,但PHP值有一个额外的“a=”,然后节点值有一个额外的“heuidae8z4dk0hu7p2z+1c” 我承认我对这里发生的事情很不确定--我错过了什么? 编辑...但不是那么不稳定,

  • 我已经尝试使用cipher.getinstance(“rsa/ecb/pkcs1padding”),但没有给出预期的结果。 感谢所有的帮助。祝你有美好的一天。

  • 我工作在AES256能够加密/解密之间的iOS和PHP使用不安全的渠道。 我见过许多类似的问题,围绕着密钥大小、模式(CBC或ECB)、随机iv的使用等。但是在这种情况下,我发现了以下奇怪的行为。 两种环境中的配置:-键:32字节(256位)-块大小:128位(标准)-iv:16字节(用于测试的静态)-模式:CBC 如果我加密一个16或32字节的文本(以匹配AES块大小),Swift和PHP中的结

  • 我有相同的数据和加密密钥,相同的算法,相同的模式,但不同的结果。 C#代码: 结果:13A6DAD3119F29A8C4BF6D5BD11564E4E1A93F85B7F2AD9E8E97756688754DE32A23ADE41DFD9F76186D8E25E66D0DCF458ECAA026F16463811C48FC814E50B10FF57FDDB0C0761088D1AC4DDDAE74

  • 我有一个 API,要求我对通过 AES 密码发送给它的数据进行编码。 但是,我得到的唯一示例代码是 Node.js 代码。 我想,用PHP重新实现它有多难? 显然很难。 下面您可以看到这两种方法,但您也可以看到不同的结果。 有人知道哪里出了问题吗? 结果:3522ca23 结果:8faa39d2

  • 我正在尝试使用 Rijndael 从 php 到 Delphi 再返回加密/解密字符串。 如果我从Delphi解密PHP字符串…工作正常。 如果我使用 Delphi 加密字符串,结果字符串还可以,但更短 为了测试,我使用了一个62个字符的字符串。带有delphi的加密字符串比PHP少4个字符 这些是琴弦...最后的字符: PHP: GyLWj1anBJRmE8mBsaO5cvTrcbvvA== D