PHP AES-256-CBC加密数据不同于JAVA AES/CBC/PKCS 5 PADDING

icomxhvb  于 2022-11-21  发布在  PHP
关注(0)|答案(1)|浏览(249)

我有一个运行良好的java代码

public static String encrypt(String message, String sercretKey)
    {
        String base64EncryptedString = "";
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] digestOfPassword = md.digest(sercretKey.getBytes("utf-8"));
            byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
            byte[] iv = Arrays.copyOf(digestOfPassword, 16);
            SecretKey key = new SecretKeySpec(keyBytes, "AES");
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, ivParameterSpec);
            byte[] plainTextBytes = message.getBytes("utf-8");
            byte[] buf = cipher.doFinal(plainTextBytes);
            byte[] base64Bytes = Base64.getEncoder().encode(buf);
            base64EncryptedString = new String(base64Bytes);
        return base64EncryptedString;
    }

我试着用下面的代码在PHP中重新创建上面的代码

function encryptTest($sSecretKey,$sValue)
        {
            $key = hash('sha256', $sSecretKey,false);
            $key = utf8_encode($key);
            $key = substr($key, 0, 24);
            $iv = substr($key, 0, 16);
            $data = $sValue;
            $outEnc = openssl_encrypt($data, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
            
            return base64_encode($outEnc);
        }

但结果却不一样。我错过了什么。
(Same问题类型在StackOverflow中可用,但指向我的问题)

bzzcjhmw

bzzcjhmw1#

存在以下问题:

  • 在PHP代码中,当前返回的密钥是十六进制编码的,而必须以字节字符串的形式返回。为此,必须将hash()中的第三个参数从false切换为true
  • 在Java代码中使用了192位密钥,即AES-192。因此,在PHP代码中必须应用"AES-192-CBC"(而不是"AES-256-CBC")。
  • PHP代码中的utf8_encode()调用将被删除,因为这会损坏键。

通过这些改变,两个代码提供相同的密文。
安全性:
使用SHA 256作为密钥派生是不安全的。请改用Argon 2或PBKDF 2之类的专用算法。此外,使用密钥(或密钥的一部分)作为IV也是不安全的,因为它会导致密钥/IV对的重用。相反,应针对每次加密应用随机生成的IV。

相关问题