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