php - openssl_encrypt() 随机失败 - 传递的 IV 仅为 ${x} 字节长,密码预计 IV 恰好为 16 字节

标签 php encryption aes encryption-symmetric php-openssl

这是我用来加密/解密数据的代码:

// Set the method
$method = 'AES-128-CBC';

// Set the encryption key
$encryption_key = 'myencryptionkey';

// Generet a random initialisation vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));

// Define the date to be encrypted
$data = "Encrypt me, please!";

var_dump("Before encryption: $data");

// Encrypt the data
$encrypted = openssl_encrypt($data, $method, $encryption_key, 0, $iv);

var_dump("Encrypted: ${encrypted}");

// Append the vector at the end of the encrypted string
$encrypted = $encrypted . ':' . $iv;

// Explode the string using the `:` separator.
$parts = explode(':', $encrypted);

// Decrypt the data
$decrypted = openssl_decrypt($parts[0], $method, $encryption_key, 0, $parts[1]);

var_dump("Decrypted: ${decrypted}");

它通常工作正常,但有时(十分之一或更少)它会失败。当它失败时,文本只是部分加密:

这是发生时的错误信息:

Warning: openssl_decrypt(): IV passed is only 10 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0

当它发生时,加密的文本看起来像:

Encrypt me���L�se!

我认为这可能是由 PHP 中的错误引起的,但我在不同的主机上进行了测试:PHP 7.0.6 和 PHP 5.6。我还尝试了多个在线 PHP 解析器,例如 phpfidle.org 或 3v4l.org。

似乎 openssl_random_pseudo_bytes 并不总是返回适当长度的字符串,但我不知道为什么。

示例如下:https://3v4l.org/RZV8d

继续刷新页面,有时会报错。

最佳答案

当您生成随机 IV 时,您会得到 raw binary .二进制字符串包含 :\0 字符的可能性非零,您将使用这些字符将 IV 与密文分开。这样做会使 explode() 给你一个更短的字符串。演示:https://3v4l.org/3ObfJ

简单的解决方案是在此过程中添加 base64 编码/解码。


也就是说,please don't roll your own crypto .特别是,unauthenticated encryption is dangerousthere are already secure libraries that solve this problem .

与其自己编写,不如考虑使用 defuse/php-encryption .这是安全的选择。

关于php - openssl_encrypt() 随机失败 - 传递的 IV 仅为 ${x} 字节长,密码预计 IV 恰好为 16 字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37439981/

相关文章:

用于加密/解密的 Java SimpleCrypto 类在 Coldfusion 9 和 Java (Android) 中产生不同的结果

javascript - AJAX/jquery 不适用于返回的 PHP 站点

PHP Mysql 表获取只给出第一行

php - 如何编辑此 mySQL 查询以找到访问特定页面超过 x 次的人?

dll - c#dll加密

javascript - crypto-js 和 pycrypto 中的 AES 问题

Java 错误 : Input length must be multiple of 16 when decrypting with padded cipher

javascript - chargeitpro 签名网址无效

javascript - 通过 Laravel 5.7 PHP 加密对象并通过 VueJS Javascript 解密

java - URLClassLoader - 使用加密的 Jar