在 PHP(PHP 5 >= 5.3.0, PHP 7, PHP 8)中,openssl_encrypt 的参数大抵如下:
openssl_encrypt(
string $data,
string $cipher_algo,
string $passphrase,
int $options = 0,
string $iv = "",
string &$tag = null,
string $aad = "",
int $tag_length = 16
): string|false
其中 $data
待加密的数据字符串,这很好了解,这里不做过多阐释。
$cipher_algo
为加密算法,如AES-128-ECB
, 两头这个数字示意密钥长度为 128 位。所有加密算法可通过 openssl_get_cipher_methods 取得。-
$passphrase
为密钥。既然下面的算法都规定了密钥长度,那这个密钥的字符串长度就曾经确定下来了。但 PHP 随性的一点是如果密钥小于或超过算法指定的长度,也都能失常返回加密后果,而不像 Java 等语言间接抛出密钥长度不正确的异样。依据手册解释:若 passphrase 比预期长度短,将静默用 NUL 填充;若比预期长度更长,将静默截断。
那么 NUL 在 PHP 中体现又是什么?查了 PHP 源代码下的 openssl 实现,找到如下代码:
if (key_len > password_len) {if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher algorithm"); return FAILURE; } key = emalloc(key_len); memset(key, 0, key_len); memcpy(key, *ppassword, password_len); *ppassword = (char *) key; *ppassword_len = key_len; *free_password = 1; }
memset(key, 0, key_len); 应该对应的就是 ASCII 中的零,也就是 PHP 里的 chr(0)。所以如果一个密钥长度不够,PHP 会主动在密钥前面用 chr(0)有余。例如:
AES-128-ECB
算法,密钥长度应为 128 位,也就是字符串长度为 16。这时如果密钥为 ”1234567890abcde” 和 ”1234567890abcde”.chr(0)的意义是一样的,失去的加密后果也是一样的。至于超出长度主动截断,这应该很好了解了。 $options
是以下标记的按位或:OPENSSL_RAW_DATA、OPENSSL_ZERO_PADDING, 指定对于数据,如何填充的。
其中OPENSSL_RAW_DATA
的默认行为是 PKCS7Padding