在PHP(PHP5>=5.3.0,PHP7,PHP8)中,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实现,发现如下代码:php_error_docref(ARNING,E_KeyW"不能为密码算法设置长度");返回失败;}key=emalloc(key_len);内存集(键,0,key_len);memcpy(key,*ppassword,password_len);*ppassword=(char*)密钥;*ppassword_len=key_len;*free_password=1;}memset(key,0,key_len);应该对应ASCII中的0,即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的含义应该是没有base64_encode的原始数据。如果没有此掩码,将返回一个base64字符串。默认填充是PKCS#7。经查询,OPENSSL_ZERO_PADDING选项在PHP新版本(7.4.4)中已经废弃,效果与OPENSSL_NO_PADDING相同。总结:0:默认值,PKCS#7padding,返回数据是base64编码;1:OPENSSL_RAW_DATA,PKCS#7padding,但返回结果不是base64编码;2:OPENSSL_ZERO_PADDING,openssl不推荐使用chr(0)填充方式,需要开发者填写,返回结果为base64编码;3:OPENSSL_NO_PADDING,需要开发者填写,返回结果不是base64编码;$ivInitializationVector(初始化向量),不同的IV加密的字符串不同,加密和解密需要相同的IV,因为IV看起来和密钥一样,但是IV还有一个额外的用途,对于每个块,key是一样的,只是第一个block的IV是用户提供的,其他blockIV是自动生成的。IV的长度为16个字节。如果超过或不足,可能的库将被填充或截断。ECB方法不需要iv,所以以ECB例子为例,快速上手。$tag使用AEAD密码模式(GCM或CCM)时要传递的身份验证标记。$aad附加验证数据。$tag_length验证标签的长度。在GCM模式下,它的范围是4到16。
