【问题标题】:AES-256 CBC encrypt in php and decrypt in Java or vice-versaAES-256 CBC 在 php 中加密并在 Java 中解密,反之亦然
【发布时间】:2017-07-12 19:25:27
【问题描述】:

JAVA

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

class AES256JavaPhp{
        public static void main(String[] args) throws Exception {
                Base64 base64 = new Base64();
                Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
                SecretKeySpec key = new
                          SecretKeySpec("PasswordPassword".getBytes("UTF-8"),"AES");
                IvParameterSpec iv = new IvParameterSpec
                      ("dynamic@dynamic@".getBytes("UTF-8"),0,ciper.getBlockSize());
            //Encrypt
                ciper.init(Cipher.ENCRYPT_MODE, key,iv);
                byte[] encryptedCiperBytes = base64.encode
                                              ((ciper.doFinal("Hello".getBytes())));
                System.out.println("Ciper : "+new String(encryptedCiperBytes));
            //Decrypt
                ciper.init(Cipher.DECRYPT_MODE, key,iv);    
                byte[] text = ciper.doFinal(base64.decode(encryptedCiperBytes));
                System.out.println("Decrypt text : "+new String(text));
          }
    }

Java 输出:

Ciper : KpgzpzCRU7mTKZePpPlEvA==
Decrypt text : Hello

PHP

<?php>    
        $cipherText = encrypt("Hello", 'aes-256-cbc');
        exit();

        function encrypt($data, $algo)
        {
            $key = 'PasswordPassword';
            //$iv = random_bytes(openssl_cipher_iv_length($algo));
            $iv = 'dynamic@dynamic@';
            $cipherText = openssl_encrypt(
                    $data,
                    $algo,
                    $key,
                    OPENSSL_RAW_DATA,
                    $iv
                );
        $cipherText = base64_encode($cipherText);
        printData("Ciper Text : $cipherText");

        $cipherText = base64_decode($cipherText);
        $plaintext = openssl_decrypt(
                    $cipherText,
                    $algo,
                    $key,
                    OPENSSL_RAW_DATA,
                    $iv
                );
        printData("Plain Text after decryption : $plaintext");
        }

        function printData($obj)
        {
            print_r($obj);
        }
?>

PHP 输出:

Ciper Text : ef/ENVlBn9QBFlkvoN7P2Q==
Plain Text after decryption : Hello

生成的密码是不同的,即使它们使用相同的密钥和 IV。这怎么可能?

【问题讨论】:

  • 你有什么问题?
  • 如果任何给定的答案解决了您的问题,您可以accept 其中一个。如果没有,请详细说明问题所在。

标签: java php encryption aes


【解决方案1】:

显然,您必须使用相同的 AES 密钥和 IV 才能进行安全会话。并且它们必须在客户端之间正确、安全地进行通信。 根本不重要客户端是用什么语言编写的。您的问题是不了解密钥协议和会话建立的协议。

初始化向量不是一个受保护的值;即,在客户端之间进行通信时,您没有对其进行加密。它必须以明文形式与加密的 AES 密钥(您从某些密钥协议协议中派生)一起打包。

CMS 使用KeyTransRecipientInfo 传递此信息。 TLS 还在其 handshake 之后定义了 IV establishment。我强烈建议遵循 CMS 实现,而不是做一些人为的、几乎可以保证包含安全漏洞的东西。


更新

现在很明显,您很困惑为什么生成的密文不是确定性的。这是因为 Java 实现默认使用 128 位加密并且提供了 128 位密钥,但是 PHP 代码请求 256 位强度加密并且只提供相同的128 位密钥。因此,PHP 必须是 padding 键。


更新 2

根据您的以下 cmets,以下是使用 Java 生成 256 位密钥的示例:

KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256); // The AES key size in number of bits
SecretKey secKey = generator.generateKey();

【讨论】:

  • 由于 Java 实现默认为 128 位加密,所以我们可以将其覆盖为 256 位吗?
  • 当我将 php 中的位更改为 128 时它正在工作...但我不会在 php 结束时进行更改...
  • 是的,您可以创建一个 256 位密钥——我刚刚使用 sn-p 更新了我的答案来执行此操作。此外,您必须添加Unlimited Strength Jurisdition Security Policy,否则您将获得InvalidKeyException
【解决方案2】:

您的密钥只有 128 位(16 字节)长,但您在 PHP 中请求 AES-256。这将导致 256 位(32 字节)的填充 AES 密钥。您必须请求 AES-128 才能使其正常工作。这就是 OpenSSL 扩展在 PHP 中的工作方式。

理想情况下,密钥应该看起来像随机噪声,以防止暴力攻击。您当前的密钥绝非如此。这是非常可预测的。您确实应该生成一些随机密钥并将其以编码形式(如 Base64)添加到您的代码中。然后你可以在使用前对其进行解码。

【讨论】:

  • 是的,我要生成的动态密钥。那么,我们可以请求 Java 进行 256 位加密吗?
猜你喜欢
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
  • 2015-04-15
  • 2020-01-14
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多