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。
我最近被要求创建一种加密/解密 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。