PHP 加密方式比较

PHP Encryption Method Comparison

我最近被要求创建一种加密/解密 URL 字符串的方法。我赶紧制作了一个1号线,拍了出来。

然后我从另一位开发人员那里获得了代码并询问了我的意见。我查看了他的,发现了一个更复杂的函数。

我的问题:

What are the specific differences here?

Are there shortfalls found in the short solution?

我们正在加密 json 编码数组并通过查询字符串 URL 传递它。

长解:

public function Encrypt($message, $key = 'defaultkey') {

    //Create an instance of the mcrypt resource
    $td = mcrypt_module_open('tripledes', '', 'ecb', '');

    //Create a random intialization vector and initialize
    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);

    // Create a Timestamp and add it.
    $T = new \DateTime('NOW');
    $message = $T->format("YmdHis") . $message;

    // PKCS7 Padding
    //get the block size of the cipher
    $b = mcrypt_get_block_size('tripledes', 'ecb');

    //What is the purpose?
    $dataPad = $b-(strlen($message)%$b);
    $message .= str_repeat(chr($dataPad), $dataPad);

    //convert to hexidec string
    $encrypted_data = bin2hex(mcrypt_generic($td, $message));
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $encrypted_data;
}

简解:

public function Encrypt($message, $key = 'defaultkey') {
    
    $T = new \DateTime('NOW');
    return bin2hex(mcrypt_encrypt(MCRYPT_3DES, $key, $T->format("YmdHis").$message, 'ecb'));
}

唯一真正的区别是填充。三重 DES 是一种对称块密码,仅在单个完整块(8 字节)上运行。像 ECB 这样的操作模式使它能够加密许多完整的块。当您的数据不是块大小的倍数时,必须对其进行填充才能加密。

MCrypt 默认使用零填充。它将用 0x00 字节填充明文,直到达到块大小的倍数。在解密过程中必须删除那些额外的填充字节(通常用 rtrim() 完成)。这意味着如果明文以 0x00 字节结尾,那些也将被删除,这可能会破坏您的明文。

PKCS#5/PKCS#7 填充另一方面用表示填充字节数的字节填充。如果明文已经是块大小的倍数,它将添加一个完整的填充块。这样做可以让它在解密过程中只删除填充而不是额外的明文字节。

使用 mcrypt_generic_init() 还是 mcrypt_encrypt() 并没有什么区别。


切勿使用 ECB 模式。 它在语义上不安全。这意味着相同的明文块将始终产生相同的密文块。由于您正在加密 URL,因此在观察到许多密文后,前几个块对于相似的 URL 将保持不变。攻击者可能会从中获取更多信息。

至少使用带有随机 IV 的 CBC 模式。 IV 不需要隐藏,因此可以很容易地添加到密文前面并在解密过程中切掉。

最好对密文进行身份验证以检测操纵。您可以使用具有不同密钥的消息身份验证代码,例如 HMAC-SHA256。更好的方法是简单地使用经过身份验证的模式,例如 GCM 或 EAX。