PHP中的双向字符串加密-以下哪项更安全?

PHP中的双向字符串加密-以下哪项更安全?,php,security,encryption,pii,Php,Security,Encryption,Pii,我需要通过要在页面上显示的查询字符串传递一个值。必须对该值进行加密,因为它包含一些供查看页面的用户使用的PII。为了让用户可读,它需要在显示时能够被解密 我正在使用PHP,目前为止的研究已经让我找到了openssl\u encrypt和openssl\u decrypt以及以下两个代码资源: 我非常喜欢#1,因为iv实际上是附加到返回的加密字符串上的。这允许我们NOT必须将iv存储为常量,并且能够在每次调用函数时生成一个新的。对我来说,这似乎比每次都使用相同的键和iv更安全真的是这样吗?如果

我需要通过要在页面上显示的查询字符串传递一个值。必须对该值进行加密,因为它包含一些供查看页面的用户使用的PII。为了让用户可读,它需要在显示时能够被解密

我正在使用PHP,目前为止的研究已经让我找到了
openssl\u encrypt
openssl\u decrypt
以及以下两个代码资源:

  • 我非常喜欢#1,因为
    iv
    实际上是附加到返回的加密字符串上的。这允许我们NOT必须将
    iv
    存储为常量,并且能够在每次调用函数时生成一个新的。对我来说,这似乎比每次都使用相同的
    iv
    更安全真的是这样吗?如果是这样,除了痛苦的显而易见之外,还有什么原因我应该知道吗?。我不喜欢的是,我认为将
    iv
    与一个字符/字符串(在本例中为
    )连接起来会出现问题,该字符/字符串可以在其他潜在的密码文本或
    iv
    中自然出现。使用这种方法,在尝试加密7000多个电子邮件地址时,其中略多于一半的地址最终会使用这些奇怪的字符,
    ���6CT∑
    等),从而破坏解码字符串

    #2是伟大的,因为它工作!!我还没有找到一根可以断开它的绳子。。。尤其是在我的邮件列表中。但如上所述,这需要。
    iv
    始终是相同的值,并存储在某个变量中。这看起来像一个小小的维护问题,但更像是一个安全问题

    因此,我进行了更多的阅读/思考,并提出了以下代码:

    <?php
    
    // generate key with base64_encode(openssl_random_pseudo_bytes(32);
    // and save it in a constant.
    define('ENCRYPT_KEY_1', 'CuH8WPfXzMj0xRWybHjssWJ+IhTDqL5w0OD9+zXFloA=');
    
    function encrypt_decrypt($action, $string) {
        $output = false;
    
        $encrypt_method = "AES-256-CBC";
        $key = ENCRYPT_KEY_1;
        
        $ivLen = openssl_cipher_iv_length($encrypt_method);
        
    
        /**
         * the key was generated with 32 pseudo-bytes and then base64Encod()-ed.
         * Not sure of the reason for encoding - just decoding in case it's necessary.
         * 
         * Thoughts?
         * **/
        $key = base64_decode($key);
    
        if ( $action == 'encrypt' ) {
            /**
            * "AES-256-CBC" expects a 16-byte string - create an 8-byte string to be 
            * converted to a 16-byte hex before being used as the initialization vector
            * TLDR" in order to end up with 16-bytes to feed to openssl_random_pseudo_bytes,
            * divide initial length in half as the hex value will double it
            * */
            $iv = openssl_random_pseudo_bytes($ivLen/2);
            $iv = bin2hex($iv);
            $tmp_data_str_in = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
            $output = base64_encode($tmp_data_str_in . $iv);
        } else if( $action == 'decrypt' ) {
            $data_str_in = base64_decode($string);
            
            // This time, rather than generating one, we get the iv (converted to hex)
            // by grabbing the last 16 characters of the concatenation of the 2 that happened
            // during encryption.
            $iv = substr($data_str_in, -$ivLen);
            
            // And now we just grab everything BUT the last 16 characters. We'll
            // run openssl_decrypt and return a copy of the original input
            $encrypted_txt_str = substr($data_str_in, 0, strlen($data_str_in)-$ivLen); 
    
            // Notice we are returning the encrypted value of a string consisting of
            // encoded versions of the input text and a random `IV` - we'll grab the `IV`
            // from it later in order to decrypt later. 
            $output = openssl_decrypt($encrypted_txt_str, $encrypt_method, $key, 0, $iv);
        }
    
        return $output;
    }
    
    $plain_txt = "memyselfandi@i.me";
    echo "Plain Text = " .$plain_txt. "\n";  
    
    $encrypted_txt = encrypt_decrypt('encrypt', $plain_txt);
    echo "Encrypted Text = " .$encrypted_txt. "\n";
    
    $decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt);
    echo "Decrypted Text = " .$decrypted_txt. "\n";
    
    if ( $plain_txt === $decrypted_txt ) echo "SUCCESS";
    else echo "FAILED";
    
    echo "\n";
    ?>
    

    很抱歉懒得将我的示例应用到您的代码中,但它应该不会太复杂,因为下面的代码是
    AES GCM 256随机IV字符串加密。IV和标记在密文之前,然后进行Base64编码

    请注意,该代码没有任何错误处理,仅用于教育目的!不要使用静态密钥进行加密。

    输出:

    Sample AES GCM 256 string encryption
    Please note that this code does not have any error handling and is for educational purpose only
    Do NOT use static keys for encryption !
    
    plaintext: The quick brown fox jumps over the lazy dog
    encrypt: jemvFuwhIaUYx49d1nap6uKz8wMIorvQuRD/PGt+SYhFt8iaK1fiqAf8CjWtVNYqFZATStgq2XQuUAhbnhMtpzHDPN7oUFo=
    decrypt: The quick brown fox jumps over the lazy dog
    
    代码:

    
    
    使用静态IV会使AES CBC模式加密不安全,因此您的方法很好。请考虑一个潜在的攻击者可以做一个简单的“篡改”攻击(在这里,你可以通过正确的方式对IV进行简单的修改来改变密钥而不知道密钥。这意味着你应该考虑使用一个经过认证的AES模式,比如GCM来获得更高的安全级别。(您只需添加另一个变量(称为“tag”)就像你在IV上做的那样,我只是看着所有这些在我的头上飞过。我将阅读验证AES模式,但想知道你是否有任何资源,可能包含一些类似于我的示例?这个问题似乎离题了,因为这是一个代码审查请求。这可能是更适合于。在发布之前,一定要阅读他们的文章,以确保你的问题符合他们的指导原则。@johncode-我尊重地不同意。我问的是如何为特定功能编写代码,并给出了一些我迄今为止尝试过的事情的示例(这样我就不只是来这里找其他人为我工作)。如果您查看下面michael Fehr的回答,您会发现我的代码缺少对我正在查询的函数的整个参数的使用。听起来我不完全知道如何使用该函数,并且可能需要一些帮助,因为它与我的用例有关。这太好了,谢谢!您是否介意解释此方法的安全性和/或w什么使我的方法不安全或不安全?请您自己考虑搜索“已验证的加密模式”。简言之:GCM模式生成一个安全标签(“HMAC”),防止密文更改,称为“已验证”。AES GCM模式比AES CBC模式更安全。
    <?php
    function encrypt($encryptionKey, $data) {
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-gcm'));
        $encrypted = openssl_encrypt($data, 'aes-256-gcm', $encryptionKey, OPENSSL_RAW_DATA, $iv, $tag);
        return base64_encode($iv . $tag . $encrypted);
    }
    
    function decrypt($encryptionKey, $data) {
        $c = base64_decode($data);
        $ivlen = openssl_cipher_iv_length($cipher="AES-256-GCM");
        $iv = substr($c, 0, $ivlen);
        $tag = substr($c, $ivlen, $taglen=16);
        $ciphertext_raw = substr($c, $ivlen+$taglen);
        return openssl_decrypt($ciphertext_raw, 'aes-256-gcm', $encryptionKey, OPENSSL_RAW_DATA, $iv, $tag);
    }
    
    echo 'Sample AES GCM 256 string encryption' . PHP_EOL;
    echo 'Please note that this code does not have any error handling and is for educational purpose only' . PHP_EOL;
    echo 'Do NOT use static keys for encryption !'. PHP_EOL . PHP_EOL;
    
    $plaintext = 'The quick brown fox jumps over the lazy dog';
    $key = '12345678901234567890123456789012'; // 32 bytes = 256 bit key
    echo 'plaintext: ' . $plaintext .PHP_EOL;
    $encrypt = encrypt($key, $plaintext);
    echo 'encrypt: ' . $encrypt . PHP_EOL;
    $decrypt = decrypt($key, $encrypt);
    echo 'decrypt: ' . $decrypt . PHP_EOL;
    ?>