使用 php openssl_encrypt 的正确方法

2022-08-30 18:28:10

我正在一个项目上使用密码学,我需要一些关于如何工作的帮助,我只是想知道最基本和正确的方法来做到这一点。以下是我到目前为止所得到的:openssl_encryptopenssl_decrypt

// To encrypt a string

$dataToEncrypt = 'Hello World';

$cypherMethod = 'AES-256-CBC';
$key = random_bytes(32);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cypherMethod));

$encryptedData = openssl_encrypt($dataToEncrypt, $cypherMethod, $key, $options=0, $iv);

然后,我存储 、 和 以供解密时使用。(让我们不要详细说明我如何存储值,谢谢!$cypherMethod$key$iv$encryptedData

// To decrypt an encrypted string

$decryptedData = openssl_decrypt($encryptedData, $cypherMethod, $key, $options=0, $iv);

首先,上面的示例代码是否是如何使用的正确示例?php openssl_encrypt

其次,我的方法生成正确和安全吗?因为我一直在阅读,所以密钥应该是加密安全的。$key$iv

最后,不是 需要值吗?如果是,那么为什么它仅作为长度返回?难道不应该吗?32-byteAES-256-CBCopenssl_cipher_iv_length()int(16)int(32)


答案 1

首先,上面的示例代码是否是如何使用php openssl_encrypt的正确示例?

您对该函数的使用看起来是正确的,但是您可能需要考虑CBC以外的操作模式。CBC很难正确,因为仅在此模式下加密数据就会对它进行已知的攻击,例如臭名昭着的CBC位翻转攻击,它允许攻击者通过修改密文对明文进行有意义的更改。如果可能的话,我会使用像GCM这样的经过身份验证的加密模式(看起来PHP 7.1 +支持它(示例#1))。

如果您使用CBC模式,请查看文档中的示例#2。请注意,加密后,MAC(消息身份验证代码)将通过密文计算并存储。此MAC应在解密密文之前重新计算,如果它与存储的MAC不匹配,则密文已被修改并且无效。

其次,我生成$key的方法是否$iv正确和安全?因为我一直在阅读,所以密钥应该是加密安全的。

需要使用加密安全的随机数生成器生成密钥。幸运的是,大多数操作系统都通过 提供了开箱即用的功能。这个答案很好地解释了如何在PHP中阅读。 也应该是加密安全的,但有时情况并非如此/dev/urandom/dev/urandomopenssl_random_pseudo_bytes

初始化向量 (IV) 需要是随机的,永远不要使用相同的密钥重用。

最后,AES-256-CBC 不是需要 32 字节值吗?如果是,那么为什么openssl_cipher_iv_length() 只返回 int(16) 作为长度?难道不应该是int(32)吗?

AES 是一种块密码,适用于 128 位(16 字节)块,无论密钥大小如何。


答案 2

以下是使用openssl_encrypt和openssl_decrypt的最基本方法。确保创建 32 字节secret_key和 16 字节secret_iv

function encrypt_decrypt($action, $string) 
    {
        $output = false;
        $encrypt_method = "AES-256-CBC";
        $secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
        $secret_iv = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
        // hash
        $key = hash('sha256', $secret_key);    
        // iv - encrypt method AES-256-CBC expects 16 bytes 
        $iv = substr(hash('sha256', $secret_iv), 0, 16);
        if ( $action == 'encrypt' ) {
            $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
            $output = base64_encode($output);
        } else if( $action == 'decrypt' ) {
            $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
        }
        return $output;
    }

推荐